@@ -200,6 +200,7 @@ struct IndirectLocalPathEntry {
200
200
LifetimeBoundCall,
201
201
TemporaryCopy,
202
202
LambdaCaptureInit,
203
+ MemberExpr,
203
204
GslReferenceInit,
204
205
GslPointerInit,
205
206
GslPointerAssignment,
@@ -593,19 +594,6 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
593
594
Path.pop_back ();
594
595
};
595
596
auto VisitGSLPointerArg = [&](const FunctionDecl *Callee, Expr *Arg) {
596
- // We are not interested in the temporary base objects of gsl Pointers:
597
- // Temp().ptr; // Here ptr might not dangle.
598
- if (isa<MemberExpr>(Arg->IgnoreImpCasts ()))
599
- return ;
600
- // Avoid false positives when the object is constructed from a conditional
601
- // operator argument. A common case is:
602
- // // 'ptr' might not be owned by the Owner object.
603
- // std::string_view s = cond() ? Owner().ptr : sv;
604
- if (const auto *Cond =
605
- dyn_cast<AbstractConditionalOperator>(Arg->IgnoreImpCasts ());
606
- Cond && isPointerLikeType (Cond->getType ()))
607
- return ;
608
-
609
597
auto ReturnType = Callee->getReturnType ();
610
598
611
599
// Once we initialized a value with a non gsl-owner reference, it can no
@@ -726,6 +714,9 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
726
714
Init = ILE->getInit (0 );
727
715
}
728
716
717
+ if (MemberExpr *ME = dyn_cast<MemberExpr>(Init->IgnoreImpCasts ()))
718
+ Path.push_back (
719
+ {IndirectLocalPathEntry::MemberExpr, ME, ME->getMemberDecl ()});
729
720
// Step over any subobject adjustments; we may have a materialized
730
721
// temporary inside them.
731
722
Init = const_cast <Expr *>(Init->skipRValueSubobjectAdjustments ());
@@ -1117,10 +1108,12 @@ enum PathLifetimeKind {
1117
1108
static PathLifetimeKind
1118
1109
shouldLifetimeExtendThroughPath (const IndirectLocalPath &Path) {
1119
1110
for (auto Elem : Path) {
1120
- if (Elem.Kind == IndirectLocalPathEntry::DefaultInit)
1121
- return PathLifetimeKind::Extend;
1122
- if (Elem.Kind != IndirectLocalPathEntry::LambdaCaptureInit)
1123
- return PathLifetimeKind::NoExtend;
1111
+ if (Elem.Kind == IndirectLocalPathEntry::MemberExpr ||
1112
+ Elem.Kind == IndirectLocalPathEntry::LambdaCaptureInit)
1113
+ continue ;
1114
+ return Elem.Kind == IndirectLocalPathEntry::DefaultInit
1115
+ ? PathLifetimeKind::Extend
1116
+ : PathLifetimeKind::NoExtend;
1124
1117
}
1125
1118
return PathLifetimeKind::Extend;
1126
1119
}
@@ -1138,6 +1131,7 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
1138
1131
case IndirectLocalPathEntry::GslPointerInit:
1139
1132
case IndirectLocalPathEntry::GslPointerAssignment:
1140
1133
case IndirectLocalPathEntry::ParenAggInit:
1134
+ case IndirectLocalPathEntry::MemberExpr:
1141
1135
// These exist primarily to mark the path as not permitting or
1142
1136
// supporting lifetime extension.
1143
1137
break ;
@@ -1167,6 +1161,7 @@ static bool pathOnlyHandlesGslPointer(const IndirectLocalPath &Path) {
1167
1161
case IndirectLocalPathEntry::VarInit:
1168
1162
case IndirectLocalPathEntry::AddressOf:
1169
1163
case IndirectLocalPathEntry::LifetimeBoundCall:
1164
+ case IndirectLocalPathEntry::MemberExpr:
1170
1165
continue ;
1171
1166
case IndirectLocalPathEntry::GslPointerInit:
1172
1167
case IndirectLocalPathEntry::GslReferenceInit:
@@ -1193,13 +1188,34 @@ enum AnalysisResult {
1193
1188
// Analyze cases where a GSLPointer is initialized or assigned from a
1194
1189
// temporary owner object.
1195
1190
static AnalysisResult analyzePathForGSLPointer (const IndirectLocalPath &Path,
1196
- Local L) {
1191
+ Local L, LifetimeKind LK ) {
1197
1192
if (!pathOnlyHandlesGslPointer (Path))
1198
1193
return NotGSLPointer;
1199
1194
1200
1195
// At this point, Path represents a series of operations involving a
1201
1196
// GSLPointer, either in the process of initialization or assignment.
1202
1197
1198
+ // Process temporary base objects for MemberExpr cases, e.g. Temp().field.
1199
+ for (const auto &E : Path) {
1200
+ if (E.Kind == IndirectLocalPathEntry::MemberExpr) {
1201
+ // Avoid interfering with the local base object.
1202
+ if (pathContainsInit (Path))
1203
+ return Abandon;
1204
+
1205
+ // We are not interested in the temporary base objects of gsl Pointers:
1206
+ // auto p1 = Temp().ptr; // Here p1 might not dangle.
1207
+ // However, we want to diagnose for gsl owner fields:
1208
+ // auto p2 = Temp().owner; // Here p2 is dangling.
1209
+ if (const auto *FD = llvm::dyn_cast_or_null<FieldDecl>(E.D );
1210
+ FD && !FD->getType ()->isReferenceType () &&
1211
+ isRecordWithAttr<OwnerAttr>(FD->getType ()) &&
1212
+ LK != LK_MemInitializer) {
1213
+ return Report;
1214
+ }
1215
+ return Abandon;
1216
+ }
1217
+ }
1218
+
1203
1219
// Note: A LifetimeBoundCall can appear interleaved in this sequence.
1204
1220
// For example:
1205
1221
// const std::string& Ref(const std::string& a [[clang::lifetimebound]]);
@@ -1297,7 +1313,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
1297
1313
auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);
1298
1314
1299
1315
bool IsGslPtrValueFromGslTempOwner = true ;
1300
- switch (analyzePathForGSLPointer (Path, L)) {
1316
+ switch (analyzePathForGSLPointer (Path, L, LK )) {
1301
1317
case Abandon:
1302
1318
return false ;
1303
1319
case Skip:
@@ -1429,6 +1445,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
1429
1445
auto *DRE = dyn_cast<DeclRefExpr>(L);
1430
1446
// Suppress false positives for code like the one below:
1431
1447
// Ctor(unique_ptr<T> up) : pointer(up.get()), owner(move(up)) {}
1448
+ // FIXME: move this logic to analyzePathForGSLPointer.
1432
1449
if (DRE && isRecordWithAttr<OwnerAttr>(DRE->getType ()))
1433
1450
return false ;
1434
1451
@@ -1527,6 +1544,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
1527
1544
1528
1545
case IndirectLocalPathEntry::LifetimeBoundCall:
1529
1546
case IndirectLocalPathEntry::TemporaryCopy:
1547
+ case IndirectLocalPathEntry::MemberExpr:
1530
1548
case IndirectLocalPathEntry::GslPointerInit:
1531
1549
case IndirectLocalPathEntry::GslReferenceInit:
1532
1550
case IndirectLocalPathEntry::GslPointerAssignment:
0 commit comments