[clang] 224116a - Revert "[Clang][CWG1815] Support lifetime extension of temporary created by aggregate initialization using a default member initializer (#87933)"
via cfe-commits
cfe-commits at lists.llvm.org
Thu May 16 09:52:24 PDT 2024
Author: erichkeane
Date: 2024-05-16T09:52:19-07:00
New Revision: 224116ab9f4d97acb0cca76dc63c1d3d4a253078
URL: https://github.com/llvm/llvm-project/commit/224116ab9f4d97acb0cca76dc63c1d3d4a253078
DIFF: https://github.com/llvm/llvm-project/commit/224116ab9f4d97acb0cca76dc63c1d3d4a253078.diff
LOG: Revert "[Clang][CWG1815] Support lifetime extension of temporary created by aggregate initialization using a default member initializer (#87933)"
This reverts commit 17daa204feadf9c28fc13b7daa69c3cbe865b238.
Multiple examples on the PR
https://github.com/llvm/llvm-project/pull/87933
show regressions, so reverting until they can be fixed in the followup.
Added:
Modified:
clang/include/clang/Basic/DiagnosticSemaKinds.td
clang/lib/Sema/SemaExpr.cpp
clang/lib/Sema/SemaInit.cpp
clang/test/AST/ast-dump-default-init-json.cpp
clang/test/AST/ast-dump-default-init.cpp
clang/test/Analysis/lifetime-extended-regions.cpp
clang/test/CXX/drs/cwg16xx.cpp
clang/test/CXX/drs/cwg18xx.cpp
clang/test/CXX/special/class.temporary/p6.cpp
clang/test/SemaCXX/constexpr-default-arg.cpp
clang/test/SemaCXX/eval-crashes.cpp
clang/www/cxx_dr_status.html
Removed:
################################################################################
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index e648b503ac034..3be9d34b36b06 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10037,6 +10037,12 @@ def warn_new_dangling_initializer_list : Warning<
"the allocated initializer list}0 "
"will be destroyed at the end of the full-expression">,
InGroup<DanglingInitializerList>;
+def warn_unsupported_lifetime_extension : Warning<
+ "lifetime extension of "
+ "%select{temporary|backing array of initializer list}0 created "
+ "by aggregate initialization using a default member initializer "
+ "is not yet supported; lifetime of %select{temporary|backing array}0 "
+ "will end at the end of the full-expression">, InGroup<Dangling>;
// For non-floating point, expressions of the form x == x or x != x
// should result in a warning, since these always evaluate to a constant.
diff --git a/clang/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 151cda5d68b01..274e1fb183534 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -5618,9 +5618,10 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
Res = Immediate.TransformInitializer(Param->getInit(),
/*NotCopy=*/false);
});
- if (Res.isUsable())
- Res = ConvertParamDefaultArgument(Param, Res.get(),
- Res.get()->getBeginLoc());
+ if (Res.isInvalid())
+ return ExprError();
+ Res = ConvertParamDefaultArgument(Param, Res.get(),
+ Res.get()->getBeginLoc());
if (Res.isInvalid())
return ExprError();
Init = Res.get();
@@ -5656,7 +5657,7 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
Expr *Init = nullptr;
bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer();
- bool InLifetimeExtendingContext = isInLifetimeExtendingContext();
+
EnterExpressionEvaluationContext EvalContext(
*this, ExpressionEvaluationContext::PotentiallyEvaluated, Field);
@@ -5691,35 +5692,19 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
ImmediateCallVisitor V(getASTContext());
if (!NestedDefaultChecking)
V.TraverseDecl(Field);
-
- // 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) {
+ if (V.HasImmediateCalls) {
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);
runWithSufficientStackSpace(Loc, [&] {
Res = Immediate.TransformInitializer(Field->getInClassInitializer(),
/*CXXDirectInit=*/false);
});
- if (Res.isUsable())
+ if (!Res.isInvalid())
Res = ConvertMemberDefaultInitExpression(Field, Res.get(), Loc);
if (Res.isInvalid()) {
Field->setInvalidDecl();
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 708286e192f9c..2177972f3af2c 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -8066,6 +8066,11 @@ static void visitLocalsRetainedByInitializer(IndirectLocalPath &Path,
enum PathLifetimeKind {
/// Lifetime-extend along this path.
Extend,
+ /// We should lifetime-extend, but we don't because (due to technical
+ /// limitations) we can't. This happens for default member initializers,
+ /// which we don't clone for every use, so we don't have a unique
+ /// MaterializeTemporaryExpr to update.
+ ShouldExtend,
/// Do not lifetime extend along this path.
NoExtend
};
@@ -8077,7 +8082,7 @@ shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) {
PathLifetimeKind Kind = PathLifetimeKind::Extend;
for (auto Elem : Path) {
if (Elem.Kind == IndirectLocalPathEntry::DefaultInit)
- Kind = PathLifetimeKind::Extend;
+ Kind = PathLifetimeKind::ShouldExtend;
else if (Elem.Kind != IndirectLocalPathEntry::LambdaCaptureInit)
return PathLifetimeKind::NoExtend;
}
@@ -8197,6 +8202,18 @@ void Sema::checkInitializerLifetime(const InitializedEntity &Entity,
ExtendingEntity->allocateManglingNumber());
// Also visit the temporaries lifetime-extended by this initializer.
return true;
+
+ case PathLifetimeKind::ShouldExtend:
+ // We're supposed to lifetime-extend the temporary along this path (per
+ // the resolution of DR1815), but we don't support that yet.
+ //
+ // FIXME: Properly handle this situation. Perhaps the easiest approach
+ // would be to clone the initializer expression on each use that would
+ // lifetime extend its temporaries.
+ Diag(DiagLoc, diag::warn_unsupported_lifetime_extension)
+ << RK << DiagRange;
+ break;
+
case PathLifetimeKind::NoExtend:
// If the path goes through the initialization of a variable or field,
// it can't possibly reach a temporary created in this full-expression.
diff --git a/clang/test/AST/ast-dump-default-init-json.cpp b/clang/test/AST/ast-dump-default-init-json.cpp
index f4949a9c9eedf..1058b4e3ea4d9 100644
--- a/clang/test/AST/ast-dump-default-init-json.cpp
+++ b/clang/test/AST/ast-dump-default-init-json.cpp
@@ -789,10 +789,10 @@ void test() {
// CHECK-NEXT: "valueCategory": "lvalue",
// CHECK-NEXT: "extendingDecl": {
// CHECK-NEXT: "id": "0x{{.*}}",
-// CHECK-NEXT: "kind": "VarDecl",
-// CHECK-NEXT: "name": "b",
+// CHECK-NEXT: "kind": "FieldDecl",
+// CHECK-NEXT: "name": "a",
// CHECK-NEXT: "type": {
-// CHECK-NEXT: "qualType": "B"
+// CHECK-NEXT: "qualType": "const A &"
// CHECK-NEXT: }
// CHECK-NEXT: },
// CHECK-NEXT: "storageDuration": "automatic",
diff --git a/clang/test/AST/ast-dump-default-init.cpp b/clang/test/AST/ast-dump-default-init.cpp
index 26864fbf15424..15b29f04bf21b 100644
--- a/clang/test/AST/ast-dump-default-init.cpp
+++ b/clang/test/AST/ast-dump-default-init.cpp
@@ -13,7 +13,7 @@ void test() {
}
// CHECK: -CXXDefaultInitExpr 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue has rewritten init
// CHECK-NEXT: `-ExprWithCleanups 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue
-// CHECK-NEXT: `-MaterializeTemporaryExpr 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue extended by Var 0x{{[^ ]*}} 'b' 'B'
+// CHECK-NEXT: `-MaterializeTemporaryExpr 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue extended by Field 0x{{[^ ]*}} 'a' 'const A &'
// CHECK-NEXT: `-ImplicitCastExpr 0x{{[^ ]*}} <{{.*}}> 'const A' <NoOp>
// CHECK-NEXT: `-CXXFunctionalCastExpr 0x{{[^ ]*}} <{{.*}}> 'A' functional cast to A <NoOp>
// CHECK-NEXT: `-InitListExpr 0x{{[^ ]*}} <{{.*}}> 'A'
diff --git a/clang/test/Analysis/lifetime-extended-regions.cpp b/clang/test/Analysis/lifetime-extended-regions.cpp
index 4458ad294af7c..4e98bd4b0403e 100644
--- a/clang/test/Analysis/lifetime-extended-regions.cpp
+++ b/clang/test/Analysis/lifetime-extended-regions.cpp
@@ -120,11 +120,10 @@ void aggregateWithReferences() {
clang_analyzer_dump(viaReference); // expected-warning-re {{&lifetime_extended_object{RefAggregate, viaReference, S{{[0-9]+}}} }}
clang_analyzer_dump(viaReference.rx); // expected-warning-re {{&lifetime_extended_object{int, viaReference, S{{[0-9]+}}} }}
clang_analyzer_dump(viaReference.ry); // expected-warning-re {{&lifetime_extended_object{Composite, viaReference, S{{[0-9]+}}} }}
-
- // FIXME: clang currently support extending lifetime of object bound to reference members of aggregates,
- // that are created from default member initializer. But CFG and ExprEngine need to be updated to address this change.
- // The following expect warning: {{&lifetime_extended_object{Composite, defaultInitExtended, S{{[0-9]+}}} }}
- RefAggregate defaultInitExtended{i};
+
+ // clang does not currently implement extending lifetime of object bound to reference members of aggregates,
+ // that are created from default member initializer (see `warn_unsupported_lifetime_extension` from `-Wdangling`)
+ RefAggregate defaultInitExtended{i}; // clang-bug does not extend `Composite`
clang_analyzer_dump(defaultInitExtended.ry); // expected-warning {{Unknown }}
}
diff --git a/clang/test/CXX/drs/cwg16xx.cpp b/clang/test/CXX/drs/cwg16xx.cpp
index 82ef871939d2c..cf6b45ceabf2c 100644
--- a/clang/test/CXX/drs/cwg16xx.cpp
+++ b/clang/test/CXX/drs/cwg16xx.cpp
@@ -483,6 +483,8 @@ namespace cwg1696 { // cwg1696: 7
const A &a = A(); // #cwg1696-D1-a
};
D1 d1 = {}; // #cwg1696-d1
+ // since-cxx14-warning at -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}}
+ // since-cxx14-note@#cwg1696-D1-a {{initializing field 'a' with default member initializer}}
struct D2 {
const A &a = A(); // #cwg1696-D2-a
diff --git a/clang/test/CXX/drs/cwg18xx.cpp b/clang/test/CXX/drs/cwg18xx.cpp
index 89adc28384904..35615076a6288 100644
--- a/clang/test/CXX/drs/cwg18xx.cpp
+++ b/clang/test/CXX/drs/cwg18xx.cpp
@@ -56,7 +56,7 @@ namespace cwg1804 { // cwg1804: 2.7
template <typename, typename>
struct A {
void f1();
-
+
template <typename V>
void f2(V);
@@ -73,7 +73,7 @@ struct A {
template <typename U>
struct A<int, U> {
void f1();
-
+
template <typename V>
void f2(V);
@@ -97,7 +97,7 @@ class D {
template <typename U>
struct A<double, U> {
void f1();
-
+
template <typename V>
void f2(V);
@@ -206,28 +206,19 @@ namespace cwg1814 { // cwg1814: yes
#endif
}
-namespace cwg1815 { // cwg1815: 19
+namespace cwg1815 { // cwg1815: no
#if __cplusplus >= 201402L
- struct A { int &&r = 0; };
+ // FIXME: needs codegen test
+ struct A { int &&r = 0; }; // #cwg1815-A
A a = {};
+ // since-cxx14-warning at -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
+ // since-cxx14-note@#cwg1815-A {{initializing field 'r' with default member initializer}}
struct B { int &&r = 0; }; // #cwg1815-B
// since-cxx14-error at -1 {{reference member 'r' binds to a temporary object whose lifetime would be shorter than the lifetime of the constructed object}}
// since-cxx14-note@#cwg1815-B {{initializing field 'r' with default member initializer}}
// since-cxx14-note@#cwg1815-b {{in implicit default constructor for 'cwg1815::B' first required here}}
B b; // #cwg1815-b
-
-#if __cplusplus >= 201703L
- struct C { const int &r = 0; };
- constexpr C c = {}; // OK, since cwg1815
- static_assert(c.r == 0);
-
- constexpr int f() {
- A a = {}; // OK, since cwg1815
- return a.r;
- }
- static_assert(f() == 0);
-#endif
#endif
}
diff --git a/clang/test/CXX/special/class.temporary/p6.cpp b/clang/test/CXX/special/class.temporary/p6.cpp
index a6d2adfd1fd2c..5554363cc69ab 100644
--- a/clang/test/CXX/special/class.temporary/p6.cpp
+++ b/clang/test/CXX/special/class.temporary/p6.cpp
@@ -269,40 +269,6 @@ void init_capture_init_list() {
// CHECK: }
}
-void check_dr1815() { // dr1815: yes
-#if __cplusplus >= 201402L
-
- struct A {
- int &&r = 0;
- ~A() {}
- };
-
- struct B {
- A &&a = A{};
- ~B() {}
- };
- B a = {};
-
- // CHECK: call {{.*}}block_scope_begin_function
- extern void block_scope_begin_function();
- extern void block_scope_end_function();
- block_scope_begin_function();
- {
- // CHECK: call void @_ZZ12check_dr1815vEN1BD1Ev
- // CHECK: call void @_ZZ12check_dr1815vEN1AD1Ev
- B b = {};
- }
- // CHECK: call {{.*}}block_scope_end_function
- block_scope_end_function();
-
- // CHECK: call {{.*}}some_other_function
- extern void some_other_function();
- some_other_function();
- // CHECK: call void @_ZZ12check_dr1815vEN1BD1Ev
- // CHECK: call void @_ZZ12check_dr1815vEN1AD1Ev
-#endif
-}
-
namespace P2718R0 {
namespace basic {
template <typename E> using T2 = std::list<E>;
diff --git a/clang/test/SemaCXX/constexpr-default-arg.cpp b/clang/test/SemaCXX/constexpr-default-arg.cpp
index 901123bfb359f..ec9b2927880bd 100644
--- a/clang/test/SemaCXX/constexpr-default-arg.cpp
+++ b/clang/test/SemaCXX/constexpr-default-arg.cpp
@@ -32,8 +32,8 @@ void test_default_arg2() {
}
// Check that multiple CXXDefaultInitExprs don't cause an assertion failure.
-struct A { int &&r = 0; };
+struct A { int &&r = 0; }; // expected-note 2{{default member initializer}}
struct B { A x, y; };
-B b = {}; // expected-no-diagnostics
+B b = {}; // expected-warning 2{{lifetime extension of temporary created by aggregate initialization using a default member initializer is not yet supported}}
}
diff --git a/clang/test/SemaCXX/eval-crashes.cpp b/clang/test/SemaCXX/eval-crashes.cpp
index a06f60f71e9c7..017df977b26b7 100644
--- a/clang/test/SemaCXX/eval-crashes.cpp
+++ b/clang/test/SemaCXX/eval-crashes.cpp
@@ -25,9 +25,11 @@ namespace pr33140_0b {
}
namespace pr33140_2 {
- struct A { int &&r = 0; };
+ // FIXME: The declaration of 'b' below should lifetime-extend two int
+ // temporaries.
+ struct A { int &&r = 0; }; // expected-note 2{{initializing field 'r' with default member initializer}}
struct B { A x, y; };
- B b = {};
+ B b = {}; // expected-warning 2{{lifetime extension of temporary created by aggregate initialization using a default member initializer is not yet supported}}
}
namespace pr33140_3 {
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index abf5d4ae4676d..2ed79fa21db26 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -10698,7 +10698,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/1815.html">1815</a></td>
<td>CD4</td>
<td>Lifetime extension in aggregate initialization</td>
- <td class="unreleased" align="center">Clang 19</td>
+ <td class="none" align="center">No</td>
</tr>
<tr id="1816">
<td><a href="https://cplusplus.github.io/CWG/issues/1816.html">1816</a></td>
More information about the cfe-commits
mailing list