Skip to content

Commit 695e618

Browse files
committed
[FOLD] add warning + tests
1 parent 5f19ff4 commit 695e618

File tree

4 files changed

+88
-6
lines changed

4 files changed

+88
-6
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -3669,6 +3669,9 @@ def warn_attribute_dllexport_explicit_instantiation_decl : Warning<
36693669
def warn_attribute_dllexport_explicit_instantiation_def : Warning<
36703670
"'dllexport' attribute ignored on explicit instantiation definition">,
36713671
InGroup<IgnoredAttributes>;
3672+
def warn_attribute_exclude_from_explicit_instantiation_local_class : Warning<
3673+
"%0 attribute ignored on local class%select{| member}1">,
3674+
InGroup<IgnoredAttributes>;
36723675
def warn_invalid_initializer_from_system_header : Warning<
36733676
"invalid constructor from class in system header, should not be explicit">,
36743677
InGroup<DiagGroup<"invalid-initializer-from-system-header">>;

clang/lib/Sema/SemaDeclAttr.cpp

Lines changed: 18 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -984,6 +984,21 @@ static void handleErrorAttr(Sema &S, Decl *D, const ParsedAttr &AL) {
984984
D->addAttr(EA);
985985
}
986986

987+
static void handleExcludeFromExplicitInstantiationAttr(Sema &S, Decl *D,
988+
const ParsedAttr &AL) {
989+
const auto *PD = isa<CXXRecordDecl>(D)
990+
? cast<DeclContext>(D)
991+
: D->getDeclContext()->getRedeclContext();
992+
if (const auto *RD = dyn_cast<CXXRecordDecl>(PD); RD && RD->isLocalClass()) {
993+
S.Diag(AL.getLoc(),
994+
diag::warn_attribute_exclude_from_explicit_instantiation_local_class)
995+
<< AL << /*IsMember=*/!isa<CXXRecordDecl>(D);
996+
return;
997+
}
998+
D->addAttr(::new (S.Context)
999+
ExcludeFromExplicitInstantiationAttr(S.Context, AL));
1000+
}
1001+
9871002
namespace {
9881003
/// Determines if a given Expr references any of the given function's
9891004
/// ParmVarDecls, or the function's implicit `this` parameter (if applicable).
@@ -9339,6 +9354,9 @@ ProcessDeclAttribute(Sema &S, Scope *scope, Decl *D, const ParsedAttr &AL,
93399354
case ParsedAttr::AT_Error:
93409355
handleErrorAttr(S, D, AL);
93419356
break;
9357+
case ParsedAttr::AT_ExcludeFromExplicitInstantiation:
9358+
handleExcludeFromExplicitInstantiationAttr(S, D, AL);
9359+
break;
93429360
case ParsedAttr::AT_DiagnoseIf:
93439361
handleDiagnoseIfAttr(S, D, AL);
93449362
break;

clang/lib/Sema/SemaTemplateInstantiate.cpp

Lines changed: 3 additions & 6 deletions
Original file line numberDiff line numberDiff line change
@@ -4124,8 +4124,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
41244124
}
41254125
}
41264126

4127-
if (Function->hasAttr<ExcludeFromExplicitInstantiationAttr>() &&
4128-
!Instantiation->isLocalClass())
4127+
if (Function->hasAttr<ExcludeFromExplicitInstantiationAttr>())
41294128
continue;
41304129

41314130
MemberSpecializationInfo *MSInfo =
@@ -4170,8 +4169,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
41704169
continue;
41714170

41724171
if (Var->isStaticDataMember()) {
4173-
if (Var->hasAttr<ExcludeFromExplicitInstantiationAttr>() &&
4174-
!Instantiation->isLocalClass())
4172+
if (Var->hasAttr<ExcludeFromExplicitInstantiationAttr>())
41754173
continue;
41764174

41774175
MemberSpecializationInfo *MSInfo = Var->getMemberSpecializationInfo();
@@ -4205,8 +4203,7 @@ Sema::InstantiateClassMembers(SourceLocation PointOfInstantiation,
42054203
}
42064204
}
42074205
} else if (auto *Record = dyn_cast<CXXRecordDecl>(D)) {
4208-
if (Record->hasAttr<ExcludeFromExplicitInstantiationAttr>() &&
4209-
!Instantiation->isLocalClass())
4206+
if (Record->hasAttr<ExcludeFromExplicitInstantiationAttr>())
42104207
continue;
42114208

42124209
// Always skip the injected-class-name, along with any
Lines changed: 64 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,64 @@
1+
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
2+
3+
// Test that the exclude_from_explicit_instantiation attribute is ignored
4+
// for local classes and members thereof.
5+
6+
#define EXCLUDE_FROM_EXPLICIT_INSTANTIATION __attribute__((exclude_from_explicit_instantiation)) // expected-note 0+{{expanded from macro}}
7+
8+
namespace N0 {
9+
10+
template<typename T>
11+
void f() {
12+
struct EXCLUDE_FROM_EXPLICIT_INSTANTIATION A { // expected-warning {{attribute ignored on local class}}
13+
// expected-note@-1 2{{in instantiation of}}
14+
EXCLUDE_FROM_EXPLICIT_INSTANTIATION void g(T t) { // expected-warning {{attribute ignored on local class member}}
15+
*t; // expected-error {{indirection requires pointer operand ('int' invalid)}}
16+
}
17+
18+
struct EXCLUDE_FROM_EXPLICIT_INSTANTIATION B { // expected-warning {{attribute ignored on local class}}
19+
void h(T t) {
20+
*t; // expected-error {{indirection requires pointer operand ('int' invalid)}}
21+
}
22+
};
23+
};
24+
}
25+
26+
template void f<int>(); // expected-note 2{{in instantiation of}}
27+
28+
}
29+
30+
// This is a reduced example from libc++ which required that 'value'
31+
// be prefixed with 'this->' because the definition of 'Local::operator A'
32+
// was not instantiated when the definition of 'g' was.
33+
namespace N1 {
34+
35+
struct A { };
36+
37+
struct B {
38+
operator A() {
39+
return A();
40+
}
41+
};
42+
43+
template<typename T>
44+
auto f(T t) {
45+
return A(t);
46+
}
47+
48+
template<typename T>
49+
auto g(T t) {
50+
struct Local {
51+
T value;
52+
53+
EXCLUDE_FROM_EXPLICIT_INSTANTIATION // expected-warning {{attribute ignored on local class member}}
54+
operator A() {
55+
return A(value);
56+
}
57+
};
58+
59+
return f(Local(t));
60+
}
61+
62+
auto x = g(B());
63+
64+
}

0 commit comments

Comments
 (0)