[clang] Reapply "[Clang][CWG1815] Support lifetime extension of temporary created by aggregate initialization using a default member initializer" (PR #92527)
via cfe-commits
cfe-commits at lists.llvm.org
Mon May 20 08:44:09 PDT 2024
================
@@ -5695,19 +5694,35 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
ImmediateCallVisitor V(getASTContext());
if (!NestedDefaultChecking)
V.TraverseDecl(Field);
- if (V.HasImmediateCalls) {
+
+ // CWG1815
+ // Support lifetime extension of temporary created by aggregate
+ // initialization using a default member initializer. We should always rebuild
+ // the initializer if it contains any temporaries (if the initializer
+ // expression is an ExprWithCleanups). Then make sure the normal lifetime
+ // extension code recurses into the default initializer and does lifetime
+ // extension when warranted.
+ bool ContainsAnyTemporaries =
+ isa_and_present<ExprWithCleanups>(Field->getInClassInitializer());
+ if (V.HasImmediateCalls || InLifetimeExtendingContext ||
+ ContainsAnyTemporaries) {
ExprEvalContexts.back().DelayedDefaultInitializationContext = {Loc, Field,
CurContext};
ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer =
NestedDefaultChecking;
-
+ // Pass down lifetime extending flag, and collect temporaries in
+ // CreateMaterializeTemporaryExpr when we rewrite the call argument.
+ keepInLifetimeExtendingContext();
EnsureImmediateInvocationInDefaultArgs Immediate(*this);
ExprResult Res;
+
+ // Rebuild CXXDefaultInitExpr might cause diagnostics.
+ SFINAETrap Trap(*this);
----------------
yronglin wrote:
Here we add `SFINAETrap Trap(*this)`. It was used to resolve the issue which looks like https://github.com/llvm/llvm-project/blob/main/clang/test/CXX/dcl.decl/dcl.init/p14-0x.cpp .
A shorter reproducer:
```
class Private {
Private(int); // expected-note {{here}}
public:
Private();
};
class S {
Private p = 42; // expected-error {{private constructor}}
S() {} // expected-error {{call to deleted constructor of 'NoDefault'}} \
expected-error {{must explicitly initialize the member 'e1' which does not have a default constructor}}
S(int) {}
};
// FIXME: test the other forms which use copy-initialization
```
`Field->getInClassInitializer()` contains an `bad access error`, then we try to rebuild this initializer, the diagnostic will emit 3 times. (The result of `Field->getInClassInitializer()->containsErrors()` 3 times are `false`).
1st time: parser member initializer.
2nd time: After rebuild, Line 5726 ` Res = ConvertMemberDefaultInitExpression(Field, Res.get(), Loc);`
3rd time: After rebuild, Line 5726 ` Res = ConvertMemberDefaultInitExpression(Field, Res.get(), Loc);`
```
./error.cpp:8:15: error: field of type 'Private' has private constructor
8 | Private p = 42; // expected-error {{private constructor}}
| ^
./error.cpp:2:3: note: implicitly declared private here
2 | Private(int); // expected-note {{here}}
| ^
./error.cpp:8:15: error: field of type 'Private' has private constructor
8 | Private p = 42; // expected-error {{private constructor}}
| ^
./error.cpp:2:3: note: implicitly declared private here
2 | Private(int); // expected-note {{here}}
| ^
./error.cpp:8:15: error: field of type 'Private' has private constructor
8 | Private p = 42; // expected-error {{private constructor}}
| ^
./error.cpp:2:3: note: implicitly declared private here
2 | Private(int); // expected-note {{here}}
| ^
3 errors generated.
```
https://github.com/llvm/llvm-project/pull/92527
More information about the cfe-commits
mailing list