@@ -45,10 +45,14 @@ enum LifetimeKind {
45
45
// / a default member initializer), the program is ill-formed.
46
46
LK_MemInitializer,
47
47
48
- // / The lifetime of a temporary bound to this entity probably ends too soon,
48
+ // / The lifetime of a temporary bound to this entity may end too soon,
49
49
// / because the entity is a pointer and we assign the address of a temporary
50
50
// / object to it.
51
51
LK_Assignment,
52
+
53
+ // / The lifetime of a temporary bound to this entity may end too soon,
54
+ // / because the entity may capture the reference to a temporary object.
55
+ LK_LifetimeCapture,
52
56
};
53
57
using LifetimeResult =
54
58
llvm::PointerIntPair<const InitializedEntity *, 3 , LifetimeKind>;
@@ -193,6 +197,7 @@ struct IndirectLocalPathEntry {
193
197
VarInit,
194
198
LValToRVal,
195
199
LifetimeBoundCall,
200
+ LifetimeCapture,
196
201
TemporaryCopy,
197
202
LambdaCaptureInit,
198
203
GslReferenceInit,
@@ -249,9 +254,10 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
249
254
LocalVisitor Visit);
250
255
251
256
template <typename T> static bool isRecordWithAttr (QualType Type) {
252
- if (auto *RD = Type->getAsCXXRecordDecl ())
253
- return RD->hasAttr <T>();
254
- return false ;
257
+ CXXRecordDecl *RD = Type.getNonReferenceType ()->getAsCXXRecordDecl ();
258
+ if (!RD)
259
+ return false ;
260
+ return RD->hasAttr <T>();
255
261
}
256
262
257
263
// Decl::isInStdNamespace will return false for iterators in some STL
@@ -1049,6 +1055,7 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
1049
1055
case IndirectLocalPathEntry::AddressOf:
1050
1056
case IndirectLocalPathEntry::LValToRVal:
1051
1057
case IndirectLocalPathEntry::LifetimeBoundCall:
1058
+ case IndirectLocalPathEntry::LifetimeCapture:
1052
1059
case IndirectLocalPathEntry::TemporaryCopy:
1053
1060
case IndirectLocalPathEntry::GslReferenceInit:
1054
1061
case IndirectLocalPathEntry::GslPointerInit:
@@ -1082,6 +1089,7 @@ static bool pathOnlyHandlesGslPointer(const IndirectLocalPath &Path) {
1082
1089
case IndirectLocalPathEntry::VarInit:
1083
1090
case IndirectLocalPathEntry::AddressOf:
1084
1091
case IndirectLocalPathEntry::LifetimeBoundCall:
1092
+ case IndirectLocalPathEntry::LifetimeCapture:
1085
1093
continue ;
1086
1094
case IndirectLocalPathEntry::GslPointerInit:
1087
1095
case IndirectLocalPathEntry::GslReferenceInit:
@@ -1110,12 +1118,13 @@ static bool shouldRunGSLAssignmentAnalysis(const Sema &SemaRef,
1110
1118
isAssignmentOperatorLifetimeBound (Entity.AssignmentOperator )));
1111
1119
}
1112
1120
1113
- static void checkExprLifetimeImpl (Sema &SemaRef,
1114
- const InitializedEntity *InitEntity,
1115
- const InitializedEntity *ExtendingEntity,
1116
- LifetimeKind LK ,
1117
- const AssignedEntity *AEntity , Expr *Init) {
1121
+ static void
1122
+ checkExprLifetimeImpl (Sema &SemaRef, const InitializedEntity *InitEntity,
1123
+ const InitializedEntity *ExtendingEntity, LifetimeKind LK ,
1124
+ const AssignedEntity *AEntity ,
1125
+ const CapturingEntity *CapEntity , Expr *Init) {
1118
1126
assert ((AEntity && LK == LK_Assignment) ||
1127
+ (CapEntity && LK == LK_LifetimeCapture) ||
1119
1128
(InitEntity && LK != LK_Assignment));
1120
1129
// If this entity doesn't have an interesting lifetime, don't bother looking
1121
1130
// for temporaries within its initializer.
@@ -1199,6 +1208,17 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
1199
1208
break ;
1200
1209
}
1201
1210
1211
+ case LK_LifetimeCapture: {
1212
+ if (!MTE)
1213
+ return false ;
1214
+ assert (shouldLifetimeExtendThroughPath (Path) ==
1215
+ PathLifetimeKind::NoExtend &&
1216
+ " No lifetime extension in function calls" );
1217
+ SemaRef.Diag (DiagLoc, diag::warn_dangling_reference_captured)
1218
+ << CapEntity->Entity << DiagRange;
1219
+ return false ;
1220
+ }
1221
+
1202
1222
case LK_Assignment: {
1203
1223
if (!MTE || pathContainsInit (Path))
1204
1224
return false ;
@@ -1359,6 +1379,7 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
1359
1379
break ;
1360
1380
1361
1381
case IndirectLocalPathEntry::LifetimeBoundCall:
1382
+ case IndirectLocalPathEntry::LifetimeCapture:
1362
1383
case IndirectLocalPathEntry::TemporaryCopy:
1363
1384
case IndirectLocalPathEntry::GslPointerInit:
1364
1385
case IndirectLocalPathEntry::GslReferenceInit:
@@ -1411,7 +1432,7 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
1411
1432
// warnings or errors on inner temporaries within this one's initializer.
1412
1433
return false ;
1413
1434
};
1414
-
1435
+ bool HasReferenceBinding = Init-> isGLValue ();
1415
1436
llvm::SmallVector<IndirectLocalPathEntry, 8 > Path;
1416
1437
if (LK == LK_Assignment &&
1417
1438
shouldRunGSLAssignmentAnalysis (SemaRef, *AEntity)) {
@@ -1420,9 +1441,18 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
1420
1441
? IndirectLocalPathEntry::LifetimeBoundCall
1421
1442
: IndirectLocalPathEntry::GslPointerAssignment,
1422
1443
Init});
1444
+ } else if (LK == LK_LifetimeCapture) {
1445
+ Path.push_back ({IndirectLocalPathEntry::LifetimeCapture, Init});
1446
+ if (isRecordWithAttr<PointerAttr>(Init->getType ()))
1447
+ HasReferenceBinding = false ;
1448
+ // Skip the top MTE if it is a temporary object of the pointer-like type
1449
+ // itself.
1450
+ if (auto *MTE = dyn_cast<MaterializeTemporaryExpr>(Init);
1451
+ MTE && isPointerLikeType (Init->getType ()))
1452
+ Init = MTE->getSubExpr ();
1423
1453
}
1424
1454
1425
- if (Init-> isGLValue () )
1455
+ if (HasReferenceBinding )
1426
1456
visitLocalsRetainedByReferenceBinding (Path, Init, RK_ReferenceBinding,
1427
1457
TemporaryVisitor);
1428
1458
else
@@ -1438,13 +1468,13 @@ void checkExprLifetime(Sema &SemaRef, const InitializedEntity &Entity,
1438
1468
LifetimeKind LK = LTResult.getInt ();
1439
1469
const InitializedEntity *ExtendingEntity = LTResult.getPointer ();
1440
1470
checkExprLifetimeImpl (SemaRef, &Entity, ExtendingEntity, LK,
1441
- /* AEntity*/ nullptr , Init);
1471
+ /* AEntity*/ nullptr , /* CapEntity= */ nullptr , Init);
1442
1472
}
1443
1473
1444
1474
void checkExprLifetimeMustTailArg (Sema &SemaRef,
1445
1475
const InitializedEntity &Entity, Expr *Init) {
1446
1476
checkExprLifetimeImpl (SemaRef, &Entity, nullptr , LK_MustTail,
1447
- /* AEntity*/ nullptr , Init);
1477
+ /* AEntity*/ nullptr , /* CapEntity= */ nullptr , Init);
1448
1478
}
1449
1479
1450
1480
void checkExprLifetime (Sema &SemaRef, const AssignedEntity &Entity,
@@ -1460,7 +1490,15 @@ void checkExprLifetime(Sema &SemaRef, const AssignedEntity &Entity,
1460
1490
1461
1491
checkExprLifetimeImpl (SemaRef, /* InitEntity=*/ nullptr ,
1462
1492
/* ExtendingEntity=*/ nullptr , LK_Assignment, &Entity,
1463
- Init);
1493
+ /* CapEntity=*/ nullptr , Init);
1494
+ }
1495
+
1496
+ void checkExprLifetime (Sema &SemaRef, const CapturingEntity &Entity,
1497
+ Expr *Init) {
1498
+ return checkExprLifetimeImpl (SemaRef, /* InitEntity=*/ nullptr ,
1499
+ /* ExtendingEntity=*/ nullptr , LK_LifetimeCapture,
1500
+ /* AEntity=*/ nullptr ,
1501
+ /* CapEntity=*/ &Entity, Init);
1464
1502
}
1465
1503
1466
1504
} // namespace clang::sema
0 commit comments