[clang] 902b2a2 - [clang] Add lifetimebound attr to std::span/std::string_view constructor (#103716)
via cfe-commits
cfe-commits at lists.llvm.org
Wed Aug 28 01:50:21 PDT 2024
Author: Haojian Wu
Date: 2024-08-28T10:50:17+02:00
New Revision: 902b2a26ab9e1e78dfb66b52fba4512c91472e09
URL: https://github.com/llvm/llvm-project/commit/902b2a26ab9e1e78dfb66b52fba4512c91472e09
DIFF: https://github.com/llvm/llvm-project/commit/902b2a26ab9e1e78dfb66b52fba4512c91472e09.diff
LOG: [clang] Add lifetimebound attr to std::span/std::string_view constructor (#103716)
With this patch, clang now automatically adds
``[[clang::lifetimebound]]`` to the parameters of `std::span,
std::string_view` constructors, this enables Clang to capture more cases
where the returned reference outlives the object.
Fixes #100567
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Sema/Sema.h
clang/lib/Sema/SemaAttr.cpp
clang/lib/Sema/SemaDecl.cpp
clang/test/SemaCXX/attr-lifetimebound.cpp
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d9fa068c2910f4..4289b3374a810b 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -220,6 +220,11 @@ Attribute Changes in Clang
- ``[[clang::lifetimebound]]`` is now explicitly disallowed on explicit object member functions
where they were previously silently ignored.
+- Clang now automatically adds ``[[clang::lifetimebound]]`` to the parameters of
+ ``std::span, std::string_view`` constructors, this enables Clang to capture
+ more cases where the returned reference outlives the object.
+ (#GH100567)
+
Improvements to Clang's diagnostics
-----------------------------------
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 1f7e555d1b8717..ed1c279fefe29c 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -1806,6 +1806,9 @@ class Sema final : public SemaBase {
/// Add [[gsl::Owner]] and [[gsl::Pointer]] attributes for std:: types.
void inferGslOwnerPointerAttribute(CXXRecordDecl *Record);
+ /// Add [[clang:::lifetimebound]] attr for std:: functions and methods.
+ void inferLifetimeBoundAttribute(FunctionDecl *FD);
+
/// Add [[gsl::Pointer]] attributes for std:: types.
void inferGslPointerAttribute(TypedefNameDecl *TD);
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp
index a1724820472b59..fb594e6f13c0b3 100644
--- a/clang/lib/Sema/SemaAttr.cpp
+++ b/clang/lib/Sema/SemaAttr.cpp
@@ -216,6 +216,59 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) {
inferGslPointerAttribute(Record, Record);
}
+void Sema::inferLifetimeBoundAttribute(FunctionDecl *FD) {
+ if (FD->getNumParams() == 0)
+ return;
+
+ if (unsigned BuiltinID = FD->getBuiltinID()) {
+ // Add lifetime attribute to std::move, std::fowrard et al.
+ switch (BuiltinID) {
+ case Builtin::BIaddressof:
+ case Builtin::BI__addressof:
+ case Builtin::BI__builtin_addressof:
+ case Builtin::BIas_const:
+ case Builtin::BIforward:
+ case Builtin::BIforward_like:
+ case Builtin::BImove:
+ case Builtin::BImove_if_noexcept:
+ if (ParmVarDecl *P = FD->getParamDecl(0u);
+ !P->hasAttr<LifetimeBoundAttr>())
+ P->addAttr(
+ LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
+ break;
+ default:
+ break;
+ }
+ return;
+ }
+ if (auto *CMD = dyn_cast<CXXMethodDecl>(FD)) {
+ const auto *CRD = CMD->getParent();
+ if (!CRD->isInStdNamespace() || !CRD->getIdentifier())
+ return;
+
+ if (isa<CXXConstructorDecl>(CMD)) {
+ auto *Param = CMD->getParamDecl(0);
+ if (Param->hasAttr<LifetimeBoundAttr>())
+ return;
+ if (CRD->getName() == "basic_string_view" &&
+ Param->getType()->isPointerType()) {
+ // construct from a char array pointed by a pointer.
+ // basic_string_view(const CharT* s);
+ // basic_string_view(const CharT* s, size_type count);
+ Param->addAttr(
+ LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
+ } else if (CRD->getName() == "span") {
+ // construct from a reference of array.
+ // span(std::type_identity_t<element_type> (&arr)[N]);
+ const auto *LRT = Param->getType()->getAs<LValueReferenceType>();
+ if (LRT && LRT->getPointeeType().IgnoreParens()->isArrayType())
+ Param->addAttr(
+ LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
+ }
+ }
+ }
+}
+
void Sema::inferNullableClassAttribute(CXXRecordDecl *CRD) {
static const llvm::StringSet<> Nullable{
"auto_ptr", "shared_ptr", "unique_ptr", "exception_ptr",
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp
index b0ccbbe34b70c3..4efa80778e71b9 100644
--- a/clang/lib/Sema/SemaDecl.cpp
+++ b/clang/lib/Sema/SemaDecl.cpp
@@ -16608,27 +16608,9 @@ void Sema::AddKnownFunctionAttributes(FunctionDecl *FD) {
default:
break;
}
-
- // Add lifetime attribute to std::move, std::fowrard et al.
- switch (BuiltinID) {
- case Builtin::BIaddressof:
- case Builtin::BI__addressof:
- case Builtin::BI__builtin_addressof:
- case Builtin::BIas_const:
- case Builtin::BIforward:
- case Builtin::BIforward_like:
- case Builtin::BImove:
- case Builtin::BImove_if_noexcept:
- if (ParmVarDecl *P = FD->getParamDecl(0u);
- !P->hasAttr<LifetimeBoundAttr>())
- P->addAttr(
- LifetimeBoundAttr::CreateImplicit(Context, FD->getLocation()));
- break;
- default:
- break;
- }
}
+ inferLifetimeBoundAttribute(FD);
AddKnownFunctionAttributesForReplaceableGlobalAllocationFunction(FD);
// If C++ exceptions are enabled but we are told extern "C" functions cannot
diff --git a/clang/test/SemaCXX/attr-lifetimebound.cpp b/clang/test/SemaCXX/attr-lifetimebound.cpp
index f4ca840cb276f9..6566ed6270cd14 100644
--- a/clang/test/SemaCXX/attr-lifetimebound.cpp
+++ b/clang/test/SemaCXX/attr-lifetimebound.cpp
@@ -238,6 +238,16 @@ template <class T> T *addressof(T &arg) {
&const_cast<char &>(reinterpret_cast<const volatile char &>(arg)));
}
+template<typename T>
+struct basic_string_view {
+ basic_string_view(const T *);
+};
+
+template <class T> struct span {
+ template<size_t _ArrayExtent>
+ span(const T (&__arr)[_ArrayExtent]) noexcept;
+};
+
} // namespace foo
} // namespace std
@@ -266,3 +276,14 @@ namespace move_forward_et_al_examples {
S *AddressOfOk = std::addressof(X);
} // namespace move_forward_et_al_examples
+namespace ctor_cases {
+std::basic_string_view<char> test1() {
+ char abc[10];
+ return abc; // expected-warning {{address of stack memory associated with local variable}}
+}
+
+std::span<int> test2() {
+ int abc[10];
+ return abc; // expected-warning {{address of stack memory associated with local variable}}
+}
+} // namespace ctor_cases
More information about the cfe-commits
mailing list