Skip to content

Commit a9a6b6e

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

File tree

9 files changed

+83
-41
lines changed

9 files changed

+83
-41
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -42,6 +42,8 @@ C/C++ Language Potentially Breaking Changes
4242

4343
C++ Specific Potentially Breaking Changes
4444
-----------------------------------------
45+
- Clang now diagnoses function/variable templates that shadow their own template parameters, e.g. ``template<class T> void T();``.
46+
This error can be disabled via `-Wno-strict-primary-template-shadow` for compatibility with previous versions of clang.
4547

4648
ABI Changes in This Version
4749
---------------------------

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/Scope.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -200,6 +200,10 @@ class Scope {
200200
/// other template parameter scopes as parents.
201201
Scope *TemplateParamParent;
202202

203+
/// DeclScopeParent - This is a direct link to the immediately containing
204+
/// DeclScope, i.e. scope which can contain declarations.
205+
Scope *DeclParent;
206+
203207
/// DeclsInScope - This keeps track of all declarations in this scope. When
204208
/// the declaration is added to the scope, it is set as the current
205209
/// declaration for the identifier in the IdentifierTable. When the scope is
@@ -299,6 +303,9 @@ class Scope {
299303
Scope *getTemplateParamParent() { return TemplateParamParent; }
300304
const Scope *getTemplateParamParent() const { return TemplateParamParent; }
301305

306+
Scope *getDeclParent() { return DeclParent; }
307+
const Scope *getDeclParent() const { return DeclParent; }
308+
302309
/// Returns the depth of this scope. The translation-unit has scope depth 0.
303310
unsigned getDepth() const { return Depth; }
304311

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -8315,7 +8315,8 @@ class Sema final {
83158315
TemplateSpecializationKind TSK,
83168316
bool Complain = true);
83178317

8318-
void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl);
8318+
void DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl,
8319+
bool IssueWarning = false);
83198320
TemplateDecl *AdjustDeclIfTemplate(Decl *&Decl);
83208321

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

clang/lib/Sema/Scope.cpp

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -37,6 +37,7 @@ void Scope::setFlags(Scope *parent, unsigned flags) {
3737
FnParent = parent->FnParent;
3838
BlockParent = parent->BlockParent;
3939
TemplateParamParent = parent->TemplateParamParent;
40+
DeclParent = parent->DeclParent;
4041
MSLastManglingParent = parent->MSLastManglingParent;
4142
MSCurManglingNumber = getMSLastManglingNumber();
4243
if ((Flags & (FnScope | ClassScope | BlockScope | TemplateParamScope |
@@ -52,6 +53,7 @@ void Scope::setFlags(Scope *parent, unsigned flags) {
5253
PrototypeIndex = 0;
5354
MSLastManglingParent = FnParent = BlockParent = nullptr;
5455
TemplateParamParent = nullptr;
56+
DeclParent = nullptr;
5557
MSLastManglingNumber = 1;
5658
MSCurManglingNumber = 1;
5759
}
@@ -76,6 +78,7 @@ void Scope::setFlags(Scope *parent, unsigned flags) {
7678
PrototypeDepth++;
7779

7880
if (flags & DeclScope) {
81+
DeclParent = this;
7982
if (flags & FunctionPrototypeScope)
8083
; // Prototype scopes are uninteresting.
8184
else if ((flags & ClassScope) && getParent()->isClassScope())

clang/lib/Sema/SemaDecl.cpp

Lines changed: 19 additions & 12 deletions
Original file line numberDiff line numberDiff line change
@@ -6359,12 +6359,6 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
63596359
} else if (DiagnoseUnexpandedParameterPack(NameInfo, UPPC_DeclarationType))
63606360
return nullptr;
63616361

6362-
// The scope passed in may not be a decl scope. Zip up the scope tree until
6363-
// we find one that is.
6364-
while ((S->getFlags() & Scope::DeclScope) == 0 ||
6365-
(S->getFlags() & Scope::TemplateParamScope) != 0)
6366-
S = S->getParent();
6367-
63686362
DeclContext *DC = CurContext;
63696363
if (D.getCXXScopeSpec().isInvalid())
63706364
D.setInvalidType();
@@ -6488,12 +6482,22 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
64886482
RemoveUsingDecls(Previous);
64896483
}
64906484

6491-
if (Previous.isSingleResult() &&
6492-
Previous.getFoundDecl()->isTemplateParameter()) {
6493-
// Maybe we will complain about the shadowed template parameter.
6494-
if (!D.isInvalidType())
6495-
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(),
6496-
Previous.getFoundDecl());
6485+
if (auto *TPD = Previous.getAsSingle<NamedDecl>();
6486+
TPD && TPD->isTemplateParameter()) {
6487+
// Older versions of clang allowed the names of function/variable templates
6488+
// to shadow the names of their template parameters. For the compatibility
6489+
// purposes we detect such cases and issue a default-to-error warning that
6490+
// can be disabled with -Wno-strict-primary-template-shadow.
6491+
if (!D.isInvalidType()) {
6492+
bool IssueShadowWarning = false;
6493+
if (Scope *DeclParent = S->getDeclParent();
6494+
Scope *TemplateParamParent = S->getTemplateParamParent()) {
6495+
IssueShadowWarning = DeclParent->Contains(*TemplateParamParent) &&
6496+
TemplateParamParent->isDeclScope(TPD);
6497+
}
6498+
DiagnoseTemplateParameterShadow(D.getIdentifierLoc(), TPD,
6499+
IssueShadowWarning);
6500+
}
64976501

64986502
// Just pretend that we didn't see the previous declaration.
64996503
Previous.clear();
@@ -6517,6 +6521,9 @@ NamedDecl *Sema::HandleDeclarator(Scope *S, Declarator &D,
65176521
if (getLangOpts().CPlusPlus)
65186522
CheckExtraCXXDefaultArguments(D);
65196523

6524+
/// Get the innermost enclosing declaration scope.
6525+
S = S->getDeclParent();
6526+
65206527
NamedDecl *New;
65216528

65226529
bool AddToScope = true;

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 4 additions & 9 deletions
Original file line numberDiff line numberDiff line change
@@ -12192,10 +12192,8 @@ Decl *Sema::ActOnUsingDirective(Scope *S, SourceLocation UsingLoc,
1219212192
assert(NamespcName && "Invalid NamespcName.");
1219312193
assert(IdentLoc.isValid() && "Invalid NamespceName location.");
1219412194

12195-
// This can only happen along a recovery path.
12196-
while (S->isTemplateParamScope())
12197-
S = S->getParent();
12198-
assert(S->getFlags() & Scope::DeclScope && "Invalid Scope.");
12195+
// Get the innermost enclosing declaration scope.
12196+
S = S->getDeclParent();
1219912197

1220012198
UsingDirectiveDecl *UDir = nullptr;
1220112199
NestedNameSpecifier *Qualifier = nullptr;
@@ -13503,11 +13501,8 @@ Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
1350313501
SourceLocation UsingLoc, UnqualifiedId &Name,
1350413502
const ParsedAttributesView &AttrList,
1350513503
TypeResult Type, Decl *DeclFromDeclSpec) {
13506-
// Skip up to the relevant declaration scope.
13507-
while (S->isTemplateParamScope())
13508-
S = S->getParent();
13509-
assert((S->getFlags() & Scope::DeclScope) &&
13510-
"got alias-declaration outside of declaration scope");
13504+
// Get the innermost enclosing declaration scope.
13505+
S = S->getDeclParent();
1351113506

1351213507
if (Type.isInvalid())
1351313508
return nullptr;

clang/lib/Sema/SemaTemplate.cpp

Lines changed: 25 additions & 15 deletions
Original file line numberDiff line numberDiff line change
@@ -885,16 +885,31 @@ 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+
///
889+
/// \param Loc The location of the declaration that shadows a template
890+
/// parameter.
891+
///
892+
/// \param PrevDecl The template parameter that the declaration shadows.
893+
///
894+
/// \param IssueWarning Whether to issue the diagnostic as a warning for
895+
/// compatibility with older versions of clang. Ignored when MSVC
896+
/// compatibility is enabled.
897+
void Sema::DiagnoseTemplateParameterShadow(SourceLocation Loc, Decl *PrevDecl,
898+
bool IssueWarning) {
889899
assert(PrevDecl->isTemplateParameter() && "Not a template parameter");
890900

891-
// C++ [temp.local]p4:
892-
// A template-parameter shall not be redeclared within its
893-
// scope (including nested scopes).
901+
// C++23 [temp.local]p6:
902+
// The name of a template-parameter shall not be bound to any following.
903+
// declaration whose locus is contained by the scope to which the
904+
// template-parameter belongs.
894905
//
895-
// 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;
906+
// When MSVC compatibility is enabled, the diagnostic is always a warning
907+
// by default. Otherwise, the diagnostic is an error unless IssueWarning
908+
// is true, in which case it is a default-to-error warning.
909+
unsigned DiagId = getLangOpts().MSVCCompat
910+
? diag::ext_template_param_shadow
911+
: (IssueWarning ? diag::ext_compat_template_param_shadow
912+
: diag::err_template_param_shadow);
898913
const auto *ND = cast<NamedDecl>(PrevDecl);
899914
Diag(Loc, DiagId) << ND->getDeclName();
900915
NoteTemplateParameterLocation(*ND);
@@ -8501,9 +8516,7 @@ Sema::CheckTemplateDeclScope(Scope *S, TemplateParameterList *TemplateParams) {
85018516
return false;
85028517

85038518
// Find the nearest enclosing declaration scope.
8504-
while ((S->getFlags() & Scope::DeclScope) == 0 ||
8505-
(S->getFlags() & Scope::TemplateParamScope) != 0)
8506-
S = S->getParent();
8519+
S = S->getDeclParent();
85078520

85088521
// C++ [temp.pre]p6: [P2096]
85098522
// A template, explicit specialization, or partial specialization shall not
@@ -10572,11 +10585,8 @@ DeclResult Sema::ActOnExplicitInstantiation(Scope *S,
1057210585
return true;
1057310586
}
1057410587

10575-
// The scope passed in may not be a decl scope. Zip up the scope tree until
10576-
// we find one that is.
10577-
while ((S->getFlags() & Scope::DeclScope) == 0 ||
10578-
(S->getFlags() & Scope::TemplateParamScope) != 0)
10579-
S = S->getParent();
10588+
// Get the innermost enclosing declaration scope.
10589+
S = S->getDeclParent();
1058010590

1058110591
// Determine the type of the declaration.
1058210592
TypeSourceInfo *T = GetTypeForDeclarator(D);

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)