Skip to content

Commit 7f52e4c

Browse files
bgra8Bogdan Graur
andauthored
Revert "Reapply "[Clang][CWG1815] Support lifetime extension of temporary created by aggregate initialization using a default member initializer" (#92527)" (#94600)
Reverting due to #92527 (comment). This reverts commit f049d72. Co-authored-by: Bogdan Graur <[email protected]>
1 parent e285818 commit 7f52e4c

File tree

15 files changed

+61
-168
lines changed

15 files changed

+61
-168
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10082,6 +10082,12 @@ def warn_new_dangling_initializer_list : Warning<
1008210082
"the allocated initializer list}0 "
1008310083
"will be destroyed at the end of the full-expression">,
1008410084
InGroup<DanglingInitializerList>;
10085+
def warn_unsupported_lifetime_extension : Warning<
10086+
"lifetime extension of "
10087+
"%select{temporary|backing array of initializer list}0 created "
10088+
"by aggregate initialization using a default member initializer "
10089+
"is not yet supported; lifetime of %select{temporary|backing array}0 "
10090+
"will end at the end of the full-expression">, InGroup<Dangling>;
1008510091

1008610092
// For non-floating point, expressions of the form x == x or x != x
1008710093
// should result in a warning, since these always evaluate to a constant.

clang/lib/Sema/SemaExpr.cpp

Lines changed: 8 additions & 23 deletions
Original file line numberDiff line numberDiff line change
@@ -5572,9 +5572,10 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
55725572
Res = Immediate.TransformInitializer(Param->getInit(),
55735573
/*NotCopy=*/false);
55745574
});
5575-
if (Res.isUsable())
5576-
Res = ConvertParamDefaultArgument(Param, Res.get(),
5577-
Res.get()->getBeginLoc());
5575+
if (Res.isInvalid())
5576+
return ExprError();
5577+
Res = ConvertParamDefaultArgument(Param, Res.get(),
5578+
Res.get()->getBeginLoc());
55785579
if (Res.isInvalid())
55795580
return ExprError();
55805581
Init = Res.get();
@@ -5610,7 +5611,7 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
56105611
Expr *Init = nullptr;
56115612

56125613
bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer();
5613-
bool InLifetimeExtendingContext = isInLifetimeExtendingContext();
5614+
56145615
EnterExpressionEvaluationContext EvalContext(
56155616
*this, ExpressionEvaluationContext::PotentiallyEvaluated, Field);
56165617

@@ -5645,35 +5646,19 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
56455646
ImmediateCallVisitor V(getASTContext());
56465647
if (!NestedDefaultChecking)
56475648
V.TraverseDecl(Field);
5648-
5649-
// CWG1815
5650-
// Support lifetime extension of temporary created by aggregate
5651-
// initialization using a default member initializer. We should always rebuild
5652-
// the initializer if it contains any temporaries (if the initializer
5653-
// expression is an ExprWithCleanups). Then make sure the normal lifetime
5654-
// extension code recurses into the default initializer and does lifetime
5655-
// extension when warranted.
5656-
bool ContainsAnyTemporaries =
5657-
isa_and_present<ExprWithCleanups>(Field->getInClassInitializer());
5658-
if (V.HasImmediateCalls || InLifetimeExtendingContext ||
5659-
ContainsAnyTemporaries) {
5649+
if (V.HasImmediateCalls) {
56605650
ExprEvalContexts.back().DelayedDefaultInitializationContext = {Loc, Field,
56615651
CurContext};
56625652
ExprEvalContexts.back().IsCurrentlyCheckingDefaultArgumentOrInitializer =
56635653
NestedDefaultChecking;
5664-
// Pass down lifetime extending flag, and collect temporaries in
5665-
// CreateMaterializeTemporaryExpr when we rewrite the call argument.
5666-
keepInLifetimeExtendingContext();
5654+
56675655
EnsureImmediateInvocationInDefaultArgs Immediate(*this);
56685656
ExprResult Res;
5669-
5670-
// Rebuild CXXDefaultInitExpr might cause diagnostics.
5671-
SFINAETrap Trap(*this);
56725657
runWithSufficientStackSpace(Loc, [&] {
56735658
Res = Immediate.TransformInitializer(Field->getInClassInitializer(),
56745659
/*CXXDirectInit=*/false);
56755660
});
5676-
if (Res.isUsable())
5661+
if (!Res.isInvalid())
56775662
Res = ConvertMemberDefaultInitExpression(Field, Res.get(), Loc);
56785663
if (Res.isInvalid()) {
56795664
Field->setInvalidDecl();

clang/lib/Sema/SemaExprCXX.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1555,6 +1555,9 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
15551555
bool ListInitialization) {
15561556
QualType Ty = TInfo->getType();
15571557
SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc();
1558+
1559+
assert((!ListInitialization || Exprs.size() == 1) &&
1560+
"List initialization must have exactly one expression.");
15581561
SourceRange FullRange = SourceRange(TyBeginLoc, RParenOrBraceLoc);
15591562

15601563
InitializedEntity Entity =

clang/lib/Sema/SemaInit.cpp

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8063,6 +8063,11 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
80638063
enum PathLifetimeKind {
80648064
/// Lifetime-extend along this path.
80658065
Extend,
8066+
/// We should lifetime-extend, but we don't because (due to technical
8067+
/// limitations) we can't. This happens for default member initializers,
8068+
/// which we don't clone for every use, so we don't have a unique
8069+
/// MaterializeTemporaryExpr to update.
8070+
ShouldExtend,
80668071
/// Do not lifetime extend along this path.
80678072
NoExtend
80688073
};
@@ -8074,7 +8079,7 @@ shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) {
80748079
PathLifetimeKind Kind = PathLifetimeKind::Extend;
80758080
for (auto Elem : Path) {
80768081
if (Elem.Kind == IndirectLocalPathEntry::DefaultInit)
8077-
Kind = PathLifetimeKind::Extend;
8082+
Kind = PathLifetimeKind::ShouldExtend;
80788083
else if (Elem.Kind != IndirectLocalPathEntry::LambdaCaptureInit)
80798084
return PathLifetimeKind::NoExtend;
80808085
}
@@ -8194,6 +8199,18 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
81948199
ExtendingEntity->allocateManglingNumber());
81958200
// Also visit the temporaries lifetime-extended by this initializer.
81968201
return true;
8202+
8203+
case PathLifetimeKind::ShouldExtend:
8204+
// We're supposed to lifetime-extend the temporary along this path (per
8205+
// the resolution of DR1815), but we don't support that yet.
8206+
//
8207+
// FIXME: Properly handle this situation. Perhaps the easiest approach
8208+
// would be to clone the initializer expression on each use that would
8209+
// lifetime extend its temporaries.
8210+
Diag(DiagLoc, diag::warn_unsupported_lifetime_extension)
8211+
<< RK << DiagRange;
8212+
break;
8213+
81978214
case PathLifetimeKind::NoExtend:
81988215
// If the path goes through the initialization of a variable or field,
81998216
// it can't possibly reach a temporary created in this full-expression.

clang/lib/Sema/TreeTransform.h

Lines changed: 4 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -14172,13 +14172,6 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
1417214172
if (TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
1417314173
&ArgumentChanged))
1417414174
return ExprError();
14175-
14176-
if (E->isListInitialization() && !E->isStdInitListInitialization()) {
14177-
ExprResult Res = RebuildInitList(E->getBeginLoc(), Args, E->getEndLoc());
14178-
if (Res.isInvalid())
14179-
return ExprError();
14180-
Args = {Res.get()};
14181-
}
1418214175
}
1418314176

1418414177
if (!getDerived().AlwaysRebuild() &&
@@ -14190,9 +14183,12 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
1419014183
return SemaRef.MaybeBindToTemporary(E);
1419114184
}
1419214185

14186+
// FIXME: We should just pass E->isListInitialization(), but we're not
14187+
// prepared to handle list-initialization without a child InitListExpr.
1419314188
SourceLocation LParenLoc = T->getTypeLoc().getEndLoc();
1419414189
return getDerived().RebuildCXXTemporaryObjectExpr(
14195-
T, LParenLoc, Args, E->getEndLoc(), E->isListInitialization());
14190+
T, LParenLoc, Args, E->getEndLoc(),
14191+
/*ListInitialization=*/LParenLoc.isInvalid());
1419614192
}
1419714193

1419814194
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 & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -483,6 +483,8 @@ namespace cwg1696 { // cwg1696: 7
483483
const A &a = A(); // #cwg1696-D1-a
484484
};
485485
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}}
486488

487489
struct D2 {
488490
const A &a = A(); // #cwg1696-D2-a

clang/test/CXX/drs/cwg18xx.cpp

Lines changed: 5 additions & 14 deletions
Original file line numberDiff line numberDiff line change
@@ -206,28 +206,19 @@ namespace cwg1814 { // cwg1814: yes
206206
#endif
207207
}
208208

209-
namespace cwg1815 { // cwg1815: 19
209+
namespace cwg1815 { // cwg1815: no
210210
#if __cplusplus >= 201402L
211-
struct A { int &&r = 0; };
211+
// FIXME: needs codegen test
212+
struct A { int &&r = 0; }; // #cwg1815-A
212213
A a = {};
214+
// 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}} FIXME
215+
// since-cxx14-note@#cwg1815-A {{initializing field 'r' with default member initializer}}
213216

214217
struct B { int &&r = 0; }; // #cwg1815-B
215218
// since-cxx14-error@-1 {{reference member 'r' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
216219
// since-cxx14-note@#cwg1815-B {{initializing field 'r' with default member initializer}}
217220
// since-cxx14-note@#cwg1815-b {{in implicit default constructor for 'cwg1815::B' first required here}}
218221
B b; // #cwg1815-b
219-
220-
#if __cplusplus >= 201703L
221-
struct C { const int &r = 0; };
222-
constexpr C c = {}; // OK, since cwg1815
223-
static_assert(c.r == 0);
224-
225-
constexpr int f() {
226-
A a = {}; // OK, since cwg1815
227-
return a.r;
228-
}
229-
static_assert(f() == 0);
230-
#endif
231222
#endif
232223
}
233224

0 commit comments

Comments
 (0)