From: Erich Keane Date: Thu, 23 Mar 2017 18:51:54 +0000 (+0000) Subject: Correct class-template deprecation behavior-REDUX X-Git-Tag: llvmorg-5.0.0-rc1~9314 X-Git-Url: http://review.tizen.org/git/?a=commitdiff_plain;h=a32910da1ac5f7c3a2a97d1e5e2050cebe109ae7;p=platform%2Fupstream%2Fllvm.git Correct class-template deprecation behavior-REDUX Correct class-template deprecation behavior Based on the comment in the test, and my reading of the standard, a deprecated warning should be issued in the following case: template [[deprecated]] class Foo{}; Foo f; This was not the case, because the ClassTemplateSpecializationDecl creation did not also copy the deprecated attribute. Note: I did NOT audit the complete set of attributes to see WHICH ones should be copied, so instead I simply copy ONLY the deprecated attribute. Previous DiffRev: https://reviews.llvm.org/D27486, was reverted. This patch fixes the issues brought up here by the reverter: https://reviews.llvm.org/rL298410 Differential Revision: https://reviews.llvm.org/D31245 llvm-svn: 298634 --- diff --git a/clang/include/clang/Basic/Attr.td b/clang/include/clang/Basic/Attr.td index ff62e10..db8e073 100644 --- a/clang/include/clang/Basic/Attr.td +++ b/clang/include/clang/Basic/Attr.td @@ -302,6 +302,9 @@ class Attr { // 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 = []; @@ -373,6 +376,7 @@ def AbiTag : Attr { let Args = [VariadicStringArgument<"Tags">]; let Subjects = SubjectList<[Struct, Var, Function, Namespace], ErrorDiag, "ExpectedStructClassVariableFunctionOrInlineNamespace">; + let MeaningfulToClassTemplateDefinition = 1; let Documentation = [AbiTagsDocs]; } @@ -805,6 +809,7 @@ def Deprecated : InheritableAttr { // An optional string argument that enables us to provide a // Fix-It. StringArgument<"Replacement", 1>]; + let MeaningfulToClassTemplateDefinition = 1; let Documentation = [DeprecatedDocs]; } @@ -1723,6 +1728,7 @@ def Visibility : InheritableAttr { let Args = [EnumArgument<"Visibility", "VisibilityType", ["default", "hidden", "internal", "protected"], ["Default", "Hidden", "Hidden", "Protected"]>]; + let MeaningfulToClassTemplateDefinition = 1; let Documentation = [Undocumented]; } diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 51504b5..8050e33 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -7505,6 +7505,12 @@ public: 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, diff --git a/clang/lib/Sema/SemaDeclAttr.cpp b/clang/lib/Sema/SemaDeclAttr.cpp index 1c350a7..3121026 100644 --- a/clang/lib/Sema/SemaDeclAttr.cpp +++ b/clang/lib/Sema/SemaDeclAttr.cpp @@ -6723,6 +6723,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, // 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; @@ -6745,6 +6746,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, diag_fwdclass_message = diag::warn_deprecated_fwdclass_message; property_note_select = /* deprecated */ 0; available_here_select_kind = /* deprecated */ 2; + if (const auto *attr = D->getAttr()) + NoteLocation = attr->getLocation(); break; case AR_Unavailable: @@ -6863,7 +6866,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K, } } else - S.Diag(D->getLocation(), diag_available_here) + S.Diag(NoteLocation, diag_available_here) << D << available_here_select_kind; if (K == AR_NotYetIntroduced) diff --git a/clang/lib/Sema/SemaTemplate.cpp b/clang/lib/Sema/SemaTemplate.cpp index f6c6ccb..b344279 100644 --- a/clang/lib/Sema/SemaTemplate.cpp +++ b/clang/lib/Sema/SemaTemplate.cpp @@ -2846,6 +2846,13 @@ QualType Sema::CheckTemplateIdType(TemplateName Name, 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); diff --git a/clang/lib/Sema/SemaTemplateInstantiate.cpp b/clang/lib/Sema/SemaTemplateInstantiate.cpp index 314dfe3..67e330a 100644 --- a/clang/lib/Sema/SemaTemplateInstantiate.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiate.cpp @@ -1939,6 +1939,9 @@ namespace clang { 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); } } diff --git a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp index cab55ea..d75d705 100644 --- a/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp +++ b/clang/lib/Sema/SemaTemplateInstantiateDecl.cpp @@ -328,6 +328,34 @@ static void instantiateOMPDeclareSimdDeclAttr( Attr.getRange()); } +static bool DeclContainsAttr(const Decl *D, const Attr *NewAttr) { + if (!D->hasAttrs() || NewAttr->duplicatesAllowed()) + return false; + return llvm::find_if(D->getAttrs(), [NewAttr](const Attr *Attr) { + return Attr->getKind() == NewAttr->getKind(); + }) != D->getAttrs().end(); +} + +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)) + New->addAttr(NewAttr); + } + } +} + void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl, Decl *New, LateInstantiatedAttrVec *LateAttrs, @@ -421,7 +449,8 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs, Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context, *this, TemplateArgs); - if (NewAttr) + + if (NewAttr && !DeclContainsAttr(New, NewAttr)) New->addAttr(NewAttr); } } diff --git a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp index a27cea8..58c7c0c 100644 --- a/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp +++ b/clang/test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp @@ -23,7 +23,38 @@ template <> class [[deprecated]] X {}; // expected-note {{'X' has been 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. + +} diff --git a/clang/test/Sema/attr-deprecated.c b/clang/test/Sema/attr-deprecated.c index 8566a0e..89c0686 100644 --- a/clang/test/Sema/attr-deprecated.c +++ b/clang/test/Sema/attr-deprecated.c @@ -1,10 +1,12 @@ // RUN: %clang_cc1 %s -verify -fsyntax-only +// RUN: %clang_cc1 %s -std=c89 -verify -fsyntax-only +// RUN: %clang_cc1 %s -std=c99 -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 +19,13 @@ int a() { } // 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 +46,8 @@ void test1(struct foo *F) { 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 +123,12 @@ struct test22 { __attribute((deprecated)) foo_dep e, f; }; -typedef int test23_ty __attribute((deprecated)); +typedef int test23_ty __attribute((deprecated)); // 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}} +// expected-note@-5 {{'test23_ty' has been explicitly marked deprecated here}} +typedef int test23_ty; #endif test23_ty test23_v; // expected-warning {{'test23_ty' is deprecated}} diff --git a/clang/test/SemaCXX/attr-deprecated.cpp b/clang/test/SemaCXX/attr-deprecated.cpp index eab5a1c..1680c5c 100644 --- a/clang/test/SemaCXX/attr-deprecated.cpp +++ b/clang/test/SemaCXX/attr-deprecated.cpp @@ -56,14 +56,14 @@ void f(B* b, C *c) { } 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}} diff --git a/clang/test/SemaCXX/template-multiple-attr-propagation.cpp b/clang/test/SemaCXX/template-multiple-attr-propagation.cpp new file mode 100644 index 0000000..8e7f457 --- /dev/null +++ b/clang/test/SemaCXX/template-multiple-attr-propagation.cpp @@ -0,0 +1,29 @@ +// RUN: %clang_cc1 %s -Wthread-safety-analysis -verify -fexceptions +// expected-no-diagnostics + +class Mutex { +public: + void Lock() __attribute__((exclusive_lock_function())); + void Unlock() __attribute__((unlock_function())); +}; + +class A { +public: + Mutex mu1, mu2; + + void foo() __attribute__((exclusive_locks_required(mu1))) __attribute__((exclusive_locks_required(mu2))) {} + + template + void bar() __attribute__((exclusive_locks_required(mu1))) __attribute__((exclusive_locks_required(mu2))) { + foo(); + } +}; + +void f() { + A a; + a.mu1.Lock(); + a.mu2.Lock(); + a.bar(); + a.mu2.Unlock(); + a.mu1.Unlock(); +} diff --git a/clang/test/SemaObjC/attr-deprecated.m b/clang/test/SemaObjC/attr-deprecated.m index 8a949f9..b061385 100644 --- a/clang/test/SemaObjC/attr-deprecated.m +++ b/clang/test/SemaObjC/attr-deprecated.m @@ -83,8 +83,8 @@ int t5() { } -__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. } diff --git a/clang/test/SemaObjC/special-dep-unavail-warning.m b/clang/test/SemaObjC/special-dep-unavail-warning.m index 9e16b33..b667c3c 100644 --- a/clang/test/SemaObjC/special-dep-unavail-warning.m +++ b/clang/test/SemaObjC/special-dep-unavail-warning.m @@ -44,8 +44,8 @@ void test(C *c) { } // 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 diff --git a/clang/test/SemaObjC/warn-deprecated-implementations.m b/clang/test/SemaObjC/warn-deprecated-implementations.m index f5a010d..0c34116 100644 --- a/clang/test/SemaObjC/warn-deprecated-implementations.m +++ b/clang/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}} diff --git a/clang/utils/TableGen/ClangAttrEmitter.cpp b/clang/utils/TableGen/ClangAttrEmitter.cpp index 990b860..c516b53 100644 --- a/clang/utils/TableGen/ClangAttrEmitter.cpp +++ b/clang/utils/TableGen/ClangAttrEmitter.cpp @@ -2451,26 +2451,19 @@ void EmitClangAttrASTVisitor(RecordKeeper &Records, raw_ostream &OS) { 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 @@ void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) { } 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"; }