Skip to content

Wrong position info for end-of-scope actions #309

Open

Description

@daveedvdv-nvidia

Consider:

$ cat test.cpp
int sink;

struct Dtor
{
    __attribute__((noinline)) ~Dtor()
    {
        sink = sink + 1;
    }
};

void f()
{
    int before = 257;

    Dtor d;

    int after = 259;

    sink = after - before + 2;
}  // Line 20

GCC maps the implicit scope-exit destructor call to the closing brace line (i.e., test.cpp:20):

$ g++ -std=c++17 -g -O0 -fno-exceptions -c test.cpp -o test.o
$ objdump -d -l --demangle test.o | sed -n '/<f()>:/,/^$/p'
0000000000000000 <f()>:
f():
test.cpp:19
  29: 8b 45 f4              mov    -0xc(%rbp),%eax
  2c: 2b 45 f0              sub    -0x10(%rbp),%eax
  2f: 83 c0 02              add    $0x2,%eax
  32: 89 05 00 00 00 00     mov    %eax,0x0(%rip)
test.cpp:20
  38: 48 8d 45 ef           lea    -0x11(%rbp),%rax
  3c: 48 89 c7              mov    %rax,%rdi
  3f: e8 00 00 00 00        call   44 <f()+0x44>

EDGcpfe accepts the program but the C-generating back end output keeps the cleanup on the previous statement line:

$ src/edgcpfe --c++17 --gnu_version=110500 --no_exceptions \
    --gen_c_file_name test.edg.cpp test.cpp
$ sed -n '17,32p' test.edg.cpp
void _Z1fv(void)
{
auto int __13_9_before = 257;

auto struct Dtor __15_10_d;

auto int __17_9_after = 259;
# 15
{ }



sink = ((__17_9_after - __13_9_before) + 2); { _ZN4DtorD1Ev((&__15_10_d));  }
}__asm__(".align 2");

Because the last directive is # 15, the generated line containing both the assignment and destructor call corresponds to source line 19. The destructor call should instead be positioned at source line 20, which has the closing brace corresponding to scope exit.
The same pattern is visible without the noinline attribute: The inlined destructor body is emitted before the generated line for the closing brace rather than at the closing-brace position.

Activity

  1. added a commit that references this issue on Oct 21, 2026
  2. daveedvdv-nvidia commented on Nov 5, 2026

    @daveedvdv-nvidia
    ContributorAuthor

    Reopening: the fix gives the implicit scope-exit destructor call the right line information, but it also moves the position at which diagnostics about that call are reported, which is undesirable.

    Consider:

    struct S { ~S(); };
    
    void f()
    {
      S s;   // line 5: declaration of the destroyed object
      // ...
    }        // line 7: scope exit

    For debugging and line mapping, the destructor call that runs at scope exit should be attributed to line 7, and that is what the fix achieves.

    However, the fix sets both code_pos_for_lowering and error_position to the closing brace while the end-of-function cleanup actions are generated, and the resulting call has no other position. Any diagnostic that arises from that synthesized call (whether issued during lowering or by a later pass that analyzes the lowered IL) is therefore now reported at line 7 instead of at the declaration on line 5. (Before the fix, the call had no position at all, so such diagnostics were positionless, which isn't good either.)

    Line 5 is the better location for such diagnostics: it is the construct that implies the destructor call, it is where the front end already reports problems with the destructor (e.g., when it is deleted or inaccessible), and it is where a user would place diagnostic-control pragmas (e.g., #pragma diag_suppress regions) to silence them. A pragma region around the declaration no longer covers a diagnostic positioned at the closing brace.

    Proposal: decouple the two positions for synthesized scope-exit destructor calls on named objects. Keep the statement position (used for line information) at the scope exit, but report diagnostics arising from the call at the destroyed object's declaration.

    This should apply to all scope exits, not just the end of a function body: Destructor calls at the end of a nested block (already positioned at that block's closing brace before this fix) and at return, goto, break, and continue (positioned at the jump statement) have the same issue.

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

Metadata

Metadata

Labels

No labels
No labels

Type

No type

Projects

No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions