diff options
author | Krystian Stasiowski <sdkrystian@gmail.com> | 2024-02-20 13:25:12 -0500 |
---|---|---|
committer | GitHub <noreply@github.com> | 2024-02-20 13:25:12 -0500 |
commit | fb615cf3b9c2d887441a4c0cca326eddc592351a (patch) | |
tree | b779a4f9feedd0796c9c66e5bbb0455545958be1 /clang/lib/Sema/SemaDecl.cpp | |
parent | c625b996527335c4fd6b6aa246655a993487e846 (diff) | |
download | llvm-fb615cf3b9c2d887441a4c0cca326eddc592351a.zip llvm-fb615cf3b9c2d887441a4c0cca326eddc592351a.tar.gz llvm-fb615cf3b9c2d887441a4c0cca326eddc592351a.tar.bz2 |
[Clang][Sema] Diagnose declarative nested-name-specifiers naming alias templates (#80842)
According to [expr.prim.id.qual] p3:
> The _nested-name-specifier_ `::` nominates the global namespace. A
_nested-name-specifier_ with a _computed-type-specifier_ nominates the
type denoted by the _computed-type-specifier_, which shall be a class or
enumeration type. **If a _nested-name-specifier_ `N` is declarative and
has a _simple-template-id_ with a template argument list `A` that
involves a template parameter, let `T` be the template nominated by `N`
without `A`. `T` shall be a class template.**
Meaning, the out-of-line definition of `A::f` in the following example
is ill-formed:
```
template<typename T>
struct A
{
void f();
};
template<typename T>
using B = A<T>;
template<typename T>
void B<T>::f() { } // error: a declarative nested name specifier cannot name an alias template
```
This patch diagnoses such cases as an extension (in group `alias-template-in-declaration-name`).
Diffstat (limited to 'clang/lib/Sema/SemaDecl.cpp')
-rw-r--r-- | clang/lib/Sema/SemaDecl.cpp | 36 |
1 files changed, 26 insertions, 10 deletions
diff --git a/clang/lib/Sema/SemaDecl.cpp b/clang/lib/Sema/SemaDecl.cpp index 558109d..10b5c27 100644 --- a/clang/lib/Sema/SemaDecl.cpp +++ b/clang/lib/Sema/SemaDecl.cpp @@ -6210,6 +6210,8 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, SourceLocation Loc, TemplateIdAnnotation *TemplateId, bool IsMemberSpecialization) { + assert(SS.isValid() && "diagnoseQualifiedDeclaration called for declaration " + "without nested-name-specifier"); DeclContext *Cur = CurContext; while (isa<LinkageSpecDecl>(Cur) || isa<CapturedDecl>(Cur)) Cur = Cur->getParent(); @@ -6298,22 +6300,36 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC, << FixItHint::CreateRemoval(TemplateId->TemplateKWLoc); NestedNameSpecifierLoc SpecLoc(SS.getScopeRep(), SS.location_data()); - while (SpecLoc.getPrefix()) { + do { if (SpecLoc.getNestedNameSpecifier()->getKind() == NestedNameSpecifier::TypeSpecWithTemplate) Diag(Loc, diag::ext_template_after_declarative_nns) << FixItHint::CreateRemoval( SpecLoc.getTypeLoc().getTemplateKeywordLoc()); - SpecLoc = SpecLoc.getPrefix(); - } - // C++11 [dcl.meaning]p1: - // [...] "The nested-name-specifier of the qualified declarator-id shall - // not begin with a decltype-specifer" - if (isa_and_nonnull<DecltypeType>( - SpecLoc.getNestedNameSpecifier()->getAsType())) - Diag(Loc, diag::err_decltype_in_declarator) - << SpecLoc.getTypeLoc().getSourceRange(); + if (const Type *T = SpecLoc.getNestedNameSpecifier()->getAsType()) { + if (const auto *TST = T->getAsAdjusted<TemplateSpecializationType>()) { + // C++23 [expr.prim.id.qual]p3: + // [...] If a nested-name-specifier N is declarative and has a + // simple-template-id with a template argument list A that involves a + // template parameter, let T be the template nominated by N without A. + // T shall be a class template. + if (TST->isDependentType() && TST->isTypeAlias()) + Diag(Loc, diag::ext_alias_template_in_declarative_nns) + << SpecLoc.getLocalSourceRange(); + } else if (T->isDecltypeType()) { + // C++23 [expr.prim.id.qual]p2: + // [...] A declarative nested-name-specifier shall not have a + // decltype-specifier. + // + // FIXME: This wording appears to be defective as it does not forbid + // declarative nested-name-specifiers with pack-index-specifiers. + // See https://github.com/cplusplus/CWG/issues/499. + Diag(Loc, diag::err_decltype_in_declarator) + << SpecLoc.getTypeLoc().getSourceRange(); + } + } + } while ((SpecLoc = SpecLoc.getPrefix())); return false; } |