Skip to content
This repository was archived by the owner on Nov 1, 2021. It is now read-only.

Commit c131236

Browse files
author
Erich Keane
committed
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<typename T> [[deprecated]] class Foo{}; Foo<int> 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. Differential Revision: https://reviews.llvm.org/D27486 git-svn-id: https://llvm.org/svn/llvm-project/cfe/trunk@298410 91177308-0d34-0410-b5e6-96231b3b80d8
1 parent 9bd00f2 commit c131236

File tree

13 files changed

+141
-43
lines changed

13 files changed

+141
-43
lines changed

include/clang/Basic/Attr.td

+6
Original file line numberDiff line numberDiff line change
@@ -302,6 +302,9 @@ class Attr {
302302
// Set to true if this attribute can be duplicated on a subject when merging
303303
// attributes. By default, attributes are not merged.
304304
bit DuplicatesAllowedWhileMerging = 0;
305+
// Set to true if this attribute is meaningful when applied to or inherited
306+
// in a class template definition.
307+
bit MeaningfulToClassTemplateDefinition = 0;
305308
// Lists language options, one of which is required to be true for the
306309
// attribute to be applicable. If empty, no language options are required.
307310
list<LangOpt> LangOpts = [];
@@ -373,6 +376,7 @@ def AbiTag : Attr {
373376
let Args = [VariadicStringArgument<"Tags">];
374377
let Subjects = SubjectList<[Struct, Var, Function, Namespace], ErrorDiag,
375378
"ExpectedStructClassVariableFunctionOrInlineNamespace">;
379+
let MeaningfulToClassTemplateDefinition = 1;
376380
let Documentation = [AbiTagsDocs];
377381
}
378382

@@ -805,6 +809,7 @@ def Deprecated : InheritableAttr {
805809
// An optional string argument that enables us to provide a
806810
// Fix-It.
807811
StringArgument<"Replacement", 1>];
812+
let MeaningfulToClassTemplateDefinition = 1;
808813
let Documentation = [DeprecatedDocs];
809814
}
810815

@@ -1723,6 +1728,7 @@ def Visibility : InheritableAttr {
17231728
let Args = [EnumArgument<"Visibility", "VisibilityType",
17241729
["default", "hidden", "internal", "protected"],
17251730
["Default", "Hidden", "Hidden", "Protected"]>];
1731+
let MeaningfulToClassTemplateDefinition = 1;
17261732
let Documentation = [Undocumented];
17271733
}
17281734

include/clang/Sema/Sema.h

+6
Original file line numberDiff line numberDiff line change
@@ -7505,6 +7505,12 @@ class Sema {
75057505
LateInstantiatedAttrVec *LateAttrs = nullptr,
75067506
LocalInstantiationScope *OuterMostScope = nullptr);
75077507

7508+
void
7509+
InstantiateAttrsForDecl(const MultiLevelTemplateArgumentList &TemplateArgs,
7510+
const Decl *Pattern, Decl *Inst,
7511+
LateInstantiatedAttrVec *LateAttrs = nullptr,
7512+
LocalInstantiationScope *OuterMostScope = nullptr);
7513+
75087514
bool
75097515
InstantiateClassTemplateSpecialization(SourceLocation PointOfInstantiation,
75107516
ClassTemplateSpecializationDecl *ClassTemplateSpec,

lib/Sema/SemaDeclAttr.cpp

+4-1
Original file line numberDiff line numberDiff line change
@@ -6723,6 +6723,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
67236723
// Diagnostics for deprecated or unavailable.
67246724
unsigned diag, diag_message, diag_fwdclass_message;
67256725
unsigned diag_available_here = diag::note_availability_specified_here;
6726+
SourceLocation NoteLocation = D->getLocation();
67266727

67276728
// Matches 'diag::note_property_attribute' options.
67286729
unsigned property_note_select;
@@ -6745,6 +6746,8 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
67456746
diag_fwdclass_message = diag::warn_deprecated_fwdclass_message;
67466747
property_note_select = /* deprecated */ 0;
67476748
available_here_select_kind = /* deprecated */ 2;
6749+
if (auto *attr = D->getAttr<DeprecatedAttr>())
6750+
NoteLocation = attr->getLocation();
67486751
break;
67496752

67506753
case AR_Unavailable:
@@ -6863,7 +6866,7 @@ static void DoEmitAvailabilityWarning(Sema &S, AvailabilityResult K,
68636866
}
68646867
}
68656868
else
6866-
S.Diag(D->getLocation(), diag_available_here)
6869+
S.Diag(NoteLocation, diag_available_here)
68676870
<< D << available_here_select_kind;
68686871

68696872
if (K == AR_NotYetIntroduced)

lib/Sema/SemaTemplate.cpp

+7
Original file line numberDiff line numberDiff line change
@@ -2846,6 +2846,13 @@ QualType Sema::CheckTemplateIdType(TemplateName Name,
28462846
Decl->setLexicalDeclContext(ClassTemplate->getLexicalDeclContext());
28472847
}
28482848

2849+
if (Decl->getSpecializationKind() == TSK_Undeclared) {
2850+
MultiLevelTemplateArgumentList TemplateArgLists;
2851+
TemplateArgLists.addOuterTemplateArguments(Converted);
2852+
InstantiateAttrsForDecl(TemplateArgLists, ClassTemplate->getTemplatedDecl(),
2853+
Decl);
2854+
}
2855+
28492856
// Diagnose uses of this specialization.
28502857
(void)DiagnoseUseOfDecl(Decl, TemplateLoc);
28512858

lib/Sema/SemaTemplateInstantiate.cpp

+3
Original file line numberDiff line numberDiff line change
@@ -1939,6 +1939,9 @@ namespace clang {
19391939
namespace sema {
19401940
Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, Sema &S,
19411941
const MultiLevelTemplateArgumentList &TemplateArgs);
1942+
Attr *instantiateTemplateAttributeForDecl(
1943+
const Attr *At, ASTContext &C, Sema &S,
1944+
const MultiLevelTemplateArgumentList &TemplateArgs);
19421945
}
19431946
}
19441947

lib/Sema/SemaTemplateInstantiateDecl.cpp

+31-1
Original file line numberDiff line numberDiff line change
@@ -328,6 +328,35 @@ static void instantiateOMPDeclareSimdDeclAttr(
328328
Attr.getRange());
329329
}
330330

331+
bool DeclContainsAttr(Decl* D, attr::Kind K) {
332+
if (!D->hasAttrs())
333+
return false;
334+
for (auto&& attr : D->getAttrs())
335+
if (attr->getKind() == K)
336+
return true;
337+
return false;
338+
}
339+
340+
void Sema::InstantiateAttrsForDecl(
341+
const MultiLevelTemplateArgumentList &TemplateArgs, const Decl *Tmpl,
342+
Decl *New, LateInstantiatedAttrVec *LateAttrs,
343+
LocalInstantiationScope *OuterMostScope) {
344+
if (NamedDecl *ND = dyn_cast<NamedDecl>(New)) {
345+
for (const auto *TmplAttr : Tmpl->attrs()) {
346+
// FIXME: If any of the special case versions from InstantiateAttrs become
347+
// applicable to template declaration, we'll need to add them here.
348+
CXXThisScopeRAII ThisScope(
349+
*this, dyn_cast_or_null<CXXRecordDecl>(ND->getDeclContext()),
350+
/*TypeQuals*/ 0, ND->isCXXInstanceMember());
351+
352+
Attr *NewAttr = sema::instantiateTemplateAttributeForDecl(
353+
TmplAttr, Context, *this, TemplateArgs);
354+
if (NewAttr && !DeclContainsAttr(New, NewAttr->getKind()))
355+
New->addAttr(NewAttr);
356+
}
357+
}
358+
}
359+
331360
void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
332361
const Decl *Tmpl, Decl *New,
333362
LateInstantiatedAttrVec *LateAttrs,
@@ -421,7 +450,8 @@ void Sema::InstantiateAttrs(const MultiLevelTemplateArgumentList &TemplateArgs,
421450

422451
Attr *NewAttr = sema::instantiateTemplateAttribute(TmplAttr, Context,
423452
*this, TemplateArgs);
424-
if (NewAttr)
453+
454+
if (NewAttr && !DeclContainsAttr(New, NewAttr->getKind()))
425455
New->addAttr(NewAttr);
426456
}
427457
}

test/CXX/dcl.dcl/dcl.attr/dcl.attr.deprecated/p1.cpp

+34-3
Original file line numberDiff line numberDiff line change
@@ -23,7 +23,38 @@ template <> class [[deprecated]] X<int> {}; // expected-note {{'X<int>' has been
2323
X<char> x1;
2424
X<int> x2; // expected-warning {{'X<int>' is deprecated}}
2525

26-
template <typename T> class [[deprecated]] X2 {};
26+
template <typename T> class [[deprecated]] X2 {}; //expected-note {{'X2<char>' has been explicitly marked deprecated here}}
2727
template <> class X2<int> {};
28-
X2<char> x3; // FIXME: no warning!
29-
X2<int> x4;
28+
X2<char> x3; // expected-warning {{'X2<char>' is deprecated}}
29+
X2<int> x4; // No warning, the specialization removes it.
30+
31+
template <typename T> class [[deprecated]] X3; //expected-note {{'X3<char>' has been explicitly marked deprecated here}}
32+
template <> class X3<int>;
33+
X3<char> *x5; // expected-warning {{'X3<char>' is deprecated}}
34+
X3<int> *x6; // No warning, the specialization removes it.
35+
36+
template <typename T> struct A;
37+
A<int> *p;
38+
template <typename T> struct [[deprecated]] A;//expected-note {{'A<int>' has been explicitly marked deprecated here}} expected-note {{'A<float>' has been explicitly marked deprecated here}}
39+
A<int> *q; // expected-warning {{'A<int>' is deprecated}}
40+
A<float> *r; // expected-warning {{'A<float>' is deprecated}}
41+
42+
template <typename T> struct B;
43+
B<int> *p2;
44+
template <typename T> struct [[deprecated]] B;//expected-note {{'B<int>' has been explicitly marked deprecated here}} expected-note {{'B<float>' has been explicitly marked deprecated here}}
45+
B<int> *q2; // expected-warning {{'B<int>' is deprecated}}
46+
B<float> *r2; // expected-warning {{'B<float>' is deprecated}}
47+
48+
template <typename T>
49+
T some_func(T t) {
50+
struct [[deprecated]] FunS{}; // expected-note {{'FunS' has been explicitly marked deprecated here}}
51+
FunS f;// expected-warning {{'FunS' is deprecated}}
52+
53+
}
54+
55+
template <typename T>
56+
[[deprecated]]T some_func2(T t) {
57+
struct FunS2{};
58+
FunS2 f;// No warning, entire function is deprecated, so usage here should be fine.
59+
60+
}

test/Sema/attr-deprecated.c

+10-10
Original file line numberDiff line numberDiff line change
@@ -1,10 +1,10 @@
11
// RUN: %clang_cc1 %s -verify -fsyntax-only
22

33
int f() __attribute__((deprecated)); // expected-note 2 {{'f' has been explicitly marked deprecated here}}
4-
void g() __attribute__((deprecated));
5-
void g(); // expected-note {{'g' has been explicitly marked deprecated here}}
4+
void g() __attribute__((deprecated));// expected-note {{'g' has been explicitly marked deprecated here}}
5+
void g();
66

7-
extern int var __attribute__((deprecated)); // expected-note {{'var' has been explicitly marked deprecated here}}
7+
extern int var __attribute__((deprecated)); // expected-note 2 {{'var' has been explicitly marked deprecated here}}
88

99
int a() {
1010
int (*ptr)() = f; // expected-warning {{'f' is deprecated}}
@@ -17,13 +17,13 @@ int a() {
1717
}
1818

1919
// test if attributes propagate to variables
20-
extern int var; // expected-note {{'var' has been explicitly marked deprecated here}}
20+
extern int var;
2121
int w() {
2222
return var; // expected-warning {{'var' is deprecated}}
2323
}
2424

25-
int old_fn() __attribute__ ((deprecated));
26-
int old_fn(); // expected-note {{'old_fn' has been explicitly marked deprecated here}}
25+
int old_fn() __attribute__ ((deprecated));// expected-note {{'old_fn' has been explicitly marked deprecated here}}
26+
int old_fn();
2727
int (*fn_ptr)() = old_fn; // expected-warning {{'old_fn' is deprecated}}
2828

2929
int old_fn() {
@@ -44,8 +44,8 @@ void test1(struct foo *F) {
4444
typedef struct foo foo_dep __attribute__((deprecated)); // expected-note 12 {{'foo_dep' has been explicitly marked deprecated here}}
4545
foo_dep *test2; // expected-warning {{'foo_dep' is deprecated}}
4646

47-
struct __attribute__((deprecated,
48-
invalid_attribute)) bar_dep ; // expected-warning {{unknown attribute 'invalid_attribute' ignored}} expected-note 2 {{'bar_dep' has been explicitly marked deprecated here}}
47+
struct __attribute__((deprecated, // expected-note 2 {{'bar_dep' has been explicitly marked deprecated here}}
48+
invalid_attribute)) bar_dep ; // expected-warning {{unknown attribute 'invalid_attribute' ignored}}
4949

5050
struct bar_dep *test3; // expected-warning {{'bar_dep' is deprecated}}
5151

@@ -121,11 +121,11 @@ struct test22 {
121121
__attribute((deprecated)) foo_dep e, f;
122122
};
123123

124-
typedef int test23_ty __attribute((deprecated));
124+
typedef int test23_ty __attribute((deprecated)); // expected-note {{'test23_ty' has been explicitly marked deprecated here}}
125125
// Redefining a typedef is a C11 feature.
126126
#if __STDC_VERSION__ <= 199901L
127127
// expected-note@-3 {{'test23_ty' has been explicitly marked deprecated here}}
128128
#else
129-
typedef int test23_ty; // expected-note {{'test23_ty' has been explicitly marked deprecated here}}
129+
typedef int test23_ty;
130130
#endif
131131
test23_ty test23_v; // expected-warning {{'test23_ty' is deprecated}}

test/SemaCXX/attr-deprecated.cpp

+6-6
Original file line numberDiff line numberDiff line change
@@ -56,14 +56,14 @@ void f(B* b, C *c) {
5656
}
5757

5858
struct D {
59-
virtual void f() __attribute__((deprecated));
60-
virtual void f(int) __attribute__((deprecated));
61-
virtual void f(int, int) __attribute__((deprecated));
59+
virtual void f() __attribute__((deprecated));// expected-note{{'f' has been explicitly marked deprecated here}}
60+
virtual void f(int) __attribute__((deprecated));// expected-note{{'f' has been explicitly marked deprecated here}}
61+
virtual void f(int, int) __attribute__((deprecated));// expected-note{{'f' has been explicitly marked deprecated here}}
6262
};
6363

64-
void D::f() { } // expected-note{{'f' has been explicitly marked deprecated here}}
65-
void D::f(int v) { } // expected-note{{'f' has been explicitly marked deprecated here}}
66-
void D::f(int v1, int v2) { } // expected-note{{'f' has been explicitly marked deprecated here}}
64+
void D::f() { }
65+
void D::f(int v) { }
66+
void D::f(int v1, int v2) { }
6767

6868
void f(D* d) {
6969
d->f(); // expected-warning{{'f' is deprecated}}

test/SemaObjC/attr-deprecated.m

+2-2
Original file line numberDiff line numberDiff line change
@@ -83,8 +83,8 @@ int t5() {
8383
}
8484

8585

86-
__attribute ((deprecated))
87-
@interface DEPRECATED { // expected-note 2 {{'DEPRECATED' has been explicitly marked deprecated here}}
86+
__attribute ((deprecated)) // expected-note 2 {{'DEPRECATED' has been explicitly marked deprecated here}}
87+
@interface DEPRECATED {
8888
@public int ivar;
8989
DEPRECATED *ivar2; // no warning.
9090
}

test/SemaObjC/special-dep-unavail-warning.m

+2-2
Original file line numberDiff line numberDiff line change
@@ -44,8 +44,8 @@ void test(C *c) {
4444
}
4545

4646
// rdar://10268422
47-
__attribute ((deprecated))
48-
@interface DEPRECATED // expected-note {{'DEPRECATED' has been explicitly marked deprecated here}}
47+
__attribute ((deprecated)) // expected-note {{'DEPRECATED' has been explicitly marked deprecated here}}
48+
@interface DEPRECATED
4949
+(id)new;
5050
@end
5151

test/SemaObjC/warn-deprecated-implementations.m

+2-2
Original file line numberDiff line numberDiff line change
@@ -28,8 +28,8 @@ @implementation A(CAT)
2828
- (void) G {} // No warning, implementing its own deprecated method
2929
@end
3030

31-
__attribute__((deprecated))
32-
@interface CL // expected-note 2 {{class declared here}} // expected-note 2 {{'CL' has been explicitly marked deprecated here}}
31+
__attribute__((deprecated)) // expected-note 2 {{'CL' has been explicitly marked deprecated here}}
32+
@interface CL // expected-note 2 {{class declared here}}
3333
@end
3434

3535
@implementation CL // expected-warning {{Implementing deprecated class}}

utils/TableGen/ClangAttrEmitter.cpp

+28-16
Original file line numberDiff line numberDiff line change
@@ -2451,26 +2451,19 @@ void EmitClangAttrASTVisitor(RecordKeeper &Records, raw_ostream &OS) {
24512451
OS << "#endif // ATTR_VISITOR_DECLS_ONLY\n";
24522452
}
24532453

2454-
// Emits code to instantiate dependent attributes on templates.
2455-
void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
2456-
emitSourceFileHeader("Template instantiation code for attributes", OS);
2457-
2458-
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
2459-
2460-
OS << "namespace clang {\n"
2461-
<< "namespace sema {\n\n"
2462-
<< "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, "
2463-
<< "Sema &S,\n"
2464-
<< " const MultiLevelTemplateArgumentList &TemplateArgs) {\n"
2465-
<< " switch (At->getKind()) {\n";
2454+
void EmitClangAttrTemplateInstantiateHelper(const std::vector<Record *> &Attrs,
2455+
raw_ostream &OS,
2456+
bool AppliesToDecl) {
24662457

2458+
OS << " switch (At->getKind()) {\n";
24672459
for (const auto *Attr : Attrs) {
24682460
const Record &R = *Attr;
24692461
if (!R.getValueAsBit("ASTNode"))
24702462
continue;
2471-
24722463
OS << " case attr::" << R.getName() << ": {\n";
2473-
bool ShouldClone = R.getValueAsBit("Clone");
2464+
bool ShouldClone = R.getValueAsBit("Clone") &&
2465+
(!AppliesToDecl ||
2466+
R.getValueAsBit("MeaningfulToClassTemplateDefinition"));
24742467

24752468
if (!ShouldClone) {
24762469
OS << " return nullptr;\n";
@@ -2507,8 +2500,27 @@ void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
25072500
}
25082501
OS << " } // end switch\n"
25092502
<< " llvm_unreachable(\"Unknown attribute!\");\n"
2510-
<< " return nullptr;\n"
2511-
<< "}\n\n"
2503+
<< " return nullptr;\n";
2504+
}
2505+
2506+
// Emits code to instantiate dependent attributes on templates.
2507+
void EmitClangAttrTemplateInstantiate(RecordKeeper &Records, raw_ostream &OS) {
2508+
emitSourceFileHeader("Template instantiation code for attributes", OS);
2509+
2510+
std::vector<Record*> Attrs = Records.getAllDerivedDefinitions("Attr");
2511+
2512+
OS << "namespace clang {\n"
2513+
<< "namespace sema {\n\n"
2514+
<< "Attr *instantiateTemplateAttribute(const Attr *At, ASTContext &C, "
2515+
<< "Sema &S,\n"
2516+
<< " const MultiLevelTemplateArgumentList &TemplateArgs) {\n";
2517+
EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/false);
2518+
OS << "}\n\n"
2519+
<< "Attr *instantiateTemplateAttributeForDecl(const Attr *At,\n"
2520+
<< " ASTContext &C, Sema &S,\n"
2521+
<< " const MultiLevelTemplateArgumentList &TemplateArgs) {\n";
2522+
EmitClangAttrTemplateInstantiateHelper(Attrs, OS, /*AppliesToDecl*/true);
2523+
OS << "}\n\n"
25122524
<< "} // end namespace sema\n"
25132525
<< "} // end namespace clang\n";
25142526
}

0 commit comments

Comments
 (0)