Skip to content

Fix ICE/AV on string mixin of version=/debug= statements - #23465

Open
AMDphreak wants to merge 4 commits into
dlang:masterfrom
dlang-supplemental:fix/mixin-null-statement-crash
Open

AMDphreak wants to merge 4 commits into
dlang:masterfrom
dlang-supplemental:fix/mixin-null-statement-crash

Conversation

@AMDphreak

Copy link
Copy Markdown

Summary

  • Fix ACCESS_VIOLATION / ICE when a string mixin contains statement-level version = / debug = (and similar parse paths that returned a null Statement).
  • parseStatement now returns ErrorStatement instead of null; mixin semantic null-guards the supplemental location.
  • Add fail_compilation/mixin_version_debug_assign.d.

Fixes #23464

Test plan

  • Reproduced crash on DMD v2.112.0 with mixin("version = foo;") / mixin("debug = 1;") (exit -1073741819 / 0xC0000005)
  • Built local dmd; same cases now exit 1 with normal diagnostics
  • CI fail_compilation test mixin_version_debug_assign.d

Comment thread compiler/src/dmd/parse.d Outdated
parseStatement returned null for those paths; mixin semantic then
dereferenced s.loc in errorSupplemental. Return ErrorStatement instead
and guard the supplemental location.

Fixes dlang#23464

Co-authored-by: Cursor <cursoragent@cursor.com>
@AMDphreak
AMDphreak force-pushed the fix/mixin-null-statement-crash branch from 1d9a147 to 5adb32a Compare October 8, 2026 00:20
thewilsonator and others added 2 commits October 8, 2026 11:13
parse.d now uses AST.ErrorStatement.get(), which only existed in the
full AST, so Parser!ASTBase (e.g. compiler/test/dub_package/avg.d and
impvisitor.d) no longer compiled. Add the same get() to ASTBase. The
singleton is created lazily, as ASTBase.ErrorExp.get() does, because
the constructor's `global.errors || global.gaggedErrors` assert cannot
run at compile time.

Only the `version =` / `debug =` paths need to return an ErrorStatement,
and both always report an error first. Restore the original `s = null`
for a failed `if` statement, which the fix does not need, and drop the
extra comments.

Extend the test to `debug = ident;` and to `mixin("else")`, whose
supplemental message previously had no location.
Comment thread compiler/src/dmd/statementsem.d Outdated
auto eSink = global.errorSink;
eSink.errorSupplemental(s.loc, "while parsing string mixin statement");
// s may be null or an ErrorStatement, which has no location
const loc = s && s.loc.isValid() ? s.loc : cs.loc;

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why try to use s.loc here?

Comment thread compiler/src/dmd/statementsem.d Outdated
{
auto eSink = global.errorSink;
eSink.errorSupplemental(s.loc, "while parsing string mixin statement");
// s may be null or an ErrorStatement, which has no location

@dkorpel dkorpel Oct 8, 2026 •

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

(Repositing as GitHub has been bugging out on my last comment) Should clarify when s is null, and why it's not consistently null or consistently ErrorStatement

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks, good catches. parseStatement returns null on some error paths (version =, debug =, a failed if, and ident::, which also crashed) and an ErrorStatement with no location on others, so trying to make the parser consistent kept missing cases. I went the other way: the parser changes are reverted, and the mixin code no longer looks at s. It always puts "while parsing string mixin statement" on the mixin's own location, so there's no s.loc left and nothing that needs a comment. Dropping ErrorStatement.get() from the parser also fixes the GDC 9 build, which couldn't see it through ASTCodegen. The new test covers all of those cases, and four existing tests now expect the note on the mixin line.

I used AI for these changes and this comment; if anything smells fishy, ping me and I'll take a closer look.

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AMDphreak Please post human written comments

Copy link
Copy Markdown
Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

@AMDphreak Please post human written comments

What are you talking about? Code comments or PR comments?

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

In general both, but in this case it was regarding the response to my review comments. The AI has a lot to say about what it does but now why it does it, so I'm asking for a human explanation showing intent and understanding about the choice between s.loc and cs.loc, and ErrorStatement and null.

parseStatement returns null on some error paths (`version =` and
`debug =` inside a function, a failed `if`, `ident::`) and an
ErrorStatement without a location on others. Rather than trying to make
the parser consistent, report "while parsing string mixin statement" at
the mixin expression's location (cs.loc) and never look at `s`.

This also fixes `mixin("a::b;")`, which still crashed, and lets us drop
the parser/astbase ErrorStatement.get() changes from the previous
commit. Those broke the GDC 9 host build ("no property 'ErrorStatement'
for type 'ASTCodegen'"), because older frontends can't resolve a static
member through ASTCodegen's public imports without an explicit alias.

The supplemental in fail246, fail265, fail4375k and ice8795 now points
at the mixin's line in the source file. The new test gains the `a::b`
and `else` cases.
@AMDphreak AMDphreak changed the title Fix ICE/AV on string mixin of version=/debug= statements Fix ICE/AV on string mixin of version=/debug= statements Oct 14, 2026
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.

ICE/AV: string mixin of version = / debug = statement null-derefs in errorSupplemental

3 participants