1717#include " llvm/ADT/PointerIntPair.h"
1818
1919namespace clang ::sema {
20+ using lifetimes::isGslOwnerType;
21+ using lifetimes::isGslPointerType;
22+
2023namespace {
2124enum LifetimeKind {
2225 // / The lifetime of a temporary bound to this entity ends at the end of the
@@ -257,38 +260,8 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
257260 Expr *Init, ReferenceKind RK,
258261 LocalVisitor Visit);
259262
260- template <typename T> static bool isRecordWithAttr (QualType Type) {
261- auto *RD = Type->getAsCXXRecordDecl ();
262- if (!RD)
263- return false ;
264- // Generally, if a primary template class declaration is annotated with an
265- // attribute, all its specializations generated from template instantiations
266- // should inherit the attribute.
267- //
268- // However, since lifetime analysis occurs during parsing, we may encounter
269- // cases where a full definition of the specialization is not required. In
270- // such cases, the specialization declaration remains incomplete and lacks the
271- // attribute. Therefore, we fall back to checking the primary template class.
272- //
273- // Note: it is possible for a specialization declaration to have an attribute
274- // even if the primary template does not.
275- //
276- // FIXME: What if the primary template and explicit specialization
277- // declarations have conflicting attributes? We should consider diagnosing
278- // this scenario.
279- bool Result = RD->hasAttr <T>();
280-
281- if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
282- Result |= CTSD->getSpecializedTemplate ()->getTemplatedDecl ()->hasAttr <T>();
283-
284- return Result;
285- }
286-
287- // Tells whether the type is annotated with [[gsl::Pointer]].
288- bool isGLSPointerType (QualType QT) { return isRecordWithAttr<PointerAttr>(QT); }
289-
290263static bool isPointerLikeType (QualType QT) {
291- return isGLSPointerType (QT) || QT->isPointerType () || QT->isNullPtrType ();
264+ return isGslPointerType (QT) || QT->isPointerType () || QT->isNullPtrType ();
292265}
293266
294267// Decl::isInStdNamespace will return false for iterators in some STL
@@ -331,7 +304,7 @@ static bool isContainerOfOwner(const RecordDecl *Container) {
331304 return false ;
332305 const auto &TAs = CTSD->getTemplateArgs ();
333306 return TAs.size () > 0 && TAs[0 ].getKind () == TemplateArgument::Type &&
334- isRecordWithAttr<OwnerAttr> (TAs[0 ].getAsType ());
307+ isGslOwnerType (TAs[0 ].getAsType ());
335308}
336309
337310// Returns true if the given Record is `std::initializer_list<pointer>`.
@@ -349,14 +322,13 @@ static bool isStdInitializerListOfPointer(const RecordDecl *RD) {
349322
350323static bool shouldTrackImplicitObjectArg (const CXXMethodDecl *Callee) {
351324 if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
352- if (isRecordWithAttr<PointerAttr> (Conv->getConversionType ()) &&
325+ if (isGslPointerType (Conv->getConversionType ()) &&
353326 Callee->getParent ()->hasAttr <OwnerAttr>())
354327 return true ;
355328 if (!isInStlNamespace (Callee->getParent ()))
356329 return false ;
357- if (!isRecordWithAttr<PointerAttr>(
358- Callee->getFunctionObjectParameterType ()) &&
359- !isRecordWithAttr<OwnerAttr>(Callee->getFunctionObjectParameterType ()))
330+ if (!isGslPointerType (Callee->getFunctionObjectParameterType ()) &&
331+ !isGslOwnerType (Callee->getFunctionObjectParameterType ()))
360332 return false ;
361333 if (isPointerLikeType (Callee->getReturnType ())) {
362334 if (!Callee->getIdentifier ())
@@ -393,7 +365,7 @@ static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
393365 if (!RD->hasAttr <PointerAttr>() && !RD->hasAttr <OwnerAttr>())
394366 return false ;
395367 if (FD->getReturnType ()->isPointerType () ||
396- isRecordWithAttr<PointerAttr> (FD->getReturnType ())) {
368+ isGslPointerType (FD->getReturnType ())) {
397369 return llvm::StringSwitch<bool >(FD->getName ())
398370 .Cases ({" begin" , " rbegin" , " cbegin" , " crbegin" }, true )
399371 .Cases ({" end" , " rend" , " cend" , " crend" }, true )
@@ -465,7 +437,7 @@ shouldTrackFirstArgumentForConstructor(const CXXConstructExpr *Ctor) {
465437 return true ;
466438
467439 // RHS must be an owner.
468- if (!isRecordWithAttr<OwnerAttr> (RHSArgType))
440+ if (!isGslOwnerType (RHSArgType))
469441 return false ;
470442
471443 // Bail out if the RHS is Owner<Pointer>.
@@ -547,7 +519,7 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
547519 // Once we initialized a value with a non gsl-owner reference, it can no
548520 // longer dangle.
549521 if (ReturnType->isReferenceType () &&
550- !isRecordWithAttr<OwnerAttr> (ReturnType->getPointeeType ())) {
522+ !isGslOwnerType (ReturnType->getPointeeType ())) {
551523 for (const IndirectLocalPathEntry &PE : llvm::reverse (Path)) {
552524 if (PE.Kind == IndirectLocalPathEntry::GslReferenceInit ||
553525 PE.Kind == IndirectLocalPathEntry::LifetimeBoundCall)
@@ -1158,8 +1130,7 @@ static AnalysisResult analyzePathForGSLPointer(const IndirectLocalPath &Path,
11581130 // auto p2 = Temp().owner; // Here p2 is dangling.
11591131 if (const auto *FD = llvm::dyn_cast_or_null<FieldDecl>(E.D );
11601132 FD && !FD->getType ()->isReferenceType () &&
1161- isRecordWithAttr<OwnerAttr>(FD->getType ()) &&
1162- LK != LK_MemInitializer) {
1133+ isGslOwnerType (FD->getType ()) && LK != LK_MemInitializer) {
11631134 return Report;
11641135 }
11651136 return Abandon;
@@ -1191,10 +1162,9 @@ static AnalysisResult analyzePathForGSLPointer(const IndirectLocalPath &Path,
11911162 // const GSLOwner& func(const Foo& foo [[clang::lifetimebound]])
11921163 // GSLOwner* func(cosnt Foo& foo [[clang::lifetimebound]])
11931164 // GSLPointer func(const Foo& foo [[clang::lifetimebound]])
1194- if (FD &&
1195- ((FD->getReturnType ()->isPointerOrReferenceType () &&
1196- isRecordWithAttr<OwnerAttr>(FD->getReturnType ()->getPointeeType ())) ||
1197- isGLSPointerType (FD->getReturnType ())))
1165+ if (FD && ((FD->getReturnType ()->isPointerOrReferenceType () &&
1166+ isGslOwnerType (FD->getReturnType ()->getPointeeType ())) ||
1167+ isGslPointerType (FD->getReturnType ())))
11981168 return Report;
11991169
12001170 return Abandon;
@@ -1206,7 +1176,7 @@ static AnalysisResult analyzePathForGSLPointer(const IndirectLocalPath &Path,
12061176 // int &p = *localUniquePtr;
12071177 // someContainer.add(std::move(localUniquePtr));
12081178 // return p;
1209- if (!pathContainsInit (Path) && isRecordWithAttr<OwnerAttr> (L->getType ()))
1179+ if (!pathContainsInit (Path) && isGslOwnerType (L->getType ()))
12101180 return Report;
12111181 return Abandon;
12121182 }
@@ -1215,8 +1185,7 @@ static AnalysisResult analyzePathForGSLPointer(const IndirectLocalPath &Path,
12151185 auto *MTE = dyn_cast<MaterializeTemporaryExpr>(L);
12161186
12171187 bool IsGslPtrValueFromGslTempOwner =
1218- MTE && !MTE->getExtendingDecl () &&
1219- isRecordWithAttr<OwnerAttr>(MTE->getType ());
1188+ MTE && !MTE->getExtendingDecl () && isGslOwnerType (MTE->getType ());
12201189 // Skipping a chain of initializing gsl::Pointer annotated objects.
12211190 // We are looking only for the final source to find out if it was
12221191 // a local or temporary owner or the address of a local
@@ -1231,7 +1200,7 @@ static bool shouldRunGSLAssignmentAnalysis(const Sema &SemaRef,
12311200 bool EnableGSLAssignmentWarnings = !SemaRef.getDiagnostics ().isIgnored (
12321201 diag::warn_dangling_lifetime_pointer_assignment, SourceLocation ());
12331202 return (EnableGSLAssignmentWarnings &&
1234- (isRecordWithAttr<PointerAttr> (Entity.LHS ->getType ()) ||
1203+ (isGslPointerType (Entity.LHS ->getType ()) ||
12351204 lifetimes::isAssignmentOperatorLifetimeBound (
12361205 Entity.AssignmentOperator )));
12371206}
@@ -1400,7 +1369,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
14001369 // Suppress false positives for code like the one below:
14011370 // Ctor(unique_ptr<T> up) : pointer(up.get()), owner(move(up)) {}
14021371 // FIXME: move this logic to analyzePathForGSLPointer.
1403- if (DRE && isRecordWithAttr<OwnerAttr> (DRE->getType ()))
1372+ if (DRE && isGslOwnerType (DRE->getType ()))
14041373 return false ;
14051374
14061375 auto *VD = DRE ? dyn_cast<VarDecl>(DRE->getDecl ()) : nullptr ;
0 commit comments