Fix issue 22671 - Allow GC allocations in if (__ctfe) blocks in @nogc functions#22680
Fix issue 22671 - Allow GC allocations in if (__ctfe) blocks in @nogc functions#22680divyansharma001 wants to merge 2 commits intodlang:masterfrom
if (__ctfe) blocks in @nogc functions#22680Conversation
|
Thanks for your pull request and interest in making D better, @divyansharma001! We are looking forward to reviewing it, and you should be hearing from a maintainer soon.
Please see CONTRIBUTING.md for more information. If you have addressed all reviews or aren't sure how to proceed, don't hesitate to ping us with a simple comment. Bugzilla referencesYour PR doesn't reference any Bugzilla issue. If your PR contains non-trivial changes, please reference a Bugzilla issue or create a manual changelog.
|
There was a problem hiding this comment.
Pull request overview
This PR fixes a false-positive @nogc violation when a @nogc function performs GC allocations inside if (__ctfe) blocks, by ensuring the GC check is aware the return came from a CTFE-only branch.
Changes:
- Add
ReturnStatement.inCtfeBlockto record whether areturnwas semantically analyzed underctfeBlock. - Populate
inCtfeBlockduring statement semantic analysis and use it insemantic3.dwhen running the return-statement post-pass GC check. - Add a compilable regression test and a pending changelog entry for the behavior change.
Reviewed changes
Copilot reviewed 5 out of 5 changed files in this pull request and generated 1 comment.
Show a summary per file
| File | Description |
|---|---|
| compiler/test/compilable/fix22671.d | Regression coverage for GC allocations inside if (__ctfe) in @nogc functions (including else and !__ctfe rewrite). |
| compiler/src/dmd/statementsem.d | Captures sc.ctfeBlock onto ReturnStatement during semantic analysis. |
| compiler/src/dmd/statement.d | Adds inCtfeBlock field to ReturnStatement. |
| compiler/src/dmd/semantic3.d | Temporarily enables ctfeBlock during ReturnStatement post-pass GC checking when applicable. |
| changelog/dmd.nogc-ctfe-alloc.dd | Documents the @nogc + if (__ctfe) GC-allocation acceptance change. |
💡 Add Copilot custom instructions for smarter, more guided reviews. Learn how to get started.
| FuncDeclaration fesFunc; // nested function for foreach it is in | ||
| bool inCtfeBlock; /// set if return is inside an `if (__ctfe)` block |
There was a problem hiding this comment.
ReturnStatement gained a new data member (inCtfeBlock). The corresponding C++ headers (compiler/src/dmd/statement.h and compiler/src/dmd/frontend.h) still define ReturnStatement without this field, so they’re now out of sync with the D AST definition. Please regenerate/update those headers (dtoh output) to keep the D/C++ AST layouts consistent.
|
See the copilot suggestions for the fix for the circleCI failure. |
compiler/src/dmd/semantic3.d
Outdated
| // https://issues.dlang.org/show_bug.cgi?id=22671 | ||
| // GC allocations inside `if (__ctfe)` blocks are always allowed | ||
| const prevCtfeBlock = sc2.ctfeBlock; | ||
| if (rs.inCtfeBlock) |
There was a problem hiding this comment.
No need to modfiy sc2.ctfeBlock, checkGC returns exp anyway if set, so
if (!rs.inCtfeBlock) exp = exp.checkGC(sc2);should be good enough.
compiler/test/compilable/fix22671.d
Outdated
| @@ -0,0 +1,51 @@ | |||
| // https://issues.dlang.org/show_bug.cgi?id=22671 | |||
There was a problem hiding this comment.
This link points to bugzilla which is dead
compiler/src/dmd/semantic3.d
Outdated
| if (tret.ty == Terror) | ||
| { | ||
| // https://issues.dlang.org/show_bug.cgi?id=13702 | ||
| // https://issues.dlang.org/show_bug.cgi?id=22671 |
…on checks in CTFE blocks
|
Compare and contrast to OpenD's fix for this issue: |
Indeed this looks simpler, I was expecting something like that in the first place, too. But AFAICT evaluating GC usage of the return statement at function level doesn't provide the scope adapted by the Doesn't your patch deal with calls of non- |
It's always possible I just did it wrong in some subtle way (wouldn't be the first time!), but I downloaded the test file in this PR and stock opend built it successfully: |
Problem
@nogcfunctions that allocate memory via the GC inside anif (__ctfe)blockwere incorrectly rejected with a
@nogcviolation:Since
if (__ctfe)code only ever runs at compile time (CTFE), and GC allocationis the only way to allocate memory during CTFE, this should be allowed.
Root Cause
semantic3.dhas a post-pass loop over allReturnStatements collected infd.returns. It callscheckGC(sc2)using the function-level scopesc2,which does not have
ctfeBlock = true— even if the return statement wasinside an
if (__ctfe)block. This caused the GC check to fire incorrectly.The analogous
ExpressionStatementpath (e.g.if (__ctfe) { new Foo(); })was already correct, because those
checkGCcalls happen during statementsemantics with a scope that does have
ctfeBlock = true.Fix
Added
bool inCtfeBlocktoReturnStatement(following the same patternalready used by
GotoStatementandLabelStatement).statement.d: AddedinCtfeBlockfield toReturnStatementstatementsem.d: Setrs.inCtfeBlock = sc.ctfeBlockat the top ofvisitReturn(), capturing the scope state at the time the return statementis semantically analyzed
semantic3.d: In thefd.returnspost-pass loop, save/restoresc2.ctfeBlockand temporarily set it totruewhenrs.inCtfeBlockisset, before calling
checkGCTest
compiler/test/compilable/fix22671.dcovers:return new ClassName()insideif (__ctfe)in a@nogcfunctionnew int[]()array allocation insideif (__ctfe)in a@nogc voidfunctionif (__ctfe) ... else ...formif (!__ctfe) ... else ...form (which the compiler rewrites internally)Verified that
@nogcstill correctly rejects GC allocations outsideif (__ctfe)blocks.Fixes #22671