Skip to content

Commit cca54e3

Browse files
committed
Revert "Reapply "[Clang][CWG1815] Support lifetime extension of temporary created by aggregate initialization using a default member initializer" (#97308)"
This reverts commit 45c8766 and 049512e. This change triggers failed asserts on inputs like this: struct a { } constexpr b; class c { public: c(a); }; class B { public: using d = int; struct e { enum { f } g; int h; c i; d j{}; }; }; B::e k{B::e::f, int(), b}; Compiled like this: clang -target x86_64-linux-gnu -c repro.cpp clang: ../../clang/lib/CodeGen/CGExpr.cpp:3105: clang::CodeGen::LValue clang::CodeGen::CodeGenFunction::EmitDeclRefLValue(const clang::DeclRefExpr*): Assertion `(ND->isUsed(false) || !isa<VarDecl>(ND) || E->isNonOdrUse() || !E->getLocation().isValid()) && "Should not use decl without marking it used!"' failed.
1 parent 7a930ce commit cca54e3

20 files changed

+87
-251
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 0 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -108,9 +108,6 @@ C++ Language Changes
108108
- Allow single element access of GCC vector/ext_vector_type object to be
109109
constant expression. Supports the `V.xyzw` syntax and other tidbits
110110
as seen in OpenCL. Selecting multiple elements is left as a future work.
111-
- Implement `CWG1815 <https://wg21.link/CWG1815>`_. Support lifetime extension
112-
of temporary created by aggregate initialization using a default member
113-
initializer.
114111

115112
- Accept C++26 user-defined ``static_assert`` messages in C++11 as an extension.
116113

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10159,6 +10159,13 @@ def warn_dangling_pointer_assignment : Warning<
1015910159
"will be destroyed at the end of the full-expression">,
1016010160
InGroup<DanglingAssignment>;
1016110161

10162+
def warn_unsupported_lifetime_extension : Warning<
10163+
"lifetime extension of "
10164+
"%select{temporary|backing array of initializer list}0 created "
10165+
"by aggregate initialization using a default member initializer "
10166+
"is not yet supported; lifetime of %select{temporary|backing array}0 "
10167+
"will end at the end of the full-expression">, InGroup<Dangling>;
10168+
1016210169
// For non-floating point, expressions of the form x == x or x != x
1016310170
// should result in a warning, since these always evaluate to a constant.
1016410171
// Array comparisons have similar warnings

clang/include/clang/Sema/Sema.h

Lines changed: 15 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6403,9 +6403,6 @@ class Sema final : public SemaBase {
64036403
/// example, in a for-range initializer).
64046404
bool InLifetimeExtendingContext = false;
64056405

6406-
/// Whether we should rebuild CXXDefaultArgExpr and CXXDefaultInitExpr.
6407-
bool RebuildDefaultArgOrDefaultInit = false;
6408-
64096406
// When evaluating immediate functions in the initializer of a default
64106407
// argument or default member initializer, this is the declaration whose
64116408
// default initializer is being evaluated and the location of the call
@@ -7813,11 +7810,9 @@ class Sema final : public SemaBase {
78137810
}
78147811

78157812
bool isInLifetimeExtendingContext() const {
7816-
return currentEvaluationContext().InLifetimeExtendingContext;
7817-
}
7818-
7819-
bool needRebuildDefaultArgOrInit() const {
7820-
return currentEvaluationContext().RebuildDefaultArgOrDefaultInit;
7813+
assert(!ExprEvalContexts.empty() &&
7814+
"Must be in an expression evaluation context");
7815+
return ExprEvalContexts.back().InLifetimeExtendingContext;
78217816
}
78227817

78237818
bool isCheckingDefaultArgumentOrInitializer() const {
@@ -7859,6 +7854,18 @@ class Sema final : public SemaBase {
78597854
return Res;
78607855
}
78617856

7857+
/// keepInLifetimeExtendingContext - Pull down InLifetimeExtendingContext
7858+
/// flag from previous context.
7859+
void keepInLifetimeExtendingContext() {
7860+
if (ExprEvalContexts.size() > 2 &&
7861+
parentEvaluationContext().InLifetimeExtendingContext) {
7862+
auto &LastRecord = ExprEvalContexts.back();
7863+
auto &PrevRecord = parentEvaluationContext();
7864+
LastRecord.InLifetimeExtendingContext =
7865+
PrevRecord.InLifetimeExtendingContext;
7866+
}
7867+
}
7868+
78627869
DefaultedComparisonKind getDefaultedComparisonKind(const FunctionDecl *FD) {
78637870
return getDefaultedFunctionKind(FD).asComparison();
78647871
}

clang/lib/Parse/ParseDecl.cpp

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2509,9 +2509,8 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
25092509

25102510
// P2718R0 - Lifetime extension in range-based for loops.
25112511
if (getLangOpts().CPlusPlus23) {
2512-
auto &LastRecord = Actions.currentEvaluationContext();
2512+
auto &LastRecord = Actions.ExprEvalContexts.back();
25132513
LastRecord.InLifetimeExtendingContext = true;
2514-
LastRecord.RebuildDefaultArgOrDefaultInit = true;
25152514
}
25162515

25172516
if (getLangOpts().OpenMP)

clang/lib/Sema/CheckExprLifetime.cpp

Lines changed: 17 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -871,6 +871,11 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
871871
enum PathLifetimeKind {
872872
/// Lifetime-extend along this path.
873873
Extend,
874+
/// We should lifetime-extend, but we don't because (due to technical
875+
/// limitations) we can't. This happens for default member initializers,
876+
/// which we don't clone for every use, so we don't have a unique
877+
/// MaterializeTemporaryExpr to update.
878+
ShouldExtend,
874879
/// Do not lifetime extend along this path.
875880
NoExtend
876881
};
@@ -882,7 +887,7 @@ shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) {
882887
PathLifetimeKind Kind = PathLifetimeKind::Extend;
883888
for (auto Elem : Path) {
884889
if (Elem.Kind == IndirectLocalPathEntry::DefaultInit)
885-
return PathLifetimeKind::Extend;
890+
Kind = PathLifetimeKind::ShouldExtend;
886891
else if (Elem.Kind != IndirectLocalPathEntry::LambdaCaptureInit)
887892
return PathLifetimeKind::NoExtend;
888893
}
@@ -1029,6 +1034,17 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
10291034
// Also visit the temporaries lifetime-extended by this initializer.
10301035
return true;
10311036

1037+
case PathLifetimeKind::ShouldExtend:
1038+
// We're supposed to lifetime-extend the temporary along this path (per
1039+
// the resolution of DR1815), but we don't support that yet.
1040+
//
1041+
// FIXME: Properly handle this situation. Perhaps the easiest approach
1042+
// would be to clone the initializer expression on each use that would
1043+
// lifetime extend its temporaries.
1044+
SemaRef.Diag(DiagLoc, diag::warn_unsupported_lifetime_extension)
1045+
<< RK << DiagRange;
1046+
break;
1047+
10321048
case PathLifetimeKind::NoExtend:
10331049
// If the path goes through the initialization of a variable or field,
10341050
// it can't possibly reach a temporary created in this full-expression.

clang/lib/Sema/SemaExpr.cpp

Lines changed: 9 additions & 27 deletions
Original file line numberDiff line numberDiff line change
@@ -5429,8 +5429,6 @@ struct EnsureImmediateInvocationInDefaultArgs
54295429
EnsureImmediateInvocationInDefaultArgs(Sema &SemaRef)
54305430
: TreeTransform(SemaRef) {}
54315431

5432-
bool AlwaysRebuild() { return true; }
5433-
54345432
// Lambda can only have immediate invocations in the default
54355433
// args of their parameters, which is transformed upon calling the closure.
54365434
// The body is not a subexpression, so we have nothing to do.
@@ -5472,7 +5470,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
54725470
assert(Param->hasDefaultArg() && "can't build nonexistent default arg");
54735471

54745472
bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer();
5475-
bool NeedRebuild = needRebuildDefaultArgOrInit();
5473+
bool InLifetimeExtendingContext = isInLifetimeExtendingContext();
54765474
std::optional<ExpressionEvaluationContextRecord::InitializationContext>
54775475
InitializationContext =
54785476
OutermostDeclarationWithDelayedImmediateInvocations();
@@ -5508,15 +5506,13 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
55085506

55095507
// Rewrite the call argument that was created from the corresponding
55105508
// parameter's default argument.
5511-
if (V.HasImmediateCalls ||
5512-
(NeedRebuild && isa_and_present<ExprWithCleanups>(Param->getInit()))) {
5509+
if (V.HasImmediateCalls || InLifetimeExtendingContext) {
55135510
if (V.HasImmediateCalls)
55145511
ExprEvalContexts.back().DelayedDefaultInitializationContext = {
55155512
CallLoc, Param, CurContext};
55165513
// Pass down lifetime extending flag, and collect temporaries in
55175514
// CreateMaterializeTemporaryExpr when we rewrite the call argument.
5518-
currentEvaluationContext().InLifetimeExtendingContext =
5519-
parentEvaluationContext().InLifetimeExtendingContext;
5515+
keepInLifetimeExtendingContext();
55205516
EnsureImmediateInvocationInDefaultArgs Immediate(*this);
55215517
ExprResult Res;
55225518
runWithSufficientStackSpace(CallLoc, [&] {
@@ -5562,7 +5558,7 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
55625558
Expr *Init = nullptr;
55635559

55645560
bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer();
5565-
bool NeedRebuild = needRebuildDefaultArgOrInit();
5561+
55665562
EnterExpressionEvaluationContext EvalContext(
55675563
*this, ExpressionEvaluationContext::PotentiallyEvaluated, Field);
55685564

@@ -5597,27 +5593,12 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
55975593
ImmediateCallVisitor V(getASTContext());
55985594
if (!NestedDefaultChecking)
55995595
V.TraverseDecl(Field);
5600-
5601-
// CWG1815
5602-
// Support lifetime extension of temporary created by aggregate
5603-
// initialization using a default member initializer. We should rebuild
5604-
// the initializer in a lifetime extension context if the initializer
5605-
// expression is an ExprWithCleanups. Then make sure the normal lifetime
5606-
// extension code recurses into the default initializer and does lifetime
5607-
// extension when warranted.
5608-
bool ContainsAnyTemporaries =
5609-
isa_and_present<ExprWithCleanups>(Field->getInClassInitializer());
5610-
if (Field->getInClassInitializer() &&
5611-
!Field->getInClassInitializer()->containsErrors() &&
5612-
(V.HasImmediateCalls || (NeedRebuild && ContainsAnyTemporaries))) {
5596+
if (V.HasImmediateCalls) {
56135597
ExprEvalContexts.back().DelayedDefaultInitializationContext = {Loc, Field,
56145598
CurContext};
56155599
ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer =
56165600
NestedDefaultChecking;
5617-
// Pass down lifetime extending flag, and collect temporaries in
5618-
// CreateMaterializeTemporaryExpr when we rewrite the call argument.
5619-
currentEvaluationContext().InLifetimeExtendingContext =
5620-
parentEvaluationContext().InLifetimeExtendingContext;
5601+
56215602
EnsureImmediateInvocationInDefaultArgs Immediate(*this);
56225603
ExprResult Res;
56235604
runWithSufficientStackSpace(Loc, [&] {
@@ -17694,10 +17675,11 @@ void Sema::PopExpressionEvaluationContext() {
1769417675

1769517676
// Append the collected materialized temporaries into previous context before
1769617677
// exit if the previous also is a lifetime extending context.
17678+
auto &PrevRecord = parentEvaluationContext();
1769717679
if (getLangOpts().CPlusPlus23 && Rec.InLifetimeExtendingContext &&
17698-
parentEvaluationContext().InLifetimeExtendingContext &&
17680+
PrevRecord.InLifetimeExtendingContext &&
1769917681
!Rec.ForRangeLifetimeExtendTemps.empty()) {
17700-
parentEvaluationContext().ForRangeLifetimeExtendTemps.append(
17682+
PrevRecord.ForRangeLifetimeExtendTemps.append(
1770117683
Rec.ForRangeLifetimeExtendTemps);
1770217684
}
1770317685

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1540,6 +1540,9 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
15401540
bool ListInitialization) {
15411541
QualType Ty = TInfo->getType();
15421542
SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc();
1543+
1544+
assert((!ListInitialization || Exprs.size() == 1) &&
1545+
"List initialization must have exactly one expression.");
15431546
SourceRange FullRange = SourceRange(TyBeginLoc, RParenOrBraceLoc);
15441547

15451548
InitializedEntity Entity =

clang/lib/Sema/SemaInit.cpp

Lines changed: 6 additions & 16 deletions
Original file line numberDiff line numberDiff line change
@@ -750,20 +750,8 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
750750
if (Field->hasInClassInitializer()) {
751751
if (VerifyOnly)
752752
return;
753-
ExprResult DIE;
754-
{
755-
// Enter a default initializer rebuild context, then we can support
756-
// lifetime extension of temporary created by aggregate initialization
757-
// using a default member initializer.
758-
// CWG1815 (https://wg21.link/CWG1815).
759-
EnterExpressionEvaluationContext RebuildDefaultInit(
760-
SemaRef, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
761-
// Just copy previous record, make sure we haven't forget anything.
762-
SemaRef.currentEvaluationContext() = SemaRef.parentEvaluationContext();
763-
SemaRef.currentEvaluationContext().RebuildDefaultArgOrDefaultInit =
764-
true;
765-
DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field);
766-
}
753+
754+
ExprResult DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field);
767755
if (DIE.isInvalid()) {
768756
hadError = true;
769757
return;
@@ -7533,8 +7521,10 @@ Sema::CreateMaterializeTemporaryExpr(QualType T, Expr *Temporary,
75337521
// are done in both CreateMaterializeTemporaryExpr and MaybeBindToTemporary,
75347522
// but there may be a chance to merge them.
75357523
Cleanup.setExprNeedsCleanups(false);
7536-
if (isInLifetimeExtendingContext())
7537-
currentEvaluationContext().ForRangeLifetimeExtendTemps.push_back(MTE);
7524+
if (isInLifetimeExtendingContext()) {
7525+
auto &Record = ExprEvalContexts.back();
7526+
Record.ForRangeLifetimeExtendTemps.push_back(MTE);
7527+
}
75387528
return MTE;
75397529
}
75407530

clang/lib/Sema/SemaTemplateInstantiateDecl.cpp

Lines changed: 1 addition & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -5481,10 +5481,7 @@ void Sema::InstantiateVariableInitializer(
54815481
EnterExpressionEvaluationContext Evaluated(
54825482
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
54835483

5484-
currentEvaluationContext().InLifetimeExtendingContext =
5485-
parentEvaluationContext().InLifetimeExtendingContext;
5486-
currentEvaluationContext().RebuildDefaultArgOrDefaultInit =
5487-
parentEvaluationContext().RebuildDefaultArgOrDefaultInit;
5484+
keepInLifetimeExtendingContext();
54885485
// Instantiate the initializer.
54895486
ExprResult Init;
54905487

clang/lib/Sema/TreeTransform.h

Lines changed: 6 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -4254,10 +4254,7 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
42544254
getSema(), EnterExpressionEvaluationContext::InitList,
42554255
Construct->isListInitialization());
42564256

4257-
getSema().currentEvaluationContext().InLifetimeExtendingContext =
4258-
getSema().parentEvaluationContext().InLifetimeExtendingContext;
4259-
getSema().currentEvaluationContext().RebuildDefaultArgOrDefaultInit =
4260-
getSema().parentEvaluationContext().RebuildDefaultArgOrDefaultInit;
4257+
getSema().keepInLifetimeExtendingContext();
42614258
SmallVector<Expr*, 8> NewArgs;
42624259
bool ArgChanged = false;
42634260
if (getDerived().TransformExprs(Construct->getArgs(), Construct->getNumArgs(),
@@ -8927,9 +8924,8 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
89278924

89288925
// P2718R0 - Lifetime extension in range-based for loops.
89298926
if (getSema().getLangOpts().CPlusPlus23) {
8930-
auto &LastRecord = getSema().currentEvaluationContext();
8927+
auto &LastRecord = getSema().ExprEvalContexts.back();
89318928
LastRecord.InLifetimeExtendingContext = true;
8932-
LastRecord.RebuildDefaultArgOrDefaultInit = true;
89338929
}
89348930
StmtResult Init =
89358931
S->getInit() ? getDerived().TransformStmt(S->getInit()) : StmtResult();
@@ -14447,13 +14443,6 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
1444714443
if (TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
1444814444
&ArgumentChanged))
1444914445
return ExprError();
14450-
14451-
if (E->isListInitialization() && !E->isStdInitListInitialization()) {
14452-
ExprResult Res = RebuildInitList(E->getBeginLoc(), Args, E->getEndLoc());
14453-
if (Res.isInvalid())
14454-
return ExprError();
14455-
Args = {Res.get()};
14456-
}
1445714446
}
1445814447

1445914448
if (!getDerived().AlwaysRebuild() &&
@@ -14465,9 +14454,12 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
1446514454
return SemaRef.MaybeBindToTemporary(E);
1446614455
}
1446714456

14457+
// FIXME: We should just pass E->isListInitialization(), but we're not
14458+
// prepared to handle list-initialization without a child InitListExpr.
1446814459
SourceLocation LParenLoc = T->getTypeLoc().getEndLoc();
1446914460
return getDerived().RebuildCXXTemporaryObjectExpr(
14470-
T, LParenLoc, Args, E->getEndLoc(), E->isListInitialization());
14461+
T, LParenLoc, Args, E->getEndLoc(),
14462+
/*ListInitialization=*/LParenLoc.isInvalid());
1447114463
}
1447214464

1447314465
template<typename Derived>

clang/test/AST/ast-dump-default-init-json.cpp

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -789,10 +789,10 @@ void test() {
789789
// CHECK-NEXT: "valueCategory": "lvalue",
790790
// CHECK-NEXT: "extendingDecl": {
791791
// CHECK-NEXT: "id": "0x{{.*}}",
792-
// CHECK-NEXT: "kind": "VarDecl",
793-
// CHECK-NEXT: "name": "b",
792+
// CHECK-NEXT: "kind": "FieldDecl",
793+
// CHECK-NEXT: "name": "a",
794794
// CHECK-NEXT: "type": {
795-
// CHECK-NEXT: "qualType": "B"
795+
// CHECK-NEXT: "qualType": "const A &"
796796
// CHECK-NEXT: }
797797
// CHECK-NEXT: },
798798
// CHECK-NEXT: "storageDuration": "automatic",

clang/test/AST/ast-dump-default-init.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -13,7 +13,7 @@ void test() {
1313
}
1414
// CHECK: -CXXDefaultInitExpr 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue has rewritten init
1515
// CHECK-NEXT: `-ExprWithCleanups 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue
16-
// CHECK-NEXT: `-MaterializeTemporaryExpr 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue extended by Var 0x{{[^ ]*}} 'b' 'B'
16+
// CHECK-NEXT: `-MaterializeTemporaryExpr 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue extended by Field 0x{{[^ ]*}} 'a' 'const A &'
1717
// CHECK-NEXT: `-ImplicitCastExpr 0x{{[^ ]*}} <{{.*}}> 'const A' <NoOp>
1818
// CHECK-NEXT: `-CXXFunctionalCastExpr 0x{{[^ ]*}} <{{.*}}> 'A' functional cast to A <NoOp>
1919
// CHECK-NEXT: `-InitListExpr 0x{{[^ ]*}} <{{.*}}> 'A'

clang/test/Analysis/lifetime-extended-regions.cpp

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -120,11 +120,10 @@ void aggregateWithReferences() {
120120
clang_analyzer_dump(viaReference); // expected-warning-re {{&lifetime_extended_object{RefAggregate, viaReference, S{{[0-9]+}}} }}
121121
clang_analyzer_dump(viaReference.rx); // expected-warning-re {{&lifetime_extended_object{int, viaReference, S{{[0-9]+}}} }}
122122
clang_analyzer_dump(viaReference.ry); // expected-warning-re {{&lifetime_extended_object{Composite, viaReference, S{{[0-9]+}}} }}
123-
124-
// FIXME: clang currently support extending lifetime of object bound to reference members of aggregates,
125-
// that are created from default member initializer. But CFG and ExprEngine need to be updated to address this change.
126-
// The following expect warning: {{&lifetime_extended_object{Composite, defaultInitExtended, S{{[0-9]+}}} }}
127-
RefAggregate defaultInitExtended{i};
123+
124+
// clang does not currently implement extending lifetime of object bound to reference members of aggregates,
125+
// that are created from default member initializer (see `warn_unsupported_lifetime_extension` from `-Wdangling`)
126+
RefAggregate defaultInitExtended{i}; // clang-bug does not extend `Composite`
128127
clang_analyzer_dump(defaultInitExtended.ry); // expected-warning {{Unknown }}
129128
}
130129

clang/test/CXX/drs/cwg16xx.cpp

Lines changed: 2 additions & 21 deletions
Original file line numberDiff line numberDiff line change
@@ -449,27 +449,6 @@ namespace cwg1696 { // cwg1696: 7
449449
// since-cxx14-note@-2 {{default member initializer declared here}}
450450
};
451451
A a{a, a};
452-
453-
struct A1 {
454-
A1() : v(42) {}
455-
// since-cxx14-error@-1 {{reference member 'v' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
456-
// since-cxx14-note@#cwg1696-A1 {{reference member declared here}}
457-
const int &v; // #cwg1696-A1
458-
};
459-
460-
struct A2 {
461-
A2() = default;
462-
// since-cxx14-error@-1 {{reference member 'v' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
463-
// since-cxx14-note-re@#cwg1696-A2-b {{in defaulted default constructor for {{.*}} first required here}}
464-
// since-cxx14-note@#cwg1696-A2-a {{initializing field 'v' with default member initializer}}
465-
A2(int v) : v(v) {}
466-
// since-cxx14-warning@-1 {{binding reference member 'v' to stack allocated parameter 'v'}}
467-
// since-cxx14-note@#cwg1696-A2-a {{reference member declared here}}
468-
const int &v = 42; // #cwg1696-A2-a
469-
};
470-
A2 a1; // #cwg1696-A2-b
471-
472-
A2 a2(1); // OK, unfortunately
473452
#endif
474453
}
475454

@@ -504,6 +483,8 @@ namespace cwg1696 { // cwg1696: 7
504483
const A &a = A(); // #cwg1696-D1-a
505484
};
506485
D1 d1 = {}; // #cwg1696-d1
486+
// since-cxx14-warning@-1 {{lifetime extension of temporary created by aggregate initialization using a default member initializer is not yet supported; lifetime of temporary will end at the end of the full-expression}}
487+
// since-cxx14-note@#cwg1696-D1-a {{initializing field 'a' with default member initializer}}
507488

508489
struct D2 {
509490
const A &a = A(); // #cwg1696-D2-a

0 commit comments

Comments
 (0)