Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -298,6 +298,9 @@ // Set to true if this attribute can be duplicated on a subject when merging // attributes. By default, attributes are not merged. bit DuplicatesAllowedWhileMerging = 0; + // Set to true if this attribute should apply to template declaration, + // remains false if this should only be applied on definition. + bit AppliesToTemplateDeclaration = 0; // Lists language options, one of which is required to be true for the // attribute to be applicable. If empty, no language options are required. list LangOpts = []; @@ -765,6 +768,7 @@ // Fix-It. StringArgument<"Replacement", 1>]; let Documentation = [DeprecatedDocs]; + let AppliesToTemplateDeclaration = 1; } def Destructor : InheritableAttr { Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -7385,6 +7385,11 @@ LateInstantiatedAttrVec *LateAttrs = nullptr, LocalInstantiationScope *OuterMostScope = nullptr); + void InstantiateAttrsForDecl(const MultiLevelTemplateArgumentList &TemplateArgs, + const Decl *Pattern, Decl *Inst, + LateInstantiatedAttrVec *LateAttrs = nullptr, + LocalInstantiationScope *OuterMostScope = nullptr); + bool InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation, ClassTemplateSpecializationDecl *ClassTemplateSpec, Index: lib/Sema/SemaTemplate.cpp =================================================================== --- lib/Sema/SemaTemplate.cpp +++ lib/Sema/SemaTemplate.cpp @@ -2401,6 +2401,10 @@ ClassTemplate->getLocation(), ClassTemplate, Converted, nullptr); + MultiLevelTemplateArgumentList TemplateArgLists; + TemplateArgLists.addOuterTemplateArguments(Converted); + InstantiateAttrsForDecl(TemplateArgLists, + ClassTemplate->getTemplatedDecl(), Decl); ClassTemplate->AddSpecialization(Decl, InsertPos); if (ClassTemplate->isOutOfLine()) Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext()); Index: lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiate.cpp +++ lib/Sema/SemaTemplateInstantiate.cpp @@ -1882,6 +1882,8 @@ namespace sema { Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, Sema &S, const MultiLevelTemplateArgumentList &TemplateArgs); + Attr *instantiateTemplateAttributeForDecl(const Attr *At, ASTContext &C, Sema &S, + const MultiLevelTemplateArgumentList &TemplateArgs); } } Index: lib/Sema/SemaTemplateInstantiateDecl.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiateDecl.cpp +++ lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -308,6 +308,26 @@ Attr.getRange()); } +void Sema::InstantiateAttrsForDecl( + const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl, + Decl *New, LateInstantiatedAttrVec *LateAttrs, + LocalInstantiationScope *OuterMostScope) { + for (const auto *TmplAttr : Tmpl->attrs()) { + // FIXME: If any of the special case versions from InstantiateAttrs become + // applicable to template declaration, we'll need to add them here. + NamedDecl *ND = dyn_cast(New); + CXXRecordDecl *ThisContext = + dyn_cast_or_null(ND->getDeclContext()); + CXXThisScopeRAII ThisScope(*this, ThisContext, /*TypeQuals*/ 0, + ND && ND->isCXXInstanceMember()); + + Attr *NewAttr = sema::instantiateTemplateAttributeForDecl(TmplAttr, Context, *this, + TemplateArgs); + if (NewAttr) + New->addAttr(NewAttr); + } +} + void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl, Decl *New, LateInstantiatedAttrVec *LateAttrs, @@ -945,6 +965,7 @@ } } + SemaRef.InstantiateAttrsForDecl(TemplateArgs, D, Enum); SemaRef.InstantiateAttrs(TemplateArgs, D, Enum); Enum->setInstantiationOfMemberEnum(D, TSK_ImplicitInstantiation); @@ -1033,6 +1054,7 @@ } if (EnumConst) { + SemaRef.InstantiateAttrsForDecl(TemplateArgs, EC, EnumConst); SemaRef.InstantiateAttrs(TemplateArgs, EC, EnumConst); EnumConst->setAccess(Enum->getAccess()); Index: test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp =================================================================== --- test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp +++ test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp @@ -23,7 +23,8 @@ X x1; X x2; // expected-warning {{'X' is deprecated}} -template class [[deprecated]] X2 {}; +template class [[deprecated]] X2 {}; //expected-note {{'X2' has been explicitly marked deprecated here}} template <> class X2 {}; -X2 x3; // FIXME: no warning! -X2 x4; +X2 x3; // expected-warning {{'X2' is deprecated}} +X2 x4; // No warning, the specialization removes it. + Index: utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2452,18 +2452,9 @@ OS << "#endif // ATTR_VISITOR_DECLS_ONLY\n"; } -// Emits code to instantiate dependent attributes on templates. -void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) { - emitSourceFileHeader("Template instantiation code for attributes", OS); - - std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); - - OS << "namespace clang {\n" - << "namespace sema {\n\n" - << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, " - << "Sema &S,\n" - << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n" - << " switch (At->getKind()) {\n"; +void EmitClangAttrTemplateInstantiateHelper(const std::vector &Attrs, + raw_ostream &OS, bool DeclTime) { + OS << " switch (At->getKind()) {\n"; for (const auto *Attr : Attrs) { const Record &R = *Attr; @@ -2471,7 +2462,10 @@ continue; OS << " case attr::" << R.getName() << ": {\n"; - bool ShouldClone = R.getValueAsBit("Clone"); + + bool ShouldClone = + R.getValueAsBit("Clone") && + R.getValueAsBit("AppliesToTemplateDeclaration") == DeclTime; if (!ShouldClone) { OS << " return nullptr;\n"; @@ -2508,8 +2502,27 @@ } OS << " } // end switch\n" << " llvm_unreachable(\"Unknown attribute!\");\n" - << " return nullptr;\n" - << "}\n\n" + << " return nullptr;\n"; +} +// Emits code to instantiate dependent attributes on templates. +void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) { + emitSourceFileHeader("Template instantiation code for attributes", OS); + + std::vector Attrs = Records.getAllDerivedDefinitions("Attr"); + + OS << "namespace clang {\n" + << "namespace sema {\n\n" + << "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, " + << "Sema &S,\n" + << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n"; + EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*DeclTime=*/false); + OS << "}\n\n" + << "Attr *instantiateTemplateAttributeForDecl(const Attr *At,\n" + << " ASTContext &C, Sema &S,\n" + << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n"; + EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*DeclTime=*/true); + + OS << "}\n\n" << "} // end namespace sema\n" << "} // end namespace clang\n"; }