Index: include/clang/Basic/Attr.td =================================================================== --- include/clang/Basic/Attr.td +++ include/clang/Basic/Attr.td @@ -301,6 +301,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 meaningful when applied to or inherited + // in a class template definition. + bit MeaningfulToClassTemplateDefinition = 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 = []; @@ -372,6 +375,7 @@ let Args = [VariadicStringArgument<"Tags">]; let Subjects = SubjectList<[Struct, Var, Function, Namespace], ErrorDiag, "ExpectedStructClassVariableFunctionOrInlineNamespace">; + let MeaningfulToClassTemplateDefinition = 1; let Documentation = [AbiTagsDocs]; } @@ -771,6 +775,7 @@ // An optional string argument that enables us to provide a // Fix-It. StringArgument<"Replacement", 1>]; + let MeaningfulToClassTemplateDefinition = 1; let Documentation = [DeprecatedDocs]; } @@ -1681,6 +1686,7 @@ let Args = [EnumArgument<"Visibility", "VisibilityType", ["default", "hidden", "internal", "protected"], ["Default", "Hidden", "Hidden", "Protected"]>]; + let MeaningfulToClassTemplateDefinition = 1; let Documentation = [Undocumented]; } Index: include/clang/Sema/Sema.h =================================================================== --- include/clang/Sema/Sema.h +++ include/clang/Sema/Sema.h @@ -7450,6 +7450,12 @@ 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 @@ -2390,6 +2390,13 @@ Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext()); } + if (Decl->getSpecializationKind() == TSK_Undeclared) { + MultiLevelTemplateArgumentList TemplateArgLists; + TemplateArgLists.addOuterTemplateArguments(Converted); + InstantiateAttrsForDecl(TemplateArgLists, ClassTemplate->getTemplatedDecl(), + Decl); + } + // Diagnose uses of this specialization. (void)DiagnoseUseOfDecl(Decl, TemplateLoc); Index: lib/Sema/SemaTemplateInstantiate.cpp =================================================================== --- lib/Sema/SemaTemplateInstantiate.cpp +++ lib/Sema/SemaTemplateInstantiate.cpp @@ -1882,6 +1882,9 @@ 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 @@ -328,6 +328,35 @@ Attr.getRange()); } +bool DeclContainsAttr(Decl* D, attr::Kind K) { + if (!D->hasAttrs()) + return false; + for (auto&& attr : D->getAttrs()) + if (attr->getKind() == K) + return true; + return false; +} + +void Sema::InstantiateAttrsForDecl( + const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl, + Decl *New, LateInstantiatedAttrVec *LateAttrs, + LocalInstantiationScope *OuterMostScope) { + if (NamedDecl *ND = dyn_cast(New)) { + 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. + CXXThisScopeRAII ThisScope( + *this, dyn_cast_or_null(ND->getDeclContext()), + /*TypeQuals*/ 0, ND->isCXXInstanceMember()); + + Attr *NewAttr = sema::instantiateTemplateAttributeForDecl( + TmplAttr, Context, *this, TemplateArgs); + if (NewAttr && !DeclContainsAttr(New, NewAttr->getKind())) + New->addAttr(NewAttr); + } + } +} + void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl, Decl *New, LateInstantiatedAttrVec *LateAttrs, @@ -421,7 +450,8 @@ Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context, *this, TemplateArgs); - if (NewAttr) + + if (NewAttr && !DeclContainsAttr(New, NewAttr->getKind())) New->addAttr(NewAttr); } } 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,38 @@ 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. + +template class [[deprecated]] X3; //expected-note {{'X3' has been explicitly marked deprecated here}} +template <> class X3; +X3 *x5; // expected-warning {{'X3' is deprecated}} +X3 *x6; // No warning, the specialization removes it. + +template struct A; +A *p; +template struct [[deprecated]] A;//expected-note {{'A' has been explicitly marked deprecated here}} expected-note {{'A' has been explicitly marked deprecated here}} +A *q; // expected-warning {{'A' is deprecated}} +A *r; // expected-warning {{'A' is deprecated}} + +template struct B; +B *p2; +template struct [[deprecated]] B;//expected-note {{'B' has been explicitly marked deprecated here}} expected-note {{'B' has been explicitly marked deprecated here}} +B *q2; // expected-warning {{'B' is deprecated}} +B *r2; // expected-warning {{'B' is deprecated}} + +template +T some_func(T t) { + struct [[deprecated]] FunS{}; // expected-note {{'FunS' has been explicitly marked deprecated here}} + FunS f;// expected-warning {{'FunS' is deprecated}} + +} + +template +[[deprecated]]T some_func2(T t) { + struct FunS2{}; + FunS2 f;// No warning, entire function is deprecated, so usage here should be fine. + +} Index: utils/TableGen/ClangAttrEmitter.cpp =================================================================== --- utils/TableGen/ClangAttrEmitter.cpp +++ utils/TableGen/ClangAttrEmitter.cpp @@ -2451,26 +2451,19 @@ 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 AppliesToDecl) { + OS << " switch (At->getKind()) {\n"; for (const auto *Attr : Attrs) { const Record &R = *Attr; if (!R.getValueAsBit("ASTNode")) continue; - OS << " case attr::" << R.getName() << ": {\n"; - bool ShouldClone = R.getValueAsBit("Clone"); + bool ShouldClone = R.getValueAsBit("Clone") && + (!AppliesToDecl || + R.getValueAsBit("MeaningfulToClassTemplateDefinition")); if (!ShouldClone) { OS << " return nullptr;\n"; @@ -2507,8 +2500,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, /*AppliesToDecl*/false); + OS << "}\n\n" + << "Attr *instantiateTemplateAttributeForDecl(const Attr *At,\n" + << " ASTContext &C, Sema &S,\n" + << " const MultiLevelTemplateArgumentList &TemplateArgs) {\n"; + EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/true); + OS << "}\n\n" << "} // end namespace sema\n" << "} // end namespace clang\n"; }