Skip to content

Aggregate parens-init checks for dangling too aggressively #61567

@timsong-cpp

Description

@timsong-cpp

Clang rejects the well-formed but dangling cases from http://eel.is/c++draft/dcl.init.general#example-3:

struct A {
  int a;
  int&& r;
};

int f();
int n = 10;

A a2(1, f());                   // well-formed, but dangling reference
A a4(1.0, 1);                   // well-formed, but dangling reference
<source>:9:9: error: reference member 'r' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object
A a2(1, f());                   // well-formed, but dangling reference
        ^~~
<source>:3:9: note: reference member declared here
  int&& r;
        ^
<source>:10:11: error: reference member 'r' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object
A a4(1.0, 1);                   // well-formed, but dangling reference
          ^
<source>:3:9: note: reference member declared here
  int&& r;

Now, these particular examples may well have justified a warning, but Clang also rejects

void f(A);

void g() {
    f(A(1, 1));
}

in which both the temporary and the aggregate live to the end of the full-expression. It also warns on

void h(int i) {
   f(A(1, static_cast<int&&>(i)));
}
<source>:16:31: warning: binding reference member 'r' to stack allocated parameter 'i' [-Wdangling-field]
    f(A(1, static_cast<int&&>(i)));
                              ^
<source>:3:9: note: reference member declared here
  int&& r;
        ^

even though i outlives the aggregate.

This will affect uses of C++23 std::ranges::elements_of, which is an aggregate with a reference member that is intended to be used exactly like this.

Metadata

Metadata

Assignees

Labels

Type

No type

Projects

Status

Done

Relationships

None yet

Development

No branches or pull requests

Issue actions