[clang] Reapply "[Clang][CWG1815] Support lifetime extension of temporary created by aggregate initialization using a default member initializer" (PR #108039)
via cfe-commits
cfe-commits at lists.llvm.org
Tue Sep 10 07:57:08 PDT 2024
llvmbot wrote:
<!--LLVM PR SUMMARY COMMENT-->
@llvm/pr-subscribers-clang
Author: None (yronglin)
<details>
<summary>Changes</summary>
The PR reapply https://github.com/llvm/llvm-project/pull/97308.
Implement [CWG1815](https://wg21.link/CWG1815): Support lifetime extension of temporary created by aggregate initialization using a default member initializer.
Fix crash that introduced in https://github.com/llvm/llvm-project/pull/97308. In `InitListChecker::FillInEmptyInitForField`, when we enter rebuild-default-init context, we copy all the contents of the parent context to the current context, which will cause the `MaybeODRUseExprs` to be lost. But we don't need to copy the entire context, only the `DelayedDefaultInitializationContext` was required, which is used to build `SourceLocExpr`, etc.
---
Patch is 29.68 KiB, truncated to 20.00 KiB below, full version: https://github.com/llvm/llvm-project/pull/108039.diff
21 Files Affected:
- (modified) clang/docs/ReleaseNotes.rst (+3)
- (modified) clang/include/clang/Basic/DiagnosticSemaKinds.td (-7)
- (modified) clang/include/clang/Sema/Sema.h (+8-15)
- (modified) clang/lib/Parse/ParseDecl.cpp (+2-1)
- (modified) clang/lib/Sema/CheckExprLifetime.cpp (+1-17)
- (modified) clang/lib/Sema/SemaExpr.cpp (+27-9)
- (modified) clang/lib/Sema/SemaExprCXX.cpp (-3)
- (modified) clang/lib/Sema/SemaInit.cpp (+17-6)
- (modified) clang/lib/Sema/SemaTemplateInstantiateDecl.cpp (+4-1)
- (modified) clang/lib/Sema/TreeTransform.h (+14-6)
- (modified) clang/test/AST/ast-dump-default-init-json.cpp (+3-3)
- (modified) clang/test/AST/ast-dump-default-init.cpp (+1-1)
- (modified) clang/test/Analysis/lifetime-extended-regions.cpp (+5-4)
- (modified) clang/test/CXX/drs/cwg16xx.cpp (+21-2)
- (modified) clang/test/CXX/drs/cwg18xx.cpp (+14-5)
- (modified) clang/test/CXX/special/class.temporary/p6.cpp (+34)
- (added) clang/test/SemaCXX/PR97308.cpp (+21)
- (modified) clang/test/SemaCXX/constexpr-default-arg.cpp (+2-2)
- (modified) clang/test/SemaCXX/cxx11-default-member-initializers.cpp (+97)
- (modified) clang/test/SemaCXX/eval-crashes.cpp (+2-4)
- (modified) clang/www/cxx_dr_status.html (+1-1)
``````````diff
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 250821a9f9c45c..07f3544e2324e3 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -108,6 +108,9 @@ C++ Language Changes
- Allow single element access of GCC vector/ext_vector_type object to be
constant expression. Supports the `V.xyzw` syntax and other tidbits
as seen in OpenCL. Selecting multiple elements is left as a future work.
+- Implement `CWG1815 <https://wg21.link/CWG1815>`_. Support lifetime extension
+ of temporary created by aggregate initialization using a default member
+ initializer.
- Accept C++26 user-defined ``static_assert`` messages in C++11 as an extension.
diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td
index 58819a64813fce..4609d2ec2b7209 100644
--- a/clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -10159,13 +10159,6 @@ def warn_dangling_pointer_assignment : Warning<
"will be destroyed at the end of the full-expression">,
InGroup<DanglingAssignment>;
-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.
// Array comparisons have similar warnings
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 68c782a15c6f1b..ac4c11964b126f 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -6403,6 +6403,9 @@ class Sema final : public SemaBase {
/// example, in a for-range initializer).
bool InLifetimeExtendingContext = false;
+ /// Whether we should rebuild CXXDefaultArgExpr and CXXDefaultInitExpr.
+ bool RebuildDefaultArgOrDefaultInit = false;
+
// When evaluating immediate functions in the initializer of a default
// argument or default member initializer, this is the declaration whose
// default initializer is being evaluated and the location of the call
@@ -7810,9 +7813,11 @@ class Sema final : public SemaBase {
}
bool isInLifetimeExtendingContext() const {
- assert(!ExprEvalContexts.empty() &&
- "Must be in an expression evaluation context");
- return ExprEvalContexts.back().InLifetimeExtendingContext;
+ return currentEvaluationContext().InLifetimeExtendingContext;
+ }
+
+ bool needRebuildDefaultArgOrInit() const {
+ return currentEvaluationContext().RebuildDefaultArgOrDefaultInit;
}
bool isCheckingDefaultArgumentOrInitializer() const {
@@ -7854,18 +7859,6 @@ class Sema final : public SemaBase {
return Res;
}
- /// keepInLifetimeExtendingContext - Pull down InLifetimeExtendingContext
- /// flag from previous context.
- void keepInLifetimeExtendingContext() {
- if (ExprEvalContexts.size() > 2 &&
- parentEvaluationContext().InLifetimeExtendingContext) {
- auto &LastRecord = ExprEvalContexts.back();
- auto &PrevRecord = parentEvaluationContext();
- LastRecord.InLifetimeExtendingContext =
- PrevRecord.InLifetimeExtendingContext;
- }
- }
-
DefaultedComparisonKind getDefaultedComparisonKind(const FunctionDecl *FD) {
return getDefaultedFunctionKind(FD).asComparison();
}
diff --git a/clang/lib/Parse/ParseDecl.cpp b/clang/lib/Parse/ParseDecl.cpp
index 61a1ca3da6bca0..1f56884be392d6 100644
--- a/clang/lib/Parse/ParseDecl.cpp
+++ b/clang/lib/Parse/ParseDecl.cpp
@@ -2509,8 +2509,9 @@ Parser::DeclGroupPtrTy Parser::ParseDeclGroup(ParsingDeclSpec &DS,
// P2718R0 - Lifetime extension in range-based for loops.
if (getLangOpts().CPlusPlus23) {
- auto &LastRecord = Actions.ExprEvalContexts.back();
+ auto &LastRecord = Actions.currentEvaluationContext();
LastRecord.InLifetimeExtendingContext = true;
+ LastRecord.RebuildDefaultArgOrDefaultInit = true;
}
if (getLangOpts().OpenMP)
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index f1507ebb9a5068..f62e18543851c1 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -871,11 +871,6 @@ 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
};
@@ -887,7 +882,7 @@ shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) {
PathLifetimeKind Kind = PathLifetimeKind::Extend;
for (auto Elem : Path) {
if (Elem.Kind == IndirectLocalPathEntry::DefaultInit)
- Kind = PathLifetimeKind::ShouldExtend;
+ return PathLifetimeKind::Extend;
else if (Elem.Kind != IndirectLocalPathEntry::LambdaCaptureInit)
return PathLifetimeKind::NoExtend;
}
@@ -1034,17 +1029,6 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
// 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.
- SemaRef.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/lib/Sema/SemaExpr.cpp b/clang/lib/Sema/SemaExpr.cpp
index 32dac4440fb82a..30e5fe4543bcaa 100644
--- a/clang/lib/Sema/SemaExpr.cpp
+++ b/clang/lib/Sema/SemaExpr.cpp
@@ -5429,6 +5429,8 @@ struct EnsureImmediateInvocationInDefaultArgs
EnsureImmediateInvocationInDefaultArgs(Sema &SemaRef)
: TreeTransform(SemaRef) {}
+ bool AlwaysRebuild() { return true; }
+
// Lambda can only have immediate invocations in the default
// args of their parameters, which is transformed upon calling the closure.
// The body is not a subexpression, so we have nothing to do.
@@ -5470,7 +5472,7 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
assert(Param->hasDefaultArg() && "can't build nonexistent default arg");
bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer();
- bool InLifetimeExtendingContext = isInLifetimeExtendingContext();
+ bool NeedRebuild = needRebuildDefaultArgOrInit();
std::optional<ExpressionEvaluationContextRecord::InitializationContext>
InitializationContext =
OutermostDeclarationWithDelayedImmediateInvocations();
@@ -5506,13 +5508,15 @@ ExprResult Sema::BuildCXXDefaultArgExpr(SourceLocation CallLoc,
// Rewrite the call argument that was created from the corresponding
// parameter's default argument.
- if (V.HasImmediateCalls || InLifetimeExtendingContext) {
+ if (V.HasImmediateCalls ||
+ (NeedRebuild && isa_and_present<ExprWithCleanups>(Param->getInit()))) {
if (V.HasImmediateCalls)
ExprEvalContexts.back().DelayedDefaultInitializationContext = {
CallLoc, Param, CurContext};
// Pass down lifetime extending flag, and collect temporaries in
// CreateMaterializeTemporaryExpr when we rewrite the call argument.
- keepInLifetimeExtendingContext();
+ currentEvaluationContext().InLifetimeExtendingContext =
+ parentEvaluationContext().InLifetimeExtendingContext;
EnsureImmediateInvocationInDefaultArgs Immediate(*this);
ExprResult Res;
runWithSufficientStackSpace(CallLoc, [&] {
@@ -5558,7 +5562,7 @@ ExprResult Sema::BuildCXXDefaultInitExpr(SourceLocation Loc, FieldDecl *Field) {
Expr *Init = nullptr;
bool NestedDefaultChecking = isCheckingDefaultArgumentOrInitializer();
-
+ bool NeedRebuild = needRebuildDefaultArgOrInit();
EnterExpressionEvaluationContext EvalContext(
*this, ExpressionEvaluationContext::PotentiallyEvaluated, Field);
@@ -5593,12 +5597,27 @@ 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 rebuild
+ // the initializer in a lifetime extension context 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 (Field->getInClassInitializer() &&
+ !Field->getInClassInitializer()->containsErrors() &&
+ (V.HasImmediateCalls || (NeedRebuild && 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.
+ currentEvaluationContext().InLifetimeExtendingContext =
+ parentEvaluationContext().InLifetimeExtendingContext;
EnsureImmediateInvocationInDefaultArgs Immediate(*this);
ExprResult Res;
runWithSufficientStackSpace(Loc, [&] {
@@ -17675,11 +17694,10 @@ void Sema::PopExpressionEvaluationContext() {
// Append the collected materialized temporaries into previous context before
// exit if the previous also is a lifetime extending context.
- auto &PrevRecord = parentEvaluationContext();
if (getLangOpts().CPlusPlus23 && Rec.InLifetimeExtendingContext &&
- PrevRecord.InLifetimeExtendingContext &&
+ parentEvaluationContext().InLifetimeExtendingContext &&
!Rec.ForRangeLifetimeExtendTemps.empty()) {
- PrevRecord.ForRangeLifetimeExtendTemps.append(
+ parentEvaluationContext().ForRangeLifetimeExtendTemps.append(
Rec.ForRangeLifetimeExtendTemps);
}
diff --git a/clang/lib/Sema/SemaExprCXX.cpp b/clang/lib/Sema/SemaExprCXX.cpp
index 14feafd1e6b17f..e086c601107041 100644
--- a/clang/lib/Sema/SemaExprCXX.cpp
+++ b/clang/lib/Sema/SemaExprCXX.cpp
@@ -1540,9 +1540,6 @@ Sema::BuildCXXTypeConstructExpr(TypeSourceInfo *TInfo,
bool ListInitialization) {
QualType Ty = TInfo->getType();
SourceLocation TyBeginLoc = TInfo->getTypeLoc().getBeginLoc();
-
- assert((!ListInitialization || Exprs.size() == 1) &&
- "List initialization must have exactly one expression.");
SourceRange FullRange = SourceRange(TyBeginLoc, RParenOrBraceLoc);
InitializedEntity Entity =
diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp
index 7dc17187524621..d21b8cb8c04e63 100644
--- a/clang/lib/Sema/SemaInit.cpp
+++ b/clang/lib/Sema/SemaInit.cpp
@@ -750,8 +750,21 @@ void InitListChecker::FillInEmptyInitForField(unsigned Init, FieldDecl *Field,
if (Field->hasInClassInitializer()) {
if (VerifyOnly)
return;
-
- ExprResult DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field);
+ ExprResult DIE;
+ {
+ // Enter a default initializer rebuild context, then we can support
+ // lifetime extension of temporary created by aggregate initialization
+ // using a default member initializer.
+ // CWG1815 (https://wg21.link/CWG1815).
+ EnterExpressionEvaluationContext RebuildDefaultInit(
+ SemaRef, Sema::ExpressionEvaluationContext::PotentiallyEvaluated);
+ SemaRef.currentEvaluationContext().RebuildDefaultArgOrDefaultInit =
+ true;
+ SemaRef.currentEvaluationContext().DelayedDefaultInitializationContext =
+ SemaRef.parentEvaluationContext()
+ .DelayedDefaultInitializationContext;
+ DIE = SemaRef.BuildCXXDefaultInitExpr(Loc, Field);
+ }
if (DIE.isInvalid()) {
hadError = true;
return;
@@ -7521,10 +7534,8 @@ Sema::CreateMaterializeTemporaryExpr(QualType T, Expr *Temporary,
// are done in both CreateMaterializeTemporaryExpr and MaybeBindToTemporary,
// but there may be a chance to merge them.
Cleanup.setExprNeedsCleanups(false);
- if (isInLifetimeExtendingContext()) {
- auto &Record = ExprEvalContexts.back();
- Record.ForRangeLifetimeExtendTemps.push_back(MTE);
- }
+ if (isInLifetimeExtendingContext())
+ currentEvaluationContext().ForRangeLifetimeExtendTemps.push_back(MTE);
return MTE;
}
diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
index 6df412cbb09c83..bb311e38409280 100644
--- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -5481,7 +5481,10 @@ void Sema::InstantiateVariableInitializer(
EnterExpressionEvaluationContext Evaluated(
*this, Sema::ExpressionEvaluationContext::PotentiallyEvaluated, Var);
- keepInLifetimeExtendingContext();
+ currentEvaluationContext().InLifetimeExtendingContext =
+ parentEvaluationContext().InLifetimeExtendingContext;
+ currentEvaluationContext().RebuildDefaultArgOrDefaultInit =
+ parentEvaluationContext().RebuildDefaultArgOrDefaultInit;
// Instantiate the initializer.
ExprResult Init;
diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h
index 0daf620b4123e4..4bbc024587915c 100644
--- a/clang/lib/Sema/TreeTransform.h
+++ b/clang/lib/Sema/TreeTransform.h
@@ -4254,7 +4254,10 @@ ExprResult TreeTransform<Derived>::TransformInitializer(Expr *Init,
getSema(), EnterExpressionEvaluationContext::InitList,
Construct->isListInitialization());
- getSema().keepInLifetimeExtendingContext();
+ getSema().currentEvaluationContext().InLifetimeExtendingContext =
+ getSema().parentEvaluationContext().InLifetimeExtendingContext;
+ getSema().currentEvaluationContext().RebuildDefaultArgOrDefaultInit =
+ getSema().parentEvaluationContext().RebuildDefaultArgOrDefaultInit;
SmallVector<Expr*, 8> NewArgs;
bool ArgChanged = false;
if (getDerived().TransformExprs(Construct->getArgs(), Construct->getNumArgs(),
@@ -8924,8 +8927,9 @@ TreeTransform<Derived>::TransformCXXForRangeStmt(CXXForRangeStmt *S) {
// P2718R0 - Lifetime extension in range-based for loops.
if (getSema().getLangOpts().CPlusPlus23) {
- auto &LastRecord = getSema().ExprEvalContexts.back();
+ auto &LastRecord = getSema().currentEvaluationContext();
LastRecord.InLifetimeExtendingContext = true;
+ LastRecord.RebuildDefaultArgOrDefaultInit = true;
}
StmtResult Init =
S->getInit() ? getDerived().TransformStmt(S->getInit()) : StmtResult();
@@ -14443,6 +14447,13 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
if (TransformExprs(E->getArgs(), E->getNumArgs(), true, Args,
&ArgumentChanged))
return ExprError();
+
+ if (E->isListInitialization() && !E->isStdInitListInitialization()) {
+ ExprResult Res = RebuildInitList(E->getBeginLoc(), Args, E->getEndLoc());
+ if (Res.isInvalid())
+ return ExprError();
+ Args = {Res.get()};
+ }
}
if (!getDerived().AlwaysRebuild() &&
@@ -14454,12 +14465,9 @@ TreeTransform<Derived>::TransformCXXTemporaryObjectExpr(
return SemaRef.MaybeBindToTemporary(E);
}
- // FIXME: We should just pass E->isListInitialization(), but we're not
- // prepared to handle list-initialization without a child InitListExpr.
SourceLocation LParenLoc = T->getTypeLoc().getEndLoc();
return getDerived().RebuildCXXTemporaryObjectExpr(
- T, LParenLoc, Args, E->getEndLoc(),
- /*ListInitialization=*/LParenLoc.isInvalid());
+ T, LParenLoc, Args, E->getEndLoc(), E->isListInitialization());
}
template<typename Derived>
diff --git a/clang/test/AST/ast-dump-default-init-json.cpp b/clang/test/AST/ast-dump-default-init-json.cpp
index 1058b4e3ea4d93..f4949a9c9eedf4 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": "FieldDecl",
-// CHECK-NEXT: "name": "a",
+// CHECK-NEXT: "kind": "VarDecl",
+// CHECK-NEXT: "name": "b",
// CHECK-NEXT: "type": {
-// CHECK-NEXT: "qualType": "const A &"
+// CHECK-NEXT: "qualType": "B"
// 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 15b29f04bf21bf..26864fbf15424d 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 Field 0x{{[^ ]*}} 'a' 'const A &'
+// CHECK-NEXT: `-MaterializeTemporaryExpr 0x{{[^ ]*}} <{{.*}}> 'const A' lvalue extended by Var 0x{{[^ ]*}} 'b' 'B'
// 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 4e98bd4b0403eb..4458ad294af7cb 100644
--- a/clang/test/Analysis/lifetime-extended-regions.cpp
+++ b/clang/test/Analysis/lifetime-extended-regions.cpp
@@ -120,10 +120,11 @@ 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]+}}} }}
-
- // 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`
+
+ // 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_analyzer_dump(defaultInitExtended.ry); // expected-warning {{Unknown }}
}
diff --git a/clang/test/CXX/drs/cwg16xx.cpp b/clang/test/CXX/drs/cwg16xx.cpp
index cf6b45ceabf2cc..95e241f0d03e9b 100644
--- a/clang/test/CXX/drs/cwg...
[truncated]
``````````
</details>
https://github.com/llvm/llvm-project/pull/108039
More information about the cfe-commits
mailing list