Skip to content

Fix translation of signed array indices #4079

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Closed
wants to merge 0 commits into from
Closed

Fix translation of signed array indices #4079

wants to merge 0 commits into from

Conversation

travisstaloch
Copy link
Contributor

@daurnimator daurnimator added the translate-c C to Zig source translation feature (@cImport) label Jan 5, 2020
@daurnimator
Copy link
Contributor

You only need the cast if the index is signed or has more bits than usize

@travisstaloch
Copy link
Contributor Author

travisstaloch commented Jan 5, 2020

I thought there might need to be some checks like this.

Not sure how to do this right now. I'm guessing the result of ZigClangArraySubscriptExpr_getIdx(stmt) would contain the type info that would need checked. Right?

Here is the line in question:
79edfb9#diff-15590d874e44509c8710e7f4cddb840cR2413

@andrewrk
Copy link
Member

andrewrk commented Jan 5, 2020

Thanks!

Now that #4053 is merged, would you mind adding a "Run Translated C" test case?

file: test/run_translated_c.zig
cmd: ./zig build test-run-translated-c

This kind of test is better at catching whether translated-c code will actually turn into viable zig code.

@travisstaloch
Copy link
Contributor Author

@andrewrk Should the tests be moved to test/run_translated_c.zig and removed from test/translate_c.zig or copied and changed?

@andrewrk
Copy link
Member

andrewrk commented Jan 5, 2020

For your pull request, I think it would be nice to copy&change, because it's also nice to see the input/output as a test case.

@travisstaloch
Copy link
Contributor Author

I've managed to get this working with the checks for signedness and width.
However, my solution maybe hacky and wouldn't support casting long long indexes. I found qualTypeIntBitWidth but it doesn't include .LongLong and .ULongLong. Should these and other c builtin integer types be added here?

    switch (ZigClangType_getTypeClass(ty)) {
        .Builtin => {
            const builtin_ty = @ptrCast(*const ZigClangBuiltinType, ty);

            switch (ZigClangBuiltinType_getKind(builtin_ty)) {
                .Char_U,
                .UChar,
                .Char_S,
                .SChar,
                => return 8,
                .UInt128,
                .Int128,
// Should we add more types here such as:
//                .ULongLong,
//                .LongLong,
                => return 128,
                else => return 0,
            }

            unreachable;
        },

https://github.com/ziglang/zig/blob/master/src-self-hosted/translate_c.zig#L3043

@travisstaloch
Copy link
Contributor Author

Would I be able to somehow get access to the QualType's TypeInfo? There seems to be public .Width property we could use: https://clang.llvm.org/doxygen/structclang_1_1TypeInfo.html. That is if we had access to QualType::getTypeInfo().

Or am I looking at the wrong docs here?

@travisstaloch
Copy link
Contributor Author

"You only need the cast if the index is signed or has more bits than usize"
I have no problems checking for signedness.
@daurnimator @LemonBoy do you guys know how to properly check the width of a type from translate_c.zig? qualTypeIntBitWidth() could work but is likely intentionally incomplete as I noted two comments above.

@andrewrk
Copy link
Member

andrewrk commented Jan 7, 2020

Consider that the width of an integer type in bytes depends on the target, and when translating from C to Zig, generally you are translating target-agnostic code to target-agnostic code. So if you have to find out how many bytes an integer is exactly, it's a bit of a code smell.

There might be a related function that I already made for a different purpose, which selects a type based on another type, but overrides the signedness. Would that help?

@travisstaloch
Copy link
Contributor Author

I think that would help. I'm working with a ZigClangQualType and trying to deduce the width from that.

@andrewrk
Copy link
Member

andrewrk commented Jan 7, 2020

/// Produces a Zig AST node by translating a Clang QualType, respecting the width, but modifying the signed-ness.
/// Asserts the type is an integer.
fn transQualTypeIntWidthOf(c: *Context, ty: ZigClangQualType, is_signed: bool) TypeError!*ast.Node {
return transTypeIntWidthOf(c, qualTypeCanon(ty), is_signed);
}
/// Produces a Zig AST node by translating a Clang Type, respecting the width, but modifying the signed-ness.
/// Asserts the type is an integer.
fn transTypeIntWidthOf(c: *Context, ty: *const ZigClangType, is_signed: bool) TypeError!*ast.Node {

@travisstaloch
Copy link
Contributor Author

Thanks for pointing out transQualTypeIntWidthOf.

So rather than checking the width, I'm now planning to create a narrow128BitIntType function which just maps .LongLong, .ULongLong, .Int128, .UInt128 => c_uint and leaves other types unchanged.

@andrewrk
Copy link
Member

andrewrk commented Jan 7, 2020

Mind rebasing while you're at it? This will make sure your new code doesn't regress the newly added test cases.

@travisstaloch travisstaloch requested a review from andrewrk January 8, 2020 03:25
@LemonBoy
Copy link
Contributor

LemonBoy commented Jan 8, 2020

Thousand dollar question, what about array[-1] ? That's legal C and definitely not the same as array[@bitCast(usize, @intCast(isize, -1))].

@travisstaloch
Copy link
Contributor Author

travisstaloch commented Jan 8, 2020

I used to c_uint in this PR. Should these be usize instead?

Also I used @intCast rather than @bitCast.

@andrewrk
Copy link
Member

andrewrk commented Jan 8, 2020

array[-1]

(@as([*]E, &array) - 1).*

@LemonBoy
Copy link
Contributor

LemonBoy commented Jan 8, 2020

(@as([*]E, &array) - 1).*

That's my point, should this PR generate that if the index is not unsigned?

Should these be usize instead?

When you're dealing with pointers using a usize is recommended.

Also, if you want to keep the PR tidy don't merge master into it but use git rebase instead.

@travisstaloch
Copy link
Contributor Author

Apologies for the messy commits. I did rebase but ended up with conflicts and must have taken a wrong turn. Ended up needing git rebase --skip after resolving... 👎

using a usize is recommended

I'll update to usize then.

@travisstaloch
Copy link
Contributor Author

I will clean up that nasty merge commit. Maybe it will be easier to leave as is for now and make a fresh PR if accepted.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
translate-c C to Zig source translation feature (@cImport)
Projects
None yet
Development

Successfully merging this pull request may close these issues.

translate-c doesn't cast signed array index
4 participants