Index: cfe/trunk/lib/Sema/SemaAttr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaAttr.cpp +++ cfe/trunk/lib/Sema/SemaAttr.cpp @@ -88,13 +88,11 @@ 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)); + for (Decl *Redecl : Record->redecls()) + Redecl->addAttr(Attribute::CreateImplicit(Context, /*DerefType=*/nullptr)); } void Sema::inferGslPointerAttribute(NamedDecl *ND, @@ -189,8 +187,7 @@ // Handle classes that directly appear in std namespace. if (Record->isInStdNamespace()) { - CXXRecordDecl *Canonical = Record->getCanonicalDecl(); - if (Canonical->hasAttr() || Canonical->hasAttr()) + if (Record->hasAttr() || Record->hasAttr()) return; if (StdOwners.count(Record->getName())) Index: cfe/trunk/lib/Sema/SemaDeclAttr.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaDeclAttr.cpp +++ cfe/trunk/lib/Sema/SemaDeclAttr.cpp @@ -4592,9 +4592,11 @@ } 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(S, D, AL)) return; @@ -4609,9 +4611,11 @@ } 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())); + } } } Index: cfe/trunk/lib/Sema/SemaInit.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaInit.cpp +++ cfe/trunk/lib/Sema/SemaInit.cpp @@ -6561,7 +6561,7 @@ template static bool isRecordWithAttr(QualType Type) { if (auto *RD = Type->getAsCXXRecordDecl()) - return RD->getCanonicalDecl()->hasAttr(); + return RD->hasAttr(); return false; } @@ -6672,7 +6672,7 @@ if (auto *CCE = dyn_cast(Call)) { const auto *Ctor = CCE->getConstructor(); - const CXXRecordDecl *RD = Ctor->getParent()->getCanonicalDecl(); + const CXXRecordDecl *RD = Ctor->getParent(); if (CCE->getNumArgs() > 0 && RD->hasAttr()) VisitPointerArg(Ctor->getParamDecl(0), CCE->getArgs()[0]); } Index: cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- cfe/trunk/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ cfe/trunk/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; Index: cfe/trunk/test/SemaCXX/attr-gsl-owner-pointer-std.cpp =================================================================== --- cfe/trunk/test/SemaCXX/attr-gsl-owner-pointer-std.cpp +++ cfe/trunk/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 Index: cfe/trunk/test/SemaCXX/attr-gsl-owner-pointer.cpp =================================================================== --- cfe/trunk/test/SemaCXX/attr-gsl-owner-pointer.cpp +++ cfe/trunk/test/SemaCXX/attr-gsl-owner-pointer.cpp @@ -105,3 +105,20 @@ class [[gsl::Owner(int)]] AddTheSameLater; // CHECK: CXXRecordDecl {{.*}} prev {{.*}} AddTheSameLater // CHECK: OwnerAttr {{.*}} int + +template +class [[gsl::Owner]] ForwardDeclared; +// CHECK: ClassTemplateDecl {{.*}} ForwardDeclared +// CHECK: OwnerAttr {{.*}} +// CHECK: ClassTemplateSpecializationDecl {{.*}} ForwardDeclared +// CHECK: TemplateArgument type 'int' +// CHECK: OwnerAttr {{.*}} + +template +class [[gsl::Owner]] ForwardDeclared { +// CHECK: ClassTemplateDecl {{.*}} ForwardDeclared +// CHECK: CXXRecordDecl {{.*}} ForwardDeclared definition +// CHECK: OwnerAttr {{.*}} +}; + +static_assert(sizeof(ForwardDeclared), ""); // Force instantiation. Index: cfe/trunk/unittests/Sema/CMakeLists.txt =================================================================== --- cfe/trunk/unittests/Sema/CMakeLists.txt +++ cfe/trunk/unittests/Sema/CMakeLists.txt @@ -5,11 +5,13 @@ add_clang_unittest(SemaTests ExternalSemaSourceTest.cpp CodeCompleteTest.cpp + GslOwnerPointerInference.cpp ) clang_target_link_libraries(SemaTests PRIVATE clangAST + clangASTMatchers clangBasic clangFrontend clangParse Index: cfe/trunk/unittests/Sema/GslOwnerPointerInference.cpp =================================================================== --- cfe/trunk/unittests/Sema/GslOwnerPointerInference.cpp +++ cfe/trunk/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 [[gsl::Owner]] C; + + template + class [[gsl::Owner]] C {}; + + C c; + )cpp", + classTemplateSpecializationDecl(hasName("C"), hasAttr(clang::attr::Owner)))); +} + +TEST(OwnerPointer, ForwardDeclOnly) { + EXPECT_TRUE(matches( + R"cpp( + template + class [[gsl::Owner]] C; + + template + class C {}; + + C c; + )cpp", + classTemplateSpecializationDecl(hasName("C"), hasAttr(clang::attr::Owner)))); +} + +TEST(OwnerPointer, LateForwardDeclOnly) { + EXPECT_TRUE(matches( + R"cpp( + template + class C; + + template + class C {}; + + template + class [[gsl::Owner]] C; + + C c; + )cpp", + classTemplateSpecializationDecl(hasName("C"), hasAttr(clang::attr::Owner)))); +} + +} // namespace clang