[clang] [clang] Check specialization for annotation (PR #117315)
Utkarsh Saxena via cfe-commits
cfe-commits at lists.llvm.org
Thu Nov 28 01:03:39 PST 2024
https://github.com/usx95 updated https://github.com/llvm/llvm-project/pull/117315
>From e30ae8a6e0c1df8e33c2add6502342cb269c1cfd Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Fri, 22 Nov 2024 11:02:49 +0000
Subject: [PATCH 1/2] [clang] Check specialization for annotation
---
clang/lib/Sema/CheckExprLifetime.cpp | 9 ++++++---
1 file changed, 6 insertions(+), 3 deletions(-)
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index 8886e5e307ddf8..64dc4794b6235a 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -253,9 +253,12 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
LocalVisitor Visit);
template <typename T> static bool isRecordWithAttr(QualType Type) {
- if (auto *RD = Type->getAsCXXRecordDecl())
- return RD->hasAttr<T>();
- return false;
+ auto *RD = Type->getAsCXXRecordDecl();
+ if (!RD)
+ return false;
+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
+ RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+ return RD->hasAttr<T>();
}
// Decl::isInStdNamespace will return false for iterators in some STL
>From db163394b70054694734c269f5fd61ef438eda3b Mon Sep 17 00:00:00 2001
From: Utkarsh Saxena <usx at google.com>
Date: Thu, 28 Nov 2024 09:01:25 +0000
Subject: [PATCH 2/2] move to Sema.h
---
clang/include/clang/Sema/Sema.h | 12 ++++++++
clang/lib/Sema/CheckExprLifetime.cpp | 45 ++++++++++------------------
clang/lib/Sema/SemaAttr.cpp | 5 ++++
3 files changed, 33 insertions(+), 29 deletions(-)
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 6ea6c67447b6f0..9029d54e90f028 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1760,6 +1760,18 @@ class Sema final : public SemaBase {
/// Add [[gsl::Pointer]] attributes for std:: types.
void inferGslPointerAttribute(TypedefNameDecl *TD);
+ template <typename T> static bool isRecordWithAttr(QualType Type) {
+ auto *RD = Type->getAsCXXRecordDecl();
+ if (!RD)
+ return false;
+ if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
+ RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
+ return RD->hasAttr<T>();
+ }
+
+ /// ....
+ static bool isPointerLikeType(QualType Type);
+
LifetimeCaptureByAttr *ParseLifetimeCaptureByAttr(const ParsedAttr &AL,
StringRef ParamName);
// Processes the argument 'X' in [[clang::lifetime_capture_by(X)]]. Since 'X'
diff --git a/clang/lib/Sema/CheckExprLifetime.cpp b/clang/lib/Sema/CheckExprLifetime.cpp
index 64dc4794b6235a..e18651d8e12ab9 100644
--- a/clang/lib/Sema/CheckExprLifetime.cpp
+++ b/clang/lib/Sema/CheckExprLifetime.cpp
@@ -252,15 +252,6 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path,
Expr *Init, ReferenceKind RK,
LocalVisitor Visit);
-template <typename T> static bool isRecordWithAttr(QualType Type) {
- auto *RD = Type->getAsCXXRecordDecl();
- if (!RD)
- return false;
- if (auto *CTSD = dyn_cast<ClassTemplateSpecializationDecl>(RD))
- RD = CTSD->getSpecializedTemplate()->getTemplatedDecl();
- return RD->hasAttr<T>();
-}
-
// Decl::isInStdNamespace will return false for iterators in some STL
// implementations due to them being defined in a namespace outside of the std
// namespace.
@@ -279,11 +270,6 @@ static bool isInStlNamespace(const Decl *D) {
return DC->isStdNamespace();
}
-static bool isPointerLikeType(QualType Type) {
- return isRecordWithAttr<PointerAttr>(Type) || Type->isPointerType() ||
- Type->isNullPtrType();
-}
-
// Returns true if the given Record decl is a form of `GSLOwner<Pointer>`
// type, e.g. std::vector<string_view>, std::optional<string_view>.
static bool isContainerOfPointer(const RecordDecl *Container) {
@@ -293,7 +279,7 @@ static bool isContainerOfPointer(const RecordDecl *Container) {
return false;
const auto &TAs = CTSD->getTemplateArgs();
return TAs.size() > 0 && TAs[0].getKind() == TemplateArgument::Type &&
- isPointerLikeType(TAs[0].getAsType());
+ Sema::isPointerLikeType(TAs[0].getAsType());
}
return false;
}
@@ -306,7 +292,7 @@ static bool isContainerOfOwner(const RecordDecl *Container) {
return false;
const auto &TAs = CTSD->getTemplateArgs();
return TAs.size() > 0 && TAs[0].getKind() == TemplateArgument::Type &&
- isRecordWithAttr<OwnerAttr>(TAs[0].getAsType());
+ Sema::isRecordWithAttr<OwnerAttr>(TAs[0].getAsType());
}
// Returns true if the given Record is `std::initializer_list<pointer>`.
@@ -317,23 +303,24 @@ static bool isStdInitializerListOfPointer(const RecordDecl *RD) {
return isInStlNamespace(RD) && RD->getIdentifier() &&
RD->getName() == "initializer_list" && TAs.size() > 0 &&
TAs[0].getKind() == TemplateArgument::Type &&
- isPointerLikeType(TAs[0].getAsType());
+ Sema::isPointerLikeType(TAs[0].getAsType());
}
return false;
}
static bool shouldTrackImplicitObjectArg(const CXXMethodDecl *Callee) {
if (auto *Conv = dyn_cast_or_null<CXXConversionDecl>(Callee))
- if (isRecordWithAttr<PointerAttr>(Conv->getConversionType()) &&
+ if (Sema::isRecordWithAttr<PointerAttr>(Conv->getConversionType()) &&
Callee->getParent()->hasAttr<OwnerAttr>())
return true;
if (!isInStlNamespace(Callee->getParent()))
return false;
- if (!isRecordWithAttr<PointerAttr>(
+ if (!Sema::isRecordWithAttr<PointerAttr>(
Callee->getFunctionObjectParameterType()) &&
- !isRecordWithAttr<OwnerAttr>(Callee->getFunctionObjectParameterType()))
+ !Sema::isRecordWithAttr<OwnerAttr>(
+ Callee->getFunctionObjectParameterType()))
return false;
- if (isPointerLikeType(Callee->getReturnType())) {
+ if (Sema::isPointerLikeType(Callee->getReturnType())) {
if (!Callee->getIdentifier())
return false;
return llvm::StringSwitch<bool>(Callee->getName())
@@ -366,7 +353,7 @@ static bool shouldTrackFirstArgument(const FunctionDecl *FD) {
if (!RD->hasAttr<PointerAttr>() && !RD->hasAttr<OwnerAttr>())
return false;
if (FD->getReturnType()->isPointerType() ||
- isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
+ Sema::isRecordWithAttr<PointerAttr>(FD->getReturnType())) {
return llvm::StringSwitch<bool>(FD->getName())
.Cases("begin", "rbegin", "cbegin", "crbegin", true)
.Cases("end", "rend", "cend", "crend", true)
@@ -438,7 +425,7 @@ shouldTrackFirstArgumentForConstructor(const CXXConstructExpr *Ctor) {
return true;
// RHS must be an owner.
- if (!isRecordWithAttr<OwnerAttr>(RHSArgType))
+ if (!Sema::isRecordWithAttr<OwnerAttr>(RHSArgType))
return false;
// Bail out if the RHS is Owner<Pointer>.
@@ -565,7 +552,7 @@ static void visitFunctionCallArguments(IndirectLocalPath &Path, Expr *Call,
// Once we initialized a value with a non gsl-owner reference, it can no
// longer dangle.
if (ReturnType->isReferenceType() &&
- !isRecordWithAttr<OwnerAttr>(ReturnType->getPointeeType())) {
+ !Sema::isRecordWithAttr<OwnerAttr>(ReturnType->getPointeeType())) {
for (const IndirectLocalPathEntry &PE : llvm::reverse(Path)) {
if (PE.Kind == IndirectLocalPathEntry::GslReferenceInit ||
PE.Kind == IndirectLocalPathEntry::LifetimeBoundCall)
@@ -1111,7 +1098,7 @@ static bool shouldRunGSLAssignmentAnalysis(const Sema &SemaRef,
bool EnableGSLAssignmentWarnings = !SemaRef.getDiagnostics().isIgnored(
diag::warn_dangling_lifetime_pointer_assignment, SourceLocation());
return (EnableGSLAssignmentWarnings &&
- (isRecordWithAttr<PointerAttr>(Entity.LHS->getType()) ||
+ (Sema::isRecordWithAttr<PointerAttr>(Entity.LHS->getType()) ||
isAssignmentOperatorLifetimeBound(Entity.AssignmentOperator)));
}
@@ -1146,12 +1133,12 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
// someContainer.add(std::move(localUniquePtr));
// return p;
if (pathContainsInit(Path) ||
- !isRecordWithAttr<OwnerAttr>(L->getType()))
+ !Sema::isRecordWithAttr<OwnerAttr>(L->getType()))
return false;
} else {
IsGslPtrValueFromGslTempOwner =
MTE && !MTE->getExtendingDecl() &&
- isRecordWithAttr<OwnerAttr>(MTE->getType());
+ Sema::isRecordWithAttr<OwnerAttr>(MTE->getType());
// Skipping a chain of initializing gsl::Pointer annotated objects.
// We are looking only for the final source to find out if it was
// a local or temporary owner or the address of a local variable/param.
@@ -1280,7 +1267,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
auto *DRE = dyn_cast<DeclRefExpr>(L);
// Suppress false positives for code like the one below:
// Ctor(unique_ptr<T> up) : pointer(up.get()), owner(move(up)) {}
- if (DRE && isRecordWithAttr<OwnerAttr>(DRE->getType()))
+ if (DRE && Sema::isRecordWithAttr<OwnerAttr>(DRE->getType()))
return false;
auto *VD = DRE ? dyn_cast<VarDecl>(DRE->getDecl()) : nullptr;
@@ -1441,7 +1428,7 @@ checkExprLifetimeImpl(Sema &SemaRef, const InitializedEntity *InitEntity,
break;
}
case LK_LifetimeCapture: {
- if (isPointerLikeType(Init->getType()))
+ if (Sema::isPointerLikeType(Init->getType()))
Path.push_back({IndirectLocalPathEntry::GslPointerInit, Init});
break;
}
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index 9fbad7ed67ccbe..9d21a01cd1b186 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -215,6 +215,11 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
inferGslPointerAttribute(Record, Record);
}
+bool Sema::isPointerLikeType(QualType Type) {
+ return isRecordWithAttr<PointerAttr>(Type) || Type->isPointerType() ||
+ Type->isNullPtrType();
+}
+
void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
if (FD->getNumParams() == 0)
return;
More information about the cfe-commits
mailing list