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/SemaDeclAttr.cpp =================================================================== --- lib/Sema/SemaDeclAttr.cpp +++ lib/Sema/SemaDeclAttr.cpp @@ -6611,6 +6611,7 @@ // Diagnostics for deprecated or unavailable. unsigned diag, diag_message, diag_fwdclass_message; unsigned diag_available_here = diag::note_availability_specified_here; + SourceLocation NoteLocation = D->getLocation(); // Matches 'diag::note_property_attribute' options. unsigned property_note_select; @@ -6633,6 +6634,8 @@ diag_fwdclass_message = diag::warn_deprecated_fwdclass_message; property_note_select = /* deprecated */ 0; available_here_select_kind = /* deprecated */ 2; + if (auto *attr = D->getAttr()) + NoteLocation = attr->getLocation(); break; case AR_Unavailable: @@ -6751,7 +6754,7 @@ } } else - S.Diag(D->getLocation(), diag_available_here) + S.Diag(NoteLocation, diag_available_here) << D << available_here_select_kind; if (K == AR_NotYetIntroduced) 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: test/Sema/attr-deprecated.c =================================================================== --- test/Sema/attr-deprecated.c +++ test/Sema/attr-deprecated.c @@ -1,10 +1,10 @@ // RUN: %clang_cc1 %s -verify -fsyntax-only int f() __attribute__((deprecated)); // expected-note 2 {{'f' has been explicitly marked deprecated here}} -void g() __attribute__((deprecated)); -void g(); // expected-note {{'g' has been explicitly marked deprecated here}} +void g() __attribute__((deprecated));// expected-note {{'g' has been explicitly marked deprecated here}} +void g(); -extern int var __attribute__((deprecated)); // expected-note {{'var' has been explicitly marked deprecated here}} +extern int var __attribute__((deprecated)); // expected-note 2 {{'var' has been explicitly marked deprecated here}} int a() { int (*ptr)() = f; // expected-warning {{'f' is deprecated}} @@ -17,13 +17,13 @@ } // test if attributes propagate to variables -extern int var; // expected-note {{'var' has been explicitly marked deprecated here}} +extern int var; int w() { return var; // expected-warning {{'var' is deprecated}} } -int old_fn() __attribute__ ((deprecated)); -int old_fn(); // expected-note {{'old_fn' has been explicitly marked deprecated here}} +int old_fn() __attribute__ ((deprecated));// expected-note {{'old_fn' has been explicitly marked deprecated here}} +int old_fn(); int (*fn_ptr)() = old_fn; // expected-warning {{'old_fn' is deprecated}} int old_fn() { @@ -44,8 +44,8 @@ typedef struct foo foo_dep __attribute__((deprecated)); // expected-note 12 {{'foo_dep' has been explicitly marked deprecated here}} foo_dep *test2; // expected-warning {{'foo_dep' is deprecated}} -struct __attribute__((deprecated, - invalid_attribute)) bar_dep ; // expected-warning {{unknown attribute 'invalid_attribute' ignored}} expected-note 2 {{'bar_dep' has been explicitly marked deprecated here}} +struct __attribute__((deprecated, // expected-note 2 {{'bar_dep' has been explicitly marked deprecated here}} + invalid_attribute)) bar_dep ; // expected-warning {{unknown attribute 'invalid_attribute' ignored}} struct bar_dep *test3; // expected-warning {{'bar_dep' is deprecated}} @@ -121,11 +121,11 @@ __attribute((deprecated)) foo_dep e, f; }; -typedef int test23_ty __attribute((deprecated)); +typedef int test23_ty __attribute((deprecated)); // expected-note {{'test23_ty' has been explicitly marked deprecated here}} // Redefining a typedef is a C11 feature. #if __STDC_VERSION__ <= 199901L // expected-note@-3 {{'test23_ty' has been explicitly marked deprecated here}} #else -typedef int test23_ty; // expected-note {{'test23_ty' has been explicitly marked deprecated here}} +typedef int test23_ty; #endif test23_ty test23_v; // expected-warning {{'test23_ty' is deprecated}} Index: test/SemaCXX/attr-deprecated.cpp =================================================================== --- test/SemaCXX/attr-deprecated.cpp +++ test/SemaCXX/attr-deprecated.cpp @@ -56,14 +56,14 @@ } struct D { - virtual void f() __attribute__((deprecated)); - virtual void f(int) __attribute__((deprecated)); - virtual void f(int, int) __attribute__((deprecated)); + virtual void f() __attribute__((deprecated));// expected-note{{'f' has been explicitly marked deprecated here}} + virtual void f(int) __attribute__((deprecated));// expected-note{{'f' has been explicitly marked deprecated here}} + virtual void f(int, int) __attribute__((deprecated));// expected-note{{'f' has been explicitly marked deprecated here}} }; -void D::f() { } // expected-note{{'f' has been explicitly marked deprecated here}} -void D::f(int v) { } // expected-note{{'f' has been explicitly marked deprecated here}} -void D::f(int v1, int v2) { } // expected-note{{'f' has been explicitly marked deprecated here}} +void D::f() { } +void D::f(int v) { } +void D::f(int v1, int v2) { } void f(D* d) { d->f(); // expected-warning{{'f' is deprecated}} Index: test/SemaObjC/attr-deprecated.m =================================================================== --- test/SemaObjC/attr-deprecated.m +++ test/SemaObjC/attr-deprecated.m @@ -83,8 +83,8 @@ } -__attribute ((deprecated)) -@interface DEPRECATED { // expected-note 2 {{'DEPRECATED' has been explicitly marked deprecated here}} +__attribute ((deprecated)) // expected-note 2 {{'DEPRECATED' has been explicitly marked deprecated here}} +@interface DEPRECATED { @public int ivar; DEPRECATED *ivar2; // no warning. } Index: test/SemaObjC/special-dep-unavail-warning.m =================================================================== --- test/SemaObjC/special-dep-unavail-warning.m +++ test/SemaObjC/special-dep-unavail-warning.m @@ -44,8 +44,8 @@ } // rdar://10268422 -__attribute ((deprecated)) -@interface DEPRECATED // expected-note {{'DEPRECATED' has been explicitly marked deprecated here}} +__attribute ((deprecated)) // expected-note {{'DEPRECATED' has been explicitly marked deprecated here}} +@interface DEPRECATED +(id)new; @end Index: test/SemaObjC/warn-deprecated-implementations.m =================================================================== --- test/SemaObjC/warn-deprecated-implementations.m +++ test/SemaObjC/warn-deprecated-implementations.m @@ -28,8 +28,8 @@ - (void) G {} // No warning, implementing its own deprecated method @end -__attribute__((deprecated)) -@interface CL // expected-note 2 {{class declared here}} // expected-note 2 {{'CL' has been explicitly marked deprecated here}} +__attribute__((deprecated)) // expected-note 2 {{'CL' has been explicitly marked deprecated here}} +@interface CL // expected-note 2 {{class declared here}} @end @implementation CL // expected-warning {{Implementing deprecated class}} 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"; }