diff --git a/clang/lib/Sema/SemaAttr.cpp b/clang/lib/Sema/SemaAttr.cpp --- a/clang/lib/Sema/SemaAttr.cpp +++ b/clang/lib/Sema/SemaAttr.cpp @@ -88,13 +88,20 @@ template static void addGslOwnerPointerAttributeIfNotExisting(ASTContext &Context, CXXRecordDecl *Record) { - CXXRecordDecl *Canonical = Record->getCanonicalDecl(); - if (Canonical->hasAttr() || Canonical->hasAttr()) + if (Record->hasAttr() || Record->hasAttr()) return; - Canonical->addAttr(::new (Context) Attribute(SourceRange{}, Context, - /*DerefType*/ nullptr, - /*Spelling=*/0)); + Record->addAttr(::new (Context) Attribute(SourceRange{}, Context, + /*DerefType*/ nullptr, + /*Spelling=*/0)); + + // Put the attribute on the definition of a class template, so it is used + // during instantiation. + if (auto *Templ = + dyn_cast_or_null(Record->getDescribedTemplate())) { + if (auto *Def = Record->getDefinition()) + addGslOwnerPointerAttributeIfNotExisting(Context, Def); + } } void Sema::inferGslPointerAttribute(NamedDecl *ND, @@ -132,8 +139,8 @@ if (Parent->isInStdNamespace() && Iterators.count(ND->getName()) && Containers.count(Parent->getName())) - addGslOwnerPointerAttributeIfNotExisting(Context, - UnderlyingRecord); + addGslOwnerPointerAttributeIfNotExisting( + Context, UnderlyingRecord->getCanonicalDecl()); } void Sema::inferGslPointerAttribute(TypedefNameDecl *TD) { @@ -194,9 +201,9 @@ return; if (StdOwners.count(Record->getName())) - addGslOwnerPointerAttributeIfNotExisting(Context, Record); + addGslOwnerPointerAttributeIfNotExisting(Context, Canonical); else if (StdPointers.count(Record->getName())) - addGslOwnerPointerAttributeIfNotExisting(Context, Record); + addGslOwnerPointerAttributeIfNotExisting(Context, Canonical); return; } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -552,6 +552,18 @@ continue; } + if (auto *A = dyn_cast(TmplAttr)) { + if (!New->hasAttr()) + New->addAttr(A->clone(Context)); + continue; + } + + if (auto *A = dyn_cast(TmplAttr)) { + if (!New->hasAttr()) + 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 @@ SemaRef.InstantiateAttrs(TemplateArgs, D, Typedef); + if (D->getUnderlyingType()->getAs()) + 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 --- a/clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp +++ b/clang/test/SemaCXX/attr-gsl-owner-pointer-std.cpp @@ -92,6 +92,59 @@ static_assert(sizeof(unordered_map::iterator), ""); // Force instantiation. } // namespace inlinens +// The iterator typedef is a DependentNameType. +template +class __unordered_multimap_iterator {}; +// CHECK: ClassTemplateDecl {{.*}} __unordered_multimap_iterator +// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_multimap_iterator +// CHECK: TemplateArgument type 'int' +// CHECK: PointerAttr + +template +class __unordered_multimap_base { +public: + using iterator = __unordered_multimap_iterator; +}; + +template +class unordered_multimap { + // CHECK: ClassTemplateDecl {{.*}} unordered_multimap + // CHECK: OwnerAttr {{.*}} + // CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_multimap + // CHECK: OwnerAttr {{.*}} +public: + using _Mybase = __unordered_multimap_base; + using iterator = typename _Mybase::iterator; +}; +static_assert(sizeof(unordered_multimap::iterator), ""); // Force instantiation. + +// The canonical declaration of the iterator template is not its definition. +template +class __unordered_multiset_iterator; +// CHECK: ClassTemplateDecl {{.*}} __unordered_multiset_iterator +// CHECK: PointerAttr +// CHECK: ClassTemplateSpecializationDecl {{.*}} __unordered_multiset_iterator +// CHECK: TemplateArgument type 'int' +// CHECK: PointerAttr + +template +class __unordered_multiset_iterator { + // CHECK: ClassTemplateDecl {{.*}} prev {{.*}} __unordered_multiset_iterator + // CHECK: PointerAttr +}; + +template +class unordered_multiset { + // CHECK: ClassTemplateDecl {{.*}} unordered_multiset + // CHECK: OwnerAttr {{.*}} + // CHECK: ClassTemplateSpecializationDecl {{.*}} unordered_multiset + // CHECK: OwnerAttr {{.*}} +public: + using iterator = __unordered_multiset_iterator; +}; + +static_assert(sizeof(unordered_multiset::iterator), ""); // Force instantiation. + // std::list has an implicit gsl::Owner attribute, // but explicit attributes take precedence. template