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 _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits