Skip to content

Cast C enumerators used as shift counts to int - #842

Open
unsafePtr wants to merge 1 commit into
dotnet:mainfrom
unsafePtr:fix/c-enum-shift-count
Open

unsafePtr wants to merge 1 commit into
dotnet:mainfrom
unsafePtr:fix/c-enum-shift-count

Conversation

@unsafePtr

Copy link
Copy Markdown

In C an enumerator has type int, so a shift by one takes the "already the correct type" case in VisitBinaryOperator and is written bare. The generator emits the enumerator as a member of its C# enum, though, and C# cannot shift by an enum:

enum Bits { BIT_A };
#define FLAG_A (1U << BIT_A)
// error CS0019: Operator '<<' cannot be applied to operands of type 'uint' and 'Bits'
public const uint FLAG_A = (1U << BIT_A);

In C++ the enumerator has the enum's type and already falls through to the (int)(...) fallback, so only C is affected. This adds a case ahead of the int case that casts when the shift count, as written (ignoring parentheses and implicit casts), is a reference to an enumerator. The new EnumConstantBitshiftTest sits next to UnsignedIntBitshiftTest from #611 and covers a constant and a macro, each with and without parentheses; it fails without the change (FlagA = 1U << BIT_A;).

Found while generating bindings for Linux's io_uring.h, whose IOSQE_* flags are defined as (1U << IOSQE_*_BIT).

Testing: the full ClangSharp.PInvokeGenerator.UnitTests suite passes on Windows. With RUN_ALL_VARIANTS=1 the only failures are 16 in WideStringLiteralConstTest and WideStringLiteralStaticConstTest, which fail the same way on main when the Unix variants run on a Windows host.

🤖 Generated with Claude Code

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

1 participant