@@ -200,6 +200,7 @@ struct IndirectLocalPathEntry {
200200 LifetimeBoundCall,
201201 TemporaryCopy,
202202 LambdaCaptureInit,
203+ MemberExpr,
203204 GslReferenceInit,
204205 GslPointerInit,
205206 GslPointerAssignment,
@@ -593,19 +594,6 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
593594 Path.pop_back ();
594595 };
595596 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-
609597 auto ReturnType = Callee->getReturnType ();
610598
611599 // Once we initialized a value with a non gsl-owner reference, it can no
@@ -726,6 +714,9 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
726714 Init = ILE->getInit (0 );
727715 }
728716
717+ if (MemberExpr *ME = dyn_cast<MemberExpr>(Init->IgnoreImpCasts ()))
718+ Path.push_back (
719+ {IndirectLocalPathEntry::MemberExpr, ME, ME->getMemberDecl ()});
729720 // Step over any subobject adjustments; we may have a materialized
730721 // temporary inside them.
731722 Init = const_cast <Expr *>(Init->skipRValueSubobjectAdjustments ());
@@ -1117,10 +1108,12 @@ enum PathLifetimeKind {
11171108static PathLifetimeKind
11181109shouldLifetimeExtendThroughPath (const IndirectLocalPath &Path) {
11191110 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;
11241117 }
11251118 return PathLifetimeKind::Extend;
11261119}
@@ -1138,6 +1131,7 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
11381131 case IndirectLocalPathEntry::GslPointerInit:
11391132 case IndirectLocalPathEntry::GslPointerAssignment:
11401133 case IndirectLocalPathEntry::ParenAggInit:
1134+ case IndirectLocalPathEntry::MemberExpr:
11411135 // These exist primarily to mark the path as not permitting or
11421136 // supporting lifetime extension.
11431137 break ;
@@ -1167,6 +1161,7 @@ static bool pathOnlyHandlesGslPointer(const IndirectLocalPath &Path) {
11671161 case IndirectLocalPathEntry::VarInit:
11681162 case IndirectLocalPathEntry::AddressOf:
11691163 case IndirectLocalPathEntry::LifetimeBoundCall:
1164+ case IndirectLocalPathEntry::MemberExpr:
11701165 continue ;
11711166 case IndirectLocalPathEntry::GslPointerInit:
11721167 case IndirectLocalPathEntry::GslReferenceInit:
@@ -1193,13 +1188,34 @@ enum AnalysisResult {
11931188// Analyze cases where a GSLPointer is initialized or assigned from a
11941189// temporary owner object.
11951190static AnalysisResult analyzePathForGSLPointer (const IndirectLocalPath &Path,
1196- Local L) {
1191+ Local L, LifetimeKind LK ) {
11971192 if (!pathOnlyHandlesGslPointer (Path))
11981193 return NotGSLPointer;
11991194
12001195 // At this point, Path represents a series of operations involving a
12011196 // GSLPointer, either in the process of initialization or assignment.
12021197
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+
12031219 // Note: A LifetimeBoundCall can appear interleaved in this sequence.
12041220 // For example:
12051221 // const std::string& Ref(const std::string& a [[clang::lifetimebound]]);
@@ -1297,7 +1313,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
12971313 auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);
12981314
12991315 bool IsGslPtrValueFromGslTempOwner = true ;
1300- switch (analyzePathForGSLPointer (Path, L)) {
1316+ switch (analyzePathForGSLPointer (Path, L, LK )) {
13011317 case Abandon:
13021318 return false ;
13031319 case Skip:
@@ -1429,6 +1445,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
14291445 auto *DRE = dyn_cast<DeclRefExpr>(L);
14301446 // Suppress false positives for code like the one below:
14311447 // Ctor(unique_ptr<T> up) : pointer(up.get()), owner(move(up)) {}
1448+ // FIXME: move this logic to analyzePathForGSLPointer.
14321449 if (DRE && isRecordWithAttr<OwnerAttr>(DRE->getType ()))
14331450 return false ;
14341451
@@ -1527,6 +1544,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
15271544
15281545 case IndirectLocalPathEntry::LifetimeBoundCall:
15291546 case IndirectLocalPathEntry::TemporaryCopy:
1547+ case IndirectLocalPathEntry::MemberExpr:
15301548 case IndirectLocalPathEntry::GslPointerInit:
15311549 case IndirectLocalPathEntry::GslReferenceInit:
15321550 case IndirectLocalPathEntry::GslPointerAssignment:
0 commit comments