Skip to content

Commit fc02532

Browse files
authored
[Clang][Sema] Diagnose function/variable templates that shadow their own template parameters (#78274)
Previously, we skipped through template parameter scopes (until we hit a declaration scope) prior to redeclaration lookup for declarators. For template declarations, the meant that their template parameters would not be found and shadowing would not be diagnosed. With these changes applied, the following declarations are correctly diagnosed: ```cpp template<typename T> void T(); // error: declaration of 'T' shadows template parameter template<typename U> int U; // error: declaration of 'U' shadows template parameter ``` The reason for skipping past non-declaration & template parameter scopes prior to lookup appears to have been because `GetTypeForDeclarator` needed this adjusted scope... but it doesn't actually use this parameter anymore. The scope adjustment now happens prior to calling `ActOnFunctionDeclarator`/`ActOnVariableDeclarator`/`ActOnTypedefDeclarator` (just in case they depend on this behavior... I didn't check in depth).
1 parent 77d21e7 commit fc02532

File tree

3 files changed

+24
-9
lines changed

3 files changed

+24
-9
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -568,6 +568,7 @@ Improvements to Clang's diagnostics
568568
- Clang now diagnoses the requirement that non-template friend declarations with requires clauses
569569
and template friend declarations with a constraint that depends on a template parameter from an
570570
enclosing template must be a definition.
571+
- Clang now diagnoses function/variable templates that shadow their own template parameters, e.g. ``template<class T> void T();``.
571572

572573

573574
Improvements to Clang's time-trace

clang/lib/Sema/SemaDecl.cpp

Lines changed: 6 additions & 6 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();
@@ -6535,6 +6529,12 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
65356529
if (getLangOpts().CPlusPlus)
65366530
CheckExtraCXXDefaultArguments(D);
65376531

6532+
// The scope passed in may not be a decl scope. Zip up the scope tree until
6533+
// we find one that is.
6534+
while ((S->getFlags() & Scope::DeclScope) == 0 ||
6535+
(S->getFlags() & Scope::TemplateParamScope) != 0)
6536+
S = S->getParent();
6537+
65386538
NamedDecl *New;
65396539

65406540
bool AddToScope = true;

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

Lines changed: 17 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -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-error{{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-error{{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-error{{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-error{{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)