Skip to content

Don't crash on undefined function-like macros#739

Merged
tannergooding merged 1 commit into
dotnet:mainfrom
tannergooding:tannergooding-fix-undefined-macro-crash
Jul 13, 2026
Merged

Don't crash on undefined function-like macros#739
tannergooding merged 1 commit into
dotnet:mainfrom
tannergooding:tannergooding-fix-undefined-macro-crash

Conversation

@tannergooding

Copy link
Copy Markdown
Member

Using an undefined function-like macro in another macro's body crashed the generator with InvalidCastException: Unable to cast object of type 'ClangSharp.Stmt' to type 'ClangSharp.Expr':

#define ADDRESS_IN_USE TESTRESULT_FROM_WIN32(10048)   // TESTRESULT_FROM_WIN32 is not defined

The generator synthesizes a ClangSharpMacro_ VarDecl and lazily resolves its initializer via VarDecl.InitFactory, which hard-cast the cursor through GetOrCreate<Expr>. When the initializer resolves to a plain Stmt rather than an Expr, that cast threw.

InitFactory now resolves via GetOrCreate<Stmt>(...) as Expr, so a non-Expr initializer yields null instead of throwing. This is behavior-preserving for real initializers, which are always Expr. The macro handling in VisitVarDecl gracefully skips such a macro and emits a warning diagnostic instead of crashing, and the existing RecoveryExpr skip now emits the same warning rather than silently dropping the macro (modern Clang represents these unresolved invocations as a RecoveryExpr).


Added UndefinedFunctionLikeMacroTest to the VarDeclaration golden suite (Base + all 16 configuration variants), asserting no crash, empty output, and the expected warning diagnostic.

Note: on the pinned libClang 21.1.8 the exact Stmt -> Expr cast is no longer produced (Clang yields a RecoveryExpr/CallExpr), so this hardens the reported cast site defensively and locks in the graceful warn-and-skip behavior via the new regression test.

Fixes #222

An undefined function-like macro used in another macro's body (e.g.
`#define ADDRESS_IN_USE TESTRESULT_FROM_WIN32(10048)` where
`TESTRESULT_FROM_WIN32` is not defined) synthesized a `ClangSharpMacro_`
`VarDecl` whose initializer resolved to a plain `Stmt` rather than an
`Expr`. `VarDecl.InitFactory` hard-cast the result via `GetOrCreate<Expr>`,
throwing `InvalidCastException`.

Resolve the initializer via `GetOrCreate<Stmt>(...) as Expr` so a non-`Expr`
initializer yields `null` instead of throwing, and have the macro handling
in `VisitVarDecl` gracefully skip such a macro while emitting a warning
diagnostic. Also warn, rather than silently skip, when the initializer
resolves to a `RecoveryExpr`, which is how modern Clang represents these
unresolved invocations.

Fixes dotnet#222

Co-authored-by: Copilot App <223556219+Copilot@users.noreply.github.com>
@tannergooding
tannergooding merged commit 7e603dd into dotnet:main Jul 13, 2026
14 checks passed
@tannergooding
tannergooding deleted the tannergooding-fix-undefined-macro-crash branch July 13, 2026 14:55
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.

A non defined function macro being used results in a crash

1 participant