Skip to content

Commit abc8f06

Browse files
committed
Reapply "[Clang][Sema] Diagnose function/variable templates that shadow their own template parameters (llvm#78274)"
1 parent faef68b commit abc8f06

File tree

6 files changed

+51
-17
lines changed

6 files changed

+51
-17
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -97,6 +97,7 @@ Attribute Changes in Clang
9797

9898
Improvements to Clang's diagnostics
9999
-----------------------------------
100+
- Clang now diagnoses function/variable templates that shadow their own template parameters, e.g. ``template<class T> void T();``.
100101

101102
Improvements to Clang's time-trace
102103
----------------------------------

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -4966,6 +4966,9 @@ def err_template_param_shadow : Error<
49664966
"declaration of %0 shadows template parameter">;
49674967
def ext_template_param_shadow : ExtWarn<
49684968
err_template_param_shadow.Summary>, InGroup<MicrosoftTemplateShadow>;
4969+
def ext_compat_template_param_shadow : ExtWarn<
4970+
err_template_param_shadow.Summary>, InGroup<
4971+
DiagGroup<"strict-primary-template-shadow">>, DefaultError;
49694972
def note_template_param_here : Note<"template parameter is declared here">;
49704973
def note_template_param_external : Note<
49714974
"template parameter from hidden source: %0">;

clang/include/clang/Sema/Sema.h

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8256,7 +8256,7 @@ class Sema final {
82568256
TemplateSpecializationKind TSK,
82578257
bool Complain = true);
82588258

8259-
void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
8259+
void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl, bool IssueWarning = false);
82608260
TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl);
82618261

82628262
NamedDecl *ActOnTypeParameter(Scope *S, bool Typename,

clang/lib/Sema/SemaDecl.cpp

Lines changed: 22 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -6377,12 +6377,6 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
63776377
} else if (DiagnoseUnexpandedParameterPack(NameInfo, UPPC_DeclarationType))
63786378
return nullptr;
63796379

6380-
// The scope passed in may not be a decl scope. Zip up the scope tree until
6381-
// we find one that is.
6382-
while ((S->getFlags() & Scope::DeclScope) == 0 ||
6383-
(S->getFlags() & Scope::TemplateParamScope) != 0)
6384-
S = S->getParent();
6385-
63866380
DeclContext *DC = CurContext;
63876381
if (D.getCXXScopeSpec().isInvalid())
63886382
D.setInvalidType();
@@ -6506,12 +6500,25 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
65066500
RemoveUsingDecls(Previous);
65076501
}
65086502

6509-
if (Previous.isSingleResult() &&
6510-
Previous.getFoundDecl()->isTemplateParameter()) {
6503+
// if (Previous.isSingleResult() &&
6504+
// Previous.getFoundDecl()->isTemplateParameter()) {
6505+
if (auto *TPD = Previous.getAsSingle<NamedDecl>(); TPD && TPD->isTemplateParameter()) {
6506+
// Older versions of clang allowed the names of function/variable templates
6507+
// to shadow the names of their template parameters. For the compatibility purposes
6508+
// we detect such cases and issue a default-to-error warning that can be disabled with
6509+
// -fno-strict-primary-template-shadow.
6510+
bool IssueShadowingWarning = false;
6511+
for (Scope *Inner = S; (Inner->getFlags() & Scope::DeclScope) == 0 ||
6512+
Inner->isTemplateParamScope(); Inner = Inner->getParent()) {
6513+
if (IssueShadowingWarning = Inner->isDeclScope(TPD))
6514+
break;
6515+
}
6516+
65116517
// Maybe we will complain about the shadowed template parameter.
65126518
if (!D.isInvalidType())
65136519
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
6514-
Previous.getFoundDecl());
6520+
TPD,
6521+
IssueShadowingWarning);
65156522

65166523
// Just pretend that we didn't see the previous declaration.
65176524
Previous.clear();
@@ -6535,6 +6542,12 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
65356542
if (getLangOpts().CPlusPlus)
65366543
CheckExtraCXXDefaultArguments(D);
65376544

6545+
// The scope passed in may not be a decl scope. Zip up the scope tree until
6546+
// we find one that is.
6547+
while ((S->getFlags() & Scope::DeclScope) == 0 ||
6548+
(S->getFlags() & Scope::TemplateParamScope) != 0)
6549+
S = S->getParent();
6550+
65386551
NamedDecl *New;
65396552

65406553
bool AddToScope = true;

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -885,16 +885,19 @@ bool Sema::DiagnoseUninstantiableTemplate(SourceLocation PointOfInstantiation,
885885
/// that the template parameter 'PrevDecl' is being shadowed by a new
886886
/// declaration at location Loc. Returns true to indicate that this is
887887
/// an error, and false otherwise.
888-
void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl) {
888+
void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl, bool IssueWarning) {
889889
assert(PrevDecl->isTemplateParameter() && "Not a template parameter");
890890

891891
// C++ [temp.local]p4:
892892
// A template-parameter shall not be redeclared within its
893893
// scope (including nested scopes).
894894
//
895895
// Make this a warning when MSVC compatibility is requested.
896-
unsigned DiagId = getLangOpts().MSVCCompat ? diag::ext_template_param_shadow
897-
: diag::err_template_param_shadow;
896+
unsigned DiagId = getLangOpts().MSVCCompat
897+
? diag::ext_template_param_shadow
898+
: (IssueWarning
899+
? diag::ext_compat_template_param_shadow
900+
: diag::err_template_param_shadow);
898901
const auto *ND = cast<NamedDecl>(PrevDecl);
899902
Diag(Loc, DiagId) << ND->getDeclName();
900903
NoteTemplateParameterLocation(*ND);

clang/test/CXX/temp/temp.res/temp.local/p6.cpp

Lines changed: 18 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,4 +1,4 @@
1-
// RUN: %clang_cc1 -verify %s -fcxx-exceptions -std=c++1y
1+
// RUN: %clang_cc1 -verify %s -fcxx-exceptions -std=c++1y -Wno-error=strict-primary-template-shadow
22

33
namespace N {}
44

@@ -127,16 +127,30 @@ template<int T> struct Z { // expected-note 16{{declared here}}
127127
template<typename T> // expected-note {{declared here}}
128128
void f(int T) {} // expected-error {{declaration of 'T' shadows template parameter}}
129129

130-
// FIXME: These are ill-formed: a template-parameter shall not have the same name as the template name.
131130
namespace A {
132131
template<typename T> struct T {}; // expected-error{{declaration of 'T' shadows template parameter}}
133132
// expected-note@-1{{template parameter is declared here}}
133+
template<typename T> struct U {
134+
template<typename V> struct V {}; // expected-error{{declaration of 'V' shadows template parameter}}
135+
// expected-note@-1{{template parameter is declared here}}
136+
};
134137
}
135138
namespace B {
136-
template<typename T> void T() {}
139+
template<typename T> void T() {} // expected-warning{{declaration of 'T' shadows template parameter}}
140+
// expected-note@-1{{template parameter is declared here}}
141+
142+
template<typename T> struct U {
143+
template<typename V> void V(); // expected-warning{{declaration of 'V' shadows template parameter}}
144+
// expected-note@-1{{template parameter is declared here}}
145+
};
137146
}
138147
namespace C {
139-
template<typename T> int T;
148+
template<typename T> int T; // expected-warning{{declaration of 'T' shadows template parameter}}
149+
// expected-note@-1{{template parameter is declared here}}
150+
template<typename T> struct U {
151+
template<typename V> static int V; // expected-warning{{declaration of 'V' shadows template parameter}}
152+
// expected-note@-1{{template parameter is declared here}}
153+
};
140154
}
141155

142156
namespace PR28023 {

0 commit comments

Comments
 (0)