diff options
-rw-r--r-- | clang/lib/Sema/SemaAttr.cpp | 11 | ||||
-rw-r--r-- | clang/lib/Sema/SemaDeclAttr.cpp | 16 | ||||
-rw-r--r-- | clang/lib/Sema/SemaInit.cpp | 4 | ||||
-rw-r--r-- | clang/lib/Sema/SemaTemplateInstantiateDecl.cpp | 15 | ||||
-rw-r--r-- | clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp | 53 | ||||
-rw-r--r-- | clang/test/SemaCXX/attr-gsl-owner-pointer.cpp | 17 | ||||
-rw-r--r-- | clang/unittests/Sema/CMakeLists.txt | 2 | ||||
-rw-r--r-- | clang/unittests/Sema/GslOwnerPointerInference.cpp | 61 |
8 files changed, 164 insertions, 15 deletions
diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp index e2542edf6ed..23cb47481f3 100644 --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -88,13 +88,11 @@ void Sema::AddMsStructLayoutForRecord(RecordDecl *RD) { template <typename Attribute> static void addGslOwnerPointerAttributeIfNotExisting(ASTContext &Context, CXXRecordDecl *Record) { - CXXRecordDecl *Canonical = Record->getCanonicalDecl(); - if (Canonical->hasAttr<OwnerAttr>() || Canonical->hasAttr<PointerAttr>()) + if (Record->hasAttr<OwnerAttr>() || Record->hasAttr<PointerAttr>()) return; - Canonical->addAttr(::new (Context) Attribute(SourceRange{}, Context, - /*DerefType*/ nullptr, - /*Spelling=*/0)); + for (Decl *Redecl : Record->redecls()) + Redecl->addAttr(Attribute::CreateImplicit(Context, /*DerefType=*/nullptr)); } void Sema::inferGslPointerAttribute(NamedDecl *ND, @@ -189,8 +187,7 @@ void Sema::inferGslOwnerPointerAttribute(CXXRecordDecl *Record) { // Handle classes that directly appear in std namespace. if (Record->isInStdNamespace()) { - CXXRecordDecl *Canonical = Record->getCanonicalDecl(); - if (Canonical->hasAttr<OwnerAttr>() || Canonical->hasAttr<PointerAttr>()) + if (Record->hasAttr<OwnerAttr>() || Record->hasAttr<PointerAttr>()) return; if (StdOwners.count(Record->getName())) diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 2a72f7d5c61..b694c058a3a 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -4592,9 +4592,11 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } return; } - D->addAttr(::new (S.Context) - OwnerAttr(AL.getRange(), S.Context, DerefTypeLoc, - AL.getAttributeSpellingListIndex())); + for (Decl *Redecl : D->redecls()) { + Redecl->addAttr(::new (S.Context) + OwnerAttr(AL.getRange(), S.Context, DerefTypeLoc, + AL.getAttributeSpellingListIndex())); + } } else { if (checkAttrMutualExclusion<OwnerAttr>(S, D, AL)) return; @@ -4609,9 +4611,11 @@ static void handleLifetimeCategoryAttr(Sema &S, Decl *D, const ParsedAttr &AL) { } return; } - D->addAttr(::new (S.Context) - PointerAttr(AL.getRange(), S.Context, DerefTypeLoc, - AL.getAttributeSpellingListIndex())); + for (Decl *Redecl : D->redecls()) { + Redecl->addAttr(::new (S.Context) + PointerAttr(AL.getRange(), S.Context, DerefTypeLoc, + AL.getAttributeSpellingListIndex())); + } } } diff --git a/clang/lib/Sema/SemaInit.cpp b/clang/lib/Sema/SemaInit.cpp index 289a1403cd8..ee9963fca77 100644 --- a/clang/lib/Sema/SemaInit.cpp +++ b/clang/lib/Sema/SemaInit.cpp @@ -6561,7 +6561,7 @@ static void visitLocalsRetainedByReferenceBinding(IndirectLocalPath &Path, template <typename T> static bool isRecordWithAttr(QualType Type) { if (auto *RD = Type->getAsCXXRecordDecl()) - return RD->getCanonicalDecl()->hasAttr<T>(); + return RD->hasAttr<T>(); return false; } @@ -6672,7 +6672,7 @@ static void handleGslAnnotatedTypes(IndirectLocalPath &Path, Expr *Call, if (auto *CCE = dyn_cast<CXXConstructExpr>(Call)) { const auto *Ctor = CCE->getConstructor(); - const CXXRecordDecl *RD = Ctor->getParent()->getCanonicalDecl(); + const CXXRecordDecl *RD = Ctor->getParent(); if (CCE->getNumArgs() > 0 && RD->hasAttr<PointerAttr>()) VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0]); } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index 25d0db80398..2e76dc1a584 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -552,6 +552,18 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, continue; } + if (auto *A = dyn_cast<PointerAttr>(TmplAttr)) { + if (!New->hasAttr<PointerAttr>()) + New->addAttr(A->clone(Context)); + continue; + } + + if (auto *A = dyn_cast<OwnerAttr>(TmplAttr)) { + if (!New->hasAttr<OwnerAttr>()) + New->addAttr(A->clone(Context)); + continue; + } + assert(!TmplAttr->isPackExpansion()); if (TmplAttr->isLateParsed() && LateAttrs) { // Late parsed attributes must be instantiated and attached after the @@ -711,6 +723,9 @@ Decl *TemplateDeclInstantiator::InstantiateTypedefNameDecl(TypedefNameDecl *D, SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef); + if (D->getUnderlyingType()->getAs<DependentNameType>()) + SemaRef.inferGslPointerAttribute(Typedef); + Typedef->setAccess(D->getAccess()); return Typedef; diff --git a/clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp b/clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp index 29675c2ac7e..352e1e47358 100644 --- a/clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp +++ b/clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp @@ -92,6 +92,59 @@ public: static_assert(sizeof(unordered_map<int>::iterator), ""); // Force instantiation. } // namespace inlinens +// The iterator typedef is a DependentNameType. +template <typename T> +class __unordered_multimap_iterator {}; +// CHECK: ClassTemplateDecl {{.*}} __unordered_multimap_iterator +// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_multimap_iterator +// CHECK: TemplateArgument type 'int' +// CHECK: PointerAttr + +template <typename T> +class __unordered_multimap_base { +public: + using iterator = __unordered_multimap_iterator<T>; +}; + +template <typename T> +class unordered_multimap { + // CHECK: ClassTemplateDecl {{.*}} unordered_multimap + // CHECK: OwnerAttr {{.*}} + // CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_multimap + // CHECK: OwnerAttr {{.*}} +public: + using _Mybase = __unordered_multimap_base<T>; + using iterator = typename _Mybase::iterator; +}; +static_assert(sizeof(unordered_multimap<int>::iterator), ""); // Force instantiation. + +// The canonical declaration of the iterator template is not its definition. +template <typename T> +class __unordered_multiset_iterator; +// CHECK: ClassTemplateDecl {{.*}} __unordered_multiset_iterator +// CHECK: PointerAttr +// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_multiset_iterator +// CHECK: TemplateArgument type 'int' +// CHECK: PointerAttr + +template <typename T> +class __unordered_multiset_iterator { + // CHECK: ClassTemplateDecl {{.*}} prev {{.*}} __unordered_multiset_iterator + // CHECK: PointerAttr +}; + +template <typename T> +class unordered_multiset { + // CHECK: ClassTemplateDecl {{.*}} unordered_multiset + // CHECK: OwnerAttr {{.*}} + // CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_multiset + // CHECK: OwnerAttr {{.*}} +public: + using iterator = __unordered_multiset_iterator<T>; +}; + +static_assert(sizeof(unordered_multiset<int>::iterator), ""); // Force instantiation. + // std::list has an implicit gsl::Owner attribute, // but explicit attributes take precedence. template <typename T> diff --git a/clang/test/SemaCXX/attr-gsl-owner-pointer.cpp b/clang/test/SemaCXX/attr-gsl-owner-pointer.cpp index 1c3deb3982e..5b438822ba2 100644 --- a/clang/test/SemaCXX/attr-gsl-owner-pointer.cpp +++ b/clang/test/SemaCXX/attr-gsl-owner-pointer.cpp @@ -105,3 +105,20 @@ class [[gsl::Owner(int)]] AddTheSameLater{}; class [[gsl::Owner(int)]] AddTheSameLater; // CHECK: CXXRecordDecl {{.*}} prev {{.*}} AddTheSameLater // CHECK: OwnerAttr {{.*}} int + +template <class T> +class [[gsl::Owner]] ForwardDeclared; +// CHECK: ClassTemplateDecl {{.*}} ForwardDeclared +// CHECK: OwnerAttr {{.*}} +// CHECK: ClassTemplateSpecializationDecl {{.*}} ForwardDeclared +// CHECK: TemplateArgument type 'int' +// CHECK: OwnerAttr {{.*}} + +template <class T> +class [[gsl::Owner]] ForwardDeclared { +// CHECK: ClassTemplateDecl {{.*}} ForwardDeclared +// CHECK: CXXRecordDecl {{.*}} ForwardDeclared definition +// CHECK: OwnerAttr {{.*}} +}; + +static_assert(sizeof(ForwardDeclared<int>), ""); // Force instantiation. diff --git a/clang/unittests/Sema/CMakeLists.txt b/clang/unittests/Sema/CMakeLists.txt index 51e8d6c5b43..6832908e7fb 100644 --- a/clang/unittests/Sema/CMakeLists.txt +++ b/clang/unittests/Sema/CMakeLists.txt @@ -5,11 +5,13 @@ set(LLVM_LINK_COMPONENTS add_clang_unittest(SemaTests ExternalSemaSourceTest.cpp CodeCompleteTest.cpp + GslOwnerPointerInference.cpp ) clang_target_link_libraries(SemaTests PRIVATE clangAST + clangASTMatchers clangBasic clangFrontend clangParse diff --git a/clang/unittests/Sema/GslOwnerPointerInference.cpp b/clang/unittests/Sema/GslOwnerPointerInference.cpp new file mode 100644 index 00000000000..e340ccb4127 --- /dev/null +++ b/clang/unittests/Sema/GslOwnerPointerInference.cpp @@ -0,0 +1,61 @@ +//== unittests/Sema/GslOwnerPointerInference.cpp - gsl::Owner/Pointer ========// +// +// Part of the LLVM Project, under the Apache License v2.0 with LLVM Exceptions. +// See https://llvm.org/LICENSE.txt for license information. +// SPDX-License-Identifier: Apache-2.0 WITH LLVM-exception +// +//===----------------------------------------------------------------------===// + +#include "../ASTMatchers/ASTMatchersTest.h" +#include "clang/ASTMatchers/ASTMatchers.h" +#include "gtest/gtest.h" + +namespace clang { +using namespace ast_matchers; + +TEST(OwnerPointer, BothHaveAttributes) { + EXPECT_TRUE(matches( + R"cpp( + template<class T> + class [[gsl::Owner]] C; + + template<class T> + class [[gsl::Owner]] C {}; + + C<int> c; + )cpp", + classTemplateSpecializationDecl(hasName("C"), hasAttr(clang::attr::Owner)))); +} + +TEST(OwnerPointer, ForwardDeclOnly) { + EXPECT_TRUE(matches( + R"cpp( + template<class T> + class [[gsl::Owner]] C; + + template<class T> + class C {}; + + C<int> c; + )cpp", + classTemplateSpecializationDecl(hasName("C"), hasAttr(clang::attr::Owner)))); +} + +TEST(OwnerPointer, LateForwardDeclOnly) { + EXPECT_TRUE(matches( + R"cpp( + template<class T> + class C; + + template<class T> + class C {}; + + template<class T> + class [[gsl::Owner]] C; + + C<int> c; + )cpp", + classTemplateSpecializationDecl(hasName("C"), hasAttr(clang::attr::Owner)))); +} + +} // namespace clang |