7
7
// ===----------------------------------------------------------------------===//
8
8
9
9
#include " CheckExprLifetime.h"
10
+ #include " clang/AST/Attrs.inc"
10
11
#include " clang/AST/Decl.h"
12
+ #include " clang/AST/DeclCXX.h"
13
+ #include " clang/AST/DeclTemplate.h"
11
14
#include " clang/AST/Expr.h"
12
15
#include " clang/Basic/DiagnosticSema.h"
13
16
#include " clang/Sema/Initialization.h"
@@ -45,10 +48,14 @@ enum LifetimeKind {
45
48
// / a default member initializer), the program is ill-formed.
46
49
LK_MemInitializer,
47
50
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,
49
52
// / because the entity is a pointer and we assign the address of a temporary
50
53
// / object to it.
51
54
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,
52
59
};
53
60
using LifetimeResult =
54
61
llvm::PointerIntPair<const InitializedEntity *, 3 , LifetimeKind>;
@@ -193,6 +200,7 @@ struct IndirectLocalPathEntry {
193
200
VarInit,
194
201
LValToRVal,
195
202
LifetimeBoundCall,
203
+ LifetimeCapture,
196
204
TemporaryCopy,
197
205
LambdaCaptureInit,
198
206
GslReferenceInit,
@@ -249,9 +257,12 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
249
257
LocalVisitor Visit);
250
258
251
259
template <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>();
255
266
}
256
267
257
268
// Decl::isInStdNamespace will return false for iterators in some STL
@@ -1049,6 +1060,7 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
1049
1060
case IndirectLocalPathEntry::AddressOf:
1050
1061
case IndirectLocalPathEntry::LValToRVal:
1051
1062
case IndirectLocalPathEntry::LifetimeBoundCall:
1063
+ case IndirectLocalPathEntry::LifetimeCapture:
1052
1064
case IndirectLocalPathEntry::TemporaryCopy:
1053
1065
case IndirectLocalPathEntry::GslReferenceInit:
1054
1066
case IndirectLocalPathEntry::GslPointerInit:
@@ -1082,6 +1094,7 @@ static bool pathOnlyHandlesGslPointer(const IndirectLocalPath &Path) {
1082
1094
case IndirectLocalPathEntry::VarInit:
1083
1095
case IndirectLocalPathEntry::AddressOf:
1084
1096
case IndirectLocalPathEntry::LifetimeBoundCall:
1097
+ case IndirectLocalPathEntry::LifetimeCapture:
1085
1098
continue ;
1086
1099
case IndirectLocalPathEntry::GslPointerInit:
1087
1100
case IndirectLocalPathEntry::GslReferenceInit:
@@ -1102,21 +1115,22 @@ static bool isAssignmentOperatorLifetimeBound(CXXMethodDecl *CMD) {
1102
1115
}
1103
1116
1104
1117
static bool shouldRunGSLAssignmentAnalysis (const Sema &SemaRef,
1105
- const AssignedEntity &Entity) {
1118
+ const CapturingEntity &Entity) {
1106
1119
bool EnableGSLAssignmentWarnings = !SemaRef.getDiagnostics ().isIgnored (
1107
1120
diag::warn_dangling_lifetime_pointer_assignment, SourceLocation ());
1108
1121
return (EnableGSLAssignmentWarnings &&
1109
- (isRecordWithAttr<PointerAttr>(Entity.LHS ->getType ()) ||
1122
+ (isRecordWithAttr<PointerAttr>(Entity.Expression ->getType ()) ||
1110
1123
isAssignmentOperatorLifetimeBound (Entity.AssignmentOperator )));
1111
1124
}
1112
1125
1113
1126
static void checkExprLifetimeImpl (Sema &SemaRef,
1114
1127
const InitializedEntity *InitEntity,
1115
1128
const InitializedEntity *ExtendingEntity,
1116
1129
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);
1120
1134
// If this entity doesn't have an interesting lifetime, don't bother looking
1121
1135
// for temporaries within its initializer.
1122
1136
if (LK == LK_FullExpression)
@@ -1199,6 +1213,17 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
1199
1213
break ;
1200
1214
}
1201
1215
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
+
1202
1227
case LK_Assignment: {
1203
1228
if (!MTE || pathContainsInit (Path))
1204
1229
return false ;
@@ -1207,10 +1232,10 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
1207
1232
" No lifetime extension for assignments" );
1208
1233
if (IsGslPtrValueFromGslTempOwner)
1209
1234
SemaRef.Diag (DiagLoc, diag::warn_dangling_lifetime_pointer_assignment)
1210
- << AEntity-> LHS << DiagRange;
1235
+ << CEntity-> Expression << DiagRange;
1211
1236
else
1212
1237
SemaRef.Diag (DiagLoc, diag::warn_dangling_pointer_assignment)
1213
- << AEntity-> LHS ->getType ()->isPointerType () << AEntity-> LHS
1238
+ << CEntity-> Expression ->getType ()->isPointerType () << CEntity-> Expression
1214
1239
<< DiagRange;
1215
1240
return false ;
1216
1241
}
@@ -1359,6 +1384,7 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
1359
1384
break ;
1360
1385
1361
1386
case IndirectLocalPathEntry::LifetimeBoundCall:
1387
+ case IndirectLocalPathEntry::LifetimeCapture:
1362
1388
case IndirectLocalPathEntry::TemporaryCopy:
1363
1389
case IndirectLocalPathEntry::GslPointerInit:
1364
1390
case IndirectLocalPathEntry::GslReferenceInit:
@@ -1412,17 +1438,27 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
1412
1438
return false ;
1413
1439
};
1414
1440
1441
+ bool HasReferenceBinding = Init->isGLValue ();
1415
1442
llvm::SmallVector<IndirectLocalPathEntry, 8 > Path;
1416
1443
if (LK == LK_Assignment &&
1417
- shouldRunGSLAssignmentAnalysis (SemaRef, *AEntity )) {
1444
+ shouldRunGSLAssignmentAnalysis (SemaRef, *CEntity )) {
1418
1445
Path.push_back (
1419
- {isAssignmentOperatorLifetimeBound (AEntity ->AssignmentOperator )
1446
+ {isAssignmentOperatorLifetimeBound (CEntity ->AssignmentOperator )
1420
1447
? IndirectLocalPathEntry::LifetimeBoundCall
1421
1448
: IndirectLocalPathEntry::GslPointerAssignment,
1422
1449
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 ();
1423
1459
}
1424
1460
1425
- if (Init-> isGLValue () )
1461
+ if (HasReferenceBinding )
1426
1462
visitLocalsRetainedByReferenceBinding (Path, Init, RK_ReferenceBinding,
1427
1463
TemporaryVisitor);
1428
1464
else
@@ -1432,7 +1468,7 @@ static void checkExprLifetimeImpl(Sema &SemaRef,
1432
1468
/* RevisitSubinits=*/ !InitEntity);
1433
1469
}
1434
1470
1435
- void checkExprLifetime (Sema &SemaRef, const InitializedEntity &Entity,
1471
+ void checkInitLifetime (Sema &SemaRef, const InitializedEntity &Entity,
1436
1472
Expr *Init) {
1437
1473
auto LTResult = getEntityLifetime (&Entity);
1438
1474
LifetimeKind LK = LTResult.getInt ();
@@ -1447,20 +1483,26 @@ void checkExprLifetimeMustTailArg(Sema &SemaRef,
1447
1483
/* AEntity*/ nullptr , Init);
1448
1484
}
1449
1485
1450
- void checkExprLifetime (Sema &SemaRef, const AssignedEntity &Entity,
1451
- Expr *Init ) {
1486
+ void checkAssignmentLifetime (Sema &SemaRef, const CapturingEntity &Entity,
1487
+ Expr *RHS ) {
1452
1488
bool EnableDanglingPointerAssignment = !SemaRef.getDiagnostics ().isIgnored (
1453
1489
diag::warn_dangling_pointer_assignment, SourceLocation ());
1454
1490
bool RunAnalysis = (EnableDanglingPointerAssignment &&
1455
- Entity.LHS ->getType ()->isPointerType ()) ||
1491
+ Entity.Expression ->getType ()->isPointerType ()) ||
1456
1492
shouldRunGSLAssignmentAnalysis (SemaRef, Entity);
1457
1493
1458
1494
if (!RunAnalysis)
1459
1495
return ;
1460
1496
1461
1497
checkExprLifetimeImpl (SemaRef, /* InitEntity=*/ nullptr ,
1462
1498
/* ExtendingEntity=*/ nullptr , LK_Assignment, &Entity,
1463
- Init );
1499
+ RHS );
1464
1500
}
1465
1501
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
+ }
1466
1508
} // namespace clang::sema
0 commit comments