[Clang][Sema] Implement approved resolution for CWG2858 (#88042)

The approved resolution for CWG2858 changes
[expr.prim.id.qual] p2 sentence 2 to read:
> A declarative _nested-name-specifier_ shall not have a
_computed-type-specifier_.

This patch implements the approved resolution. Since we don't consider
_nested-name-specifiers_ in friend declarations to be declarative (yet),
it currently isn't possible to write a test that would produce this
diagnostic (`diagnoseQualifiedDeclaration` is never called if the
`DeclContext` can't be computed). Nevertheless, tests were added which
will produce the diagnostic once we start calling
`diagnoseQualifiedDeclaration` for friend declarations.
This commit is contained in:
Krystian Stasiowski 2024-04-11 11:23:24 -04:00 committed by GitHub
parent 44718311de
commit 198ffb8531
No known key found for this signature in database
GPG Key ID: B5690EEEBB952194
6 changed files with 40 additions and 16 deletions

View File

@ -147,6 +147,9 @@ Resolutions to C++ Defect Reports
compatibility of two types.
(`CWG2759: [[no_unique_address] and common initial sequence <https://cplusplus.github.io/CWG/issues/2759.html>`_).
- Clang now diagnoses declarative nested-name-specifiers with pack-index-specifiers.
(`CWG2858: Declarative nested-name-specifiers and pack-index-specifiers <https://cplusplus.github.io/CWG/issues/2858.html>`_).
C Language Changes
------------------

View File

@ -2402,10 +2402,6 @@ def err_selected_explicit_constructor : Error<
def note_explicit_ctor_deduction_guide_here : Note<
"explicit %select{constructor|deduction guide}0 declared here">;
// C++11 decltype
def err_decltype_in_declarator : Error<
"'decltype' cannot be used to name a declaration">;
// C++11 auto
def warn_cxx98_compat_auto_type_specifier : Warning<
"'auto' type specifier is incompatible with C++98">,
@ -8313,6 +8309,9 @@ def ext_template_after_declarative_nns : ExtWarn<
def ext_alias_template_in_declarative_nns : ExtWarn<
"a declarative nested name specifier cannot name an alias template">,
InGroup<DiagGroup<"alias-template-in-declaration-name">>;
def err_computed_type_in_declarative_nns : Error<
"a %select{pack indexing|'decltype'}0 specifier cannot be used in "
"a declarative nested name specifier">;
def err_no_typeid_with_fno_rtti : Error<
"use of typeid requires -frtti">;

View File

@ -6335,16 +6335,15 @@ bool Sema::diagnoseQualifiedDeclaration(CXXScopeSpec &SS, DeclContext *DC,
if (TST->isDependentType() && TST->isTypeAlias())
Diag(Loc, diag::ext_alias_template_in_declarative_nns)
<< SpecLoc.getLocalSourceRange();
} else if (T->isDecltypeType()) {
} else if (T->isDecltypeType() || T->getAsAdjusted<PackIndexingType>()) {
// C++23 [expr.prim.id.qual]p2:
// [...] A declarative nested-name-specifier shall not have a
// decltype-specifier.
// computed-type-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();
// CWG2858 changed this from 'decltype-specifier' to
// 'computed-type-specifier'.
Diag(Loc, diag::err_computed_type_in_declarative_nns)
<< T->isDecltypeType() << SpecLoc.getTypeLoc().getSourceRange();
}
}
} while ((SpecLoc = SpecLoc.getPrefix()));

View File

@ -6,8 +6,8 @@ class foo {
void func();
};
int decltype(foo())::i; // expected-error{{'decltype' cannot be used to name a declaration}}
void decltype(foo())::func() { // expected-error{{'decltype' cannot be used to name a declaration}}
int decltype(foo())::i; // expected-error{{a 'decltype' specifier cannot be used in a declarative nested name specifier}}
void decltype(foo())::func() { // expected-error{{a 'decltype' specifier cannot be used in a declarative nested name specifier}}
}

View File

@ -58,3 +58,26 @@ void B<int>::g() requires true;
#endif
} // namespace dr2847
namespace dr2858 { // dr2858: 19
#if __cplusplus > 202302L
template<typename... Ts>
struct A {
// FIXME: The nested-name-specifier in the following friend declarations are declarative,
// but we don't treat them as such (yet).
friend void Ts...[0]::f();
template<typename U>
friend void Ts...[0]::g();
friend struct Ts...[0]::B;
// FIXME: The index of the pack-index-specifier is printed as a memory address in the diagnostic.
template<typename U>
friend struct Ts...[0]::C;
// expected-warning-re@-1 {{dependent nested name specifier 'Ts...[{{.*}}]::' for friend template declaration is not supported; ignoring this friend declaration}}
};
#endif
} // namespace dr2858

View File

@ -59,14 +59,14 @@ typedef union {
} y;
} bug3177;
// check that we don't consume the token after the access specifier
// check that we don't consume the token after the access specifier
// when it's not a colon
class D {
public // expected-error{{expected ':'}}
int i;
};
// consume the token after the access specifier if it's a semicolon
// consume the token after the access specifier if it's a semicolon
// that was meant to be a colon
class E {
public; // expected-error{{expected ':'}}
@ -281,7 +281,7 @@ struct A {} ::PR41192::a; // ok, no missing ';' here expected-warning {{extra q
#if __cplusplus >= 201103L
struct C;
struct D { static C c; };
struct C {} decltype(D())::c; // expected-error {{'decltype' cannot be used to name a declaration}}
struct C {} decltype(D())::c; // expected-error {{a 'decltype' specifier cannot be used in a declarative nested name specifier}}
#endif
}