Skip to content

Commit 13abf4c

Browse files
committed
[Clang][Sema] Diagnose declarative nested-name-specifiers naming alias templates
1 parent cf94e00 commit 13abf4c

File tree

4 files changed

+59
-11
lines changed

4 files changed

+59
-11
lines changed

clang/include/clang/Basic/DiagnosticSemaKinds.td

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -8250,6 +8250,9 @@ def err_not_tag_in_scope : Error<
82508250
def ext_template_after_declarative_nns : ExtWarn<
82518251
"'template' cannot be used after a declarative nested name specifier">,
82528252
InGroup<DiagGroup<"template-in-declaration-name">>;
8253+
def ext_alias_template_in_declarative_nns : ExtWarn<
8254+
"a declarative nested name specifier cannot name an alias template">,
8255+
InGroup<DiagGroup<"alias-template-in-declaration-name">>;
82538256

82548257
def err_no_typeid_with_fno_rtti : Error<
82558258
"use of typeid requires -frtti">;

clang/lib/Sema/SemaDecl.cpp

Lines changed: 26 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -6207,6 +6207,8 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
62076207
SourceLocation Loc,
62086208
TemplateIdAnnotation *TemplateId,
62096209
bool IsMemberSpecialization) {
6210+
assert(SS.isValid() && "diagnoseQualifiedDeclaration called for declaration "
6211+
"without nested-name-specifier");
62106212
DeclContext *Cur = CurContext;
62116213
while (isa<LinkageSpecDecl>(Cur) || isa<CapturedDecl>(Cur))
62126214
Cur = Cur->getParent();
@@ -6295,22 +6297,36 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
62956297
<< FixItHint::CreateRemoval(TemplateId->TemplateKWLoc);
62966298

62976299
NestedNameSpecifierLoc SpecLoc(SS.getScopeRep(), SS.location_data());
6298-
while (SpecLoc.getPrefix()) {
6300+
do {
62996301
if (SpecLoc.getNestedNameSpecifier()->getKind() ==
63006302
NestedNameSpecifier::TypeSpecWithTemplate)
63016303
Diag(Loc, diag::ext_template_after_declarative_nns)
63026304
<< FixItHint::CreateRemoval(
63036305
SpecLoc.getTypeLoc().getTemplateKeywordLoc());
63046306

6305-
SpecLoc = SpecLoc.getPrefix();
6306-
}
6307-
// C++11 [dcl.meaning]p1:
6308-
// [...] "The nested-name-specifier of the qualified declarator-id shall
6309-
// not begin with a decltype-specifer"
6310-
if (isa_and_nonnull<DecltypeType>(
6311-
SpecLoc.getNestedNameSpecifier()->getAsType()))
6312-
Diag(Loc, diag::err_decltype_in_declarator)
6313-
<< SpecLoc.getTypeLoc().getSourceRange();
6307+
if (const Type *T = SpecLoc.getNestedNameSpecifier()->getAsType()) {
6308+
if (const auto *TST = T->getAsAdjusted<TemplateSpecializationType>()) {
6309+
// C++23 [expr.prim.id.qual]p3:
6310+
// [...] If a nested-name-specifier N is declarative and has a
6311+
// simple-template-id with a template argument list A that involves a
6312+
// template parameter, let T be the template nominated by N without A.
6313+
// T shall be a class template.
6314+
if (TST->isDependentType() && TST->isTypeAlias())
6315+
Diag(Loc, diag::ext_alias_template_in_declarative_nns)
6316+
<< SpecLoc.getLocalSourceRange();
6317+
} else if (T->isDecltypeType()) {
6318+
// C++23 [expr.prim.id.qual]p2:
6319+
// [...] A declarative nested-name-specifier shall not have a
6320+
// decltype-specifier.
6321+
//
6322+
// FIXME: This wording appears to be defective as it does not forbid
6323+
// declarative nested-name-specifiers with pack-index-specifiers.
6324+
// See https://github.com/cplusplus/CWG/issues/499.
6325+
Diag(Loc, diag::err_decltype_in_declarator)
6326+
<< SpecLoc.getTypeLoc().getSourceRange();
6327+
}
6328+
}
6329+
} while ((SpecLoc = SpecLoc.getPrefix()));
63146330

63156331
return false;
63166332
}
Lines changed: 29 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,29 @@
1+
// RUN: %clang_cc1 -verify %s
2+
3+
template<typename T>
4+
struct A {
5+
void f();
6+
};
7+
8+
template<typename T>
9+
using B = A<T>;
10+
11+
template<typename T>
12+
void B<T>::f() { } // expected-warning {{a declarative nested name specifier cannot name an alias template}}
13+
14+
template<>
15+
void B<int>::f() { } // ok, template argument list of simple-template-id doesn't involve template parameters
16+
17+
namespace N {
18+
19+
template<typename T>
20+
struct D {
21+
void f();
22+
};
23+
24+
template<typename T>
25+
using E = D<T>;
26+
}
27+
28+
template<typename T>
29+
void N::E<T>::f() { } // expected-warning {{a declarative nested name specifier cannot name an alias template}}

clang/test/CXX/temp/temp.res/temp.dep/temp.dep.type/p1.cpp

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -26,5 +26,5 @@ namespace Example2 {
2626
void g();
2727
};
2828
template<class T> using B = A<T>;
29-
template<class T> void B<T>::g() {} // ok.
29+
template<class T> void B<T>::g() {} // // expected-warning {{a declarative nested name specifier cannot name an alias template}}
3030
}

0 commit comments

Comments
 (0)