@@ -200,6 +200,7 @@ struct IndirectLocalPathEntry {
200200 LifetimeBoundCall,
201201 TemporaryCopy,
202202 LambdaCaptureInit,
203+ MemberExpr,
203204 GslReferenceInit,
204205 GslPointerInit,
205206 GslPointerAssignment,
@@ -578,19 +579,6 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
578579 Path.pop_back ();
579580 };
580581 auto VisitGSLPointerArg = [&](const FunctionDecl *Callee, Expr *Arg) {
581- // We are not interested in the temporary base objects of gsl Pointers:
582- // Temp().ptr; // Here ptr might not dangle.
583- if (isa<MemberExpr>(Arg->IgnoreImpCasts ()))
584- return ;
585- // Avoid false positives when the object is constructed from a conditional
586- // operator argument. A common case is:
587- // // 'ptr' might not be owned by the Owner object.
588- // std::string_view s = cond() ? Owner().ptr : sv;
589- if (const auto *Cond =
590- dyn_cast<AbstractConditionalOperator>(Arg->IgnoreImpCasts ());
591- Cond && isPointerLikeType (Cond->getType ()))
592- return ;
593-
594582 auto ReturnType = Callee->getReturnType ();
595583
596584 // Once we initialized a value with a non gsl-owner reference, it can no
@@ -710,6 +698,9 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
710698 Init = ILE->getInit (0 );
711699 }
712700
701+ if (MemberExpr *ME = dyn_cast<MemberExpr>(Init->IgnoreImpCasts ()))
702+ Path.push_back (
703+ {IndirectLocalPathEntry::MemberExpr, ME, ME->getMemberDecl ()});
713704 // Step over any subobject adjustments; we may have a materialized
714705 // temporary inside them.
715706 Init = const_cast <Expr *>(Init->skipRValueSubobjectAdjustments ());
@@ -1103,6 +1094,8 @@ shouldLifetimeExtendThroughPath(const IndirectLocalPath &Path) {
11031094 for (auto Elem : Path) {
11041095 if (Elem.Kind == IndirectLocalPathEntry::DefaultInit)
11051096 return PathLifetimeKind::Extend;
1097+ if (Elem.Kind == IndirectLocalPathEntry::MemberExpr)
1098+ continue ;
11061099 if (Elem.Kind != IndirectLocalPathEntry::LambdaCaptureInit)
11071100 return PathLifetimeKind::NoExtend;
11081101 }
@@ -1122,6 +1115,7 @@ static SourceRange nextPathEntryRange(const IndirectLocalPath &Path, unsigned I,
11221115 case IndirectLocalPathEntry::GslPointerInit:
11231116 case IndirectLocalPathEntry::GslPointerAssignment:
11241117 case IndirectLocalPathEntry::ParenAggInit:
1118+ case IndirectLocalPathEntry::MemberExpr:
11251119 // These exist primarily to mark the path as not permitting or
11261120 // supporting lifetime extension.
11271121 break ;
@@ -1151,6 +1145,7 @@ static bool pathOnlyHandlesGslPointer(const IndirectLocalPath &Path) {
11511145 case IndirectLocalPathEntry::VarInit:
11521146 case IndirectLocalPathEntry::AddressOf:
11531147 case IndirectLocalPathEntry::LifetimeBoundCall:
1148+ case IndirectLocalPathEntry::MemberExpr:
11541149 continue ;
11551150 case IndirectLocalPathEntry::GslPointerInit:
11561151 case IndirectLocalPathEntry::GslReferenceInit:
@@ -1184,6 +1179,26 @@ static AnalysisResult analyzePathForGSLPointer(const IndirectLocalPath &Path,
11841179 // At this point, Path represents a series of operations involving a
11851180 // GSLPointer, either in the process of initialization or assignment.
11861181
1182+ // Process temporary base objects for MemberExpr cases, e.g. Temp().field.
1183+ for (const auto &E : Path) {
1184+ if (E.Kind == IndirectLocalPathEntry::MemberExpr) {
1185+ // Avoid interfering with the local base object.
1186+ if (pathContainsInit (Path))
1187+ return Abandon;
1188+
1189+ // We are not interested in the temporary base objects of gsl Pointers:
1190+ // auto p1 = Temp().ptr; // Here p1 might not dangle.
1191+ // However, we want to diagnose for gsl owner fields:
1192+ // auto p2 = Temp().owner; // Here p2 is dangling.
1193+ if (const auto *FD = llvm::dyn_cast_or_null<FieldDecl>(E.D );
1194+ FD && !FD->getType ()->isReferenceType () &&
1195+ isRecordWithAttr<OwnerAttr>(FD->getType ())) {
1196+ return Report;
1197+ }
1198+ return Abandon;
1199+ }
1200+ }
1201+
11871202 // Note: A LifetimeBoundCall can appear interleaved in this sequence.
11881203 // For example:
11891204 // const std::string& Ref(const std::string& a [[clang::lifetimebound]]);
@@ -1510,6 +1525,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
15101525
15111526 case IndirectLocalPathEntry::LifetimeBoundCall:
15121527 case IndirectLocalPathEntry::TemporaryCopy:
1528+ case IndirectLocalPathEntry::MemberExpr:
15131529 case IndirectLocalPathEntry::GslPointerInit:
15141530 case IndirectLocalPathEntry::GslReferenceInit:
15151531 case IndirectLocalPathEntry::GslPointerAssignment:
0 commit comments