77// ===----------------------------------------------------------------------===//
88
99#include " CheckExprLifetime.h"
10+ #include " clang/AST/Attrs.inc"
1011#include " clang/AST/Decl.h"
12+ #include " clang/AST/DeclCXX.h"
13+ #include " clang/AST/DeclTemplate.h"
1114#include " clang/AST/Expr.h"
1215#include " clang/Basic/DiagnosticSema.h"
1316#include " clang/Sema/Initialization.h"
@@ -45,10 +48,14 @@ enum LifetimeKind {
4548 // / a default member initializer), the program is ill-formed.
4649 LK_MemInitializer,
4750
48- // / The lifetime of a temporary bound to this entity probably ends too soon,
51+ // / The lifetime of a temporary bound to this entity may end too soon,
4952 // / because the entity is a pointer and we assign the address of a temporary
5053 // / object to it.
5154 LK_Assignment,
55+
56+ // / The lifetime of a temporary bound to this entity may end too soon,
57+ // / because the entity may capture the reference to a temporary object.
58+ LK_LifetimeCapture,
5259};
5360using LifetimeResult =
5461 llvm::PointerIntPair<const InitializedEntity *, 3 , LifetimeKind>;
@@ -193,6 +200,7 @@ struct IndirectLocalPathEntry {
193200 VarInit,
194201 LValToRVal,
195202 LifetimeBoundCall,
203+ LifetimeCapture,
196204 TemporaryCopy,
197205 LambdaCaptureInit,
198206 GslReferenceInit,
@@ -249,9 +257,12 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
249257 LocalVisitor Visit);
250258
251259template <typename T> static bool isRecordWithAttr (QualType Type) {
252- if (auto *RD = Type->getAsCXXRecordDecl ())
253- return RD->hasAttr <T>();
254- return false ;
260+ CXXRecordDecl *RD = Type.getNonReferenceType ()->getAsCXXRecordDecl ();
261+ if (!RD)
262+ return false ;
263+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
264+ RD = CTSD->getSpecializedTemplate ()->getTemplatedDecl ();
265+ return RD->hasAttr <T>();
255266}
256267
257268// Decl::isInStdNamespace will return false for iterators in some STL
@@ -1049,6 +1060,7 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
10491060 case IndirectLocalPathEntry::AddressOf:
10501061 case IndirectLocalPathEntry::LValToRVal:
10511062 case IndirectLocalPathEntry::LifetimeBoundCall:
1063+ case IndirectLocalPathEntry::LifetimeCapture:
10521064 case IndirectLocalPathEntry::TemporaryCopy:
10531065 case IndirectLocalPathEntry::GslReferenceInit:
10541066 case IndirectLocalPathEntry::GslPointerInit:
@@ -1082,6 +1094,7 @@ static bool pathOnlyHandlesGslPointer(const IndirectLocalPath &Path) {
10821094 case IndirectLocalPathEntry::VarInit:
10831095 case IndirectLocalPathEntry::AddressOf:
10841096 case IndirectLocalPathEntry::LifetimeBoundCall:
1097+ case IndirectLocalPathEntry::LifetimeCapture:
10851098 continue ;
10861099 case IndirectLocalPathEntry::GslPointerInit:
10871100 case IndirectLocalPathEntry::GslReferenceInit:
@@ -1102,21 +1115,22 @@ static bool isAssignmentOperatorLifetimeBound(CXXMethodDecl *CMD) {
11021115}
11031116
11041117static bool shouldRunGSLAssignmentAnalysis (const Sema &SemaRef,
1105- const AssignedEntity &Entity) {
1118+ const CapturingEntity &Entity) {
11061119 bool EnableGSLAssignmentWarnings = !SemaRef.getDiagnostics ().isIgnored (
11071120 diag::warn_dangling_lifetime_pointer_assignment, SourceLocation ());
11081121 return (EnableGSLAssignmentWarnings &&
1109- (isRecordWithAttr<PointerAttr>(Entity.LHS ->getType ()) ||
1122+ (isRecordWithAttr<PointerAttr>(Entity.Expression ->getType ()) ||
11101123 isAssignmentOperatorLifetimeBound (Entity.AssignmentOperator )));
11111124}
11121125
11131126static void checkExprLifetimeImpl (Sema &SemaRef,
11141127 const InitializedEntity *InitEntity,
11151128 const InitializedEntity *ExtendingEntity,
11161129 LifetimeKind LK,
1117- const AssignedEntity *AEntity, Expr *Init) {
1118- assert ((AEntity && LK == LK_Assignment) ||
1119- (InitEntity && LK != LK_Assignment));
1130+ const CapturingEntity *CEntity, Expr *Init) {
1131+ assert (InitEntity || CEntity);
1132+ assert (!CEntity || LK == LK_Assignment || LK == LK_LifetimeCapture);
1133+ assert (!InitEntity || LK != LK_Assignment);
11201134 // If this entity doesn't have an interesting lifetime, don't bother looking
11211135 // for temporaries within its initializer.
11221136 if (LK == LK_FullExpression)
@@ -1199,6 +1213,17 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
11991213 break ;
12001214 }
12011215
1216+ case LK_LifetimeCapture: {
1217+ if (!MTE)
1218+ return false ;
1219+ assert (shouldLifetimeExtendThroughPath (Path) ==
1220+ PathLifetimeKind::NoExtend &&
1221+ " No lifetime extension in function calls" );
1222+ SemaRef.Diag (DiagLoc, diag::warn_dangling_reference_captured)
1223+ << CEntity->Expression << DiagRange;
1224+ return false ;
1225+ }
1226+
12021227 case LK_Assignment: {
12031228 if (!MTE || pathContainsInit (Path))
12041229 return false ;
@@ -1207,10 +1232,10 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
12071232 " No lifetime extension for assignments" );
12081233 if (IsGslPtrValueFromGslTempOwner)
12091234 SemaRef.Diag (DiagLoc, diag::warn_dangling_lifetime_pointer_assignment)
1210- << AEntity-> LHS << DiagRange;
1235+ << CEntity-> Expression << DiagRange;
12111236 else
12121237 SemaRef.Diag (DiagLoc, diag::warn_dangling_pointer_assignment)
1213- << AEntity-> LHS ->getType ()->isPointerType () << AEntity-> LHS
1238+ << CEntity-> Expression ->getType ()->isPointerType () << CEntity-> Expression
12141239 << DiagRange;
12151240 return false ;
12161241 }
@@ -1359,6 +1384,7 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
13591384 break ;
13601385
13611386 case IndirectLocalPathEntry::LifetimeBoundCall:
1387+ case IndirectLocalPathEntry::LifetimeCapture:
13621388 case IndirectLocalPathEntry::TemporaryCopy:
13631389 case IndirectLocalPathEntry::GslPointerInit:
13641390 case IndirectLocalPathEntry::GslReferenceInit:
@@ -1412,17 +1438,27 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
14121438 return false ;
14131439 };
14141440
1441+ bool HasReferenceBinding = Init->isGLValue ();
14151442 llvm::SmallVector<IndirectLocalPathEntry, 8 > Path;
14161443 if (LK == LK_Assignment &&
1417- shouldRunGSLAssignmentAnalysis (SemaRef, *AEntity )) {
1444+ shouldRunGSLAssignmentAnalysis (SemaRef, *CEntity )) {
14181445 Path.push_back (
1419- {isAssignmentOperatorLifetimeBound (AEntity ->AssignmentOperator )
1446+ {isAssignmentOperatorLifetimeBound (CEntity ->AssignmentOperator )
14201447 ? IndirectLocalPathEntry::LifetimeBoundCall
14211448 : IndirectLocalPathEntry::GslPointerAssignment,
14221449 Init});
1450+ } else if (LK == LK_LifetimeCapture) {
1451+ Path.push_back ({IndirectLocalPathEntry::LifetimeCapture, Init});
1452+ if (isRecordWithAttr<PointerAttr>(Init->getType ()))
1453+ HasReferenceBinding = false ;
1454+ // Skip the top MaterializeTemoraryExpr if it is temporary object of the
1455+ // pointer-like type itself.
1456+ if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init);
1457+ MTE && isPointerLikeType (Init->getType ()))
1458+ Init = MTE->getSubExpr ();
14231459 }
14241460
1425- if (Init-> isGLValue () )
1461+ if (HasReferenceBinding )
14261462 visitLocalsRetainedByReferenceBinding (Path, Init, RK_ReferenceBinding,
14271463 TemporaryVisitor);
14281464 else
@@ -1432,7 +1468,7 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
14321468 /* RevisitSubinits=*/ !InitEntity);
14331469}
14341470
1435- void checkExprLifetime (Sema &SemaRef, const InitializedEntity &Entity,
1471+ void checkInitLifetime (Sema &SemaRef, const InitializedEntity &Entity,
14361472 Expr *Init) {
14371473 auto LTResult = getEntityLifetime (&Entity);
14381474 LifetimeKind LK = LTResult.getInt ();
@@ -1447,20 +1483,26 @@ void checkExprLifetimeMustTailArg(Sema &SemaRef,
14471483 /* AEntity*/ nullptr , Init);
14481484}
14491485
1450- void checkExprLifetime (Sema &SemaRef, const AssignedEntity &Entity,
1451- Expr *Init ) {
1486+ void checkAssignmentLifetime (Sema &SemaRef, const CapturingEntity &Entity,
1487+ Expr *RHS ) {
14521488 bool EnableDanglingPointerAssignment = !SemaRef.getDiagnostics ().isIgnored (
14531489 diag::warn_dangling_pointer_assignment, SourceLocation ());
14541490 bool RunAnalysis = (EnableDanglingPointerAssignment &&
1455- Entity.LHS ->getType ()->isPointerType ()) ||
1491+ Entity.Expression ->getType ()->isPointerType ()) ||
14561492 shouldRunGSLAssignmentAnalysis (SemaRef, Entity);
14571493
14581494 if (!RunAnalysis)
14591495 return ;
14601496
14611497 checkExprLifetimeImpl (SemaRef, /* InitEntity=*/ nullptr ,
14621498 /* ExtendingEntity=*/ nullptr , LK_Assignment, &Entity,
1463- Init );
1499+ RHS );
14641500}
14651501
1502+ void checkCaptureLifetime (Sema &SemaRef, const CapturingEntity &Entity,
1503+ Expr *Captured) {
1504+ checkExprLifetimeImpl (SemaRef, /* InitEntity=*/ nullptr ,
1505+ /* ExtendingEntity=*/ nullptr , LK_LifetimeCapture,
1506+ &Entity, Captured);
1507+ }
14661508} // namespace clang::sema
0 commit comments