Skip to content

Commit bc4d50f

Browse files
authored
[clang] Implement CWG2877 "Type-only lookup for using-enum-declarator" (#95399)
This patch implements 2024-05-31 resolution of a tentatively ready issue [CWG2877](https://cplusplus.github.io/CWG/issues/2877.html) "Type-only lookup for using-enum-declarator", which supersedes earlier [CWG2621](https://cplusplus.github.io/CWG/issues/2621.html) "Kind of lookup for `using enum` declarations". Now we perform type-only lookup (not to be confused with type-only context) for `elaborated-enum-declarator`. This is the same kind of lookup that elaborated type specifiers and base specifiers undergo. I also found out (and fixed) that one of our existing tests claimed that a dependent type can be used in `elaborated-enum-declarator`, but that's not the case: > The [using-enum-declarator](http://eel.is/c++draft/enum.udecl#nt:using-enum-declarator) shall designate a non-dependent type with a reachable [enum-specifier](http://eel.is/c++draft/dcl.enum#nt:enum-specifier)[.](http://eel.is/c++draft/enum.udecl#1.sentence-2)
1 parent aed9891 commit bc4d50f

File tree

8 files changed

+73
-35
lines changed

8 files changed

+73
-35
lines changed

clang/docs/ReleaseNotes.rst

Lines changed: 3 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -287,6 +287,9 @@ Resolutions to C++ Defect Reports
287287
- P0522 implementation is enabled by default in all language versions, and
288288
provisional wording for CWG2398 is implemented.
289289

290+
- Clang now performs type-only lookup for the name in ``using enum`` declaration.
291+
(`CWG2877: Type-only lookup for using-enum-declarator <https://cplusplus.github.io/CWG/issues/2877.html>`_).
292+
290293
- Clang now requires a template argument list after a template keyword.
291294
(`CWG96: Syntactic disambiguation using the template keyword <https://cplusplus.github.io/CWG/issues/96.html>`_).
292295

clang/include/clang/Sema/Sema.h

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -4031,8 +4031,8 @@ class Sema final : public SemaBase {
40314031
const ParsedAttributesView &AttrList);
40324032
Decl *ActOnUsingEnumDeclaration(Scope *CurScope, AccessSpecifier AS,
40334033
SourceLocation UsingLoc,
4034-
SourceLocation EnumLoc,
4035-
SourceLocation IdentLoc, IdentifierInfo &II,
4034+
SourceLocation EnumLoc, SourceRange TyLoc,
4035+
const IdentifierInfo &II, ParsedType Ty,
40364036
CXXScopeSpec *SS = nullptr);
40374037
Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS,
40384038
MultiTemplateParamsArg TemplateParams,

clang/lib/Parse/ParseDeclCXX.cpp

Lines changed: 42 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -692,7 +692,7 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
692692
/// using-enum-declaration: [C++20, dcl.enum]
693693
/// 'using' elaborated-enum-specifier ;
694694
/// The terminal name of the elaborated-enum-specifier undergoes
695-
/// ordinary lookup
695+
/// type-only lookup
696696
///
697697
/// elaborated-enum-specifier:
698698
/// 'enum' nested-name-specifier[opt] identifier
@@ -724,7 +724,7 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
724724
/*ObectHasErrors=*/false,
725725
/*EnteringConttext=*/false,
726726
/*MayBePseudoDestructor=*/nullptr,
727-
/*IsTypename=*/false,
727+
/*IsTypename=*/true,
728728
/*IdentifierInfo=*/nullptr,
729729
/*OnlyNamespace=*/false,
730730
/*InUsingDeclaration=*/true)) {
@@ -738,16 +738,49 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
738738
return nullptr;
739739
}
740740

741-
if (!Tok.is(tok::identifier)) {
741+
Decl *UED = nullptr;
742+
743+
// FIXME: identifier and annot_template_id handling is very similar to
744+
// ParseBaseTypeSpecifier. It should be factored out into a function.
745+
if (Tok.is(tok::identifier)) {
746+
IdentifierInfo *IdentInfo = Tok.getIdentifierInfo();
747+
SourceLocation IdentLoc = ConsumeToken();
748+
749+
ParsedType Type = Actions.getTypeName(
750+
*IdentInfo, IdentLoc, getCurScope(), &SS, /*isClassName=*/true,
751+
/*HasTrailingDot=*/false,
752+
/*ObjectType=*/nullptr, /*IsCtorOrDtorName=*/false,
753+
/*WantNontrivialTypeSourceInfo=*/true);
754+
755+
UED = Actions.ActOnUsingEnumDeclaration(
756+
getCurScope(), AS, UsingLoc, UELoc, IdentLoc, *IdentInfo, Type, &SS);
757+
} else if (Tok.is(tok::annot_template_id)) {
758+
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
759+
760+
if (TemplateId->mightBeType()) {
761+
AnnotateTemplateIdTokenAsType(SS, ImplicitTypenameContext::No,
762+
/*IsClassName=*/true);
763+
764+
assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
765+
TypeResult Type = getTypeAnnotation(Tok);
766+
SourceRange Loc = Tok.getAnnotationRange();
767+
ConsumeAnnotationToken();
768+
769+
UED = Actions.ActOnUsingEnumDeclaration(getCurScope(), AS, UsingLoc,
770+
UELoc, Loc, *TemplateId->Name,
771+
Type.get(), &SS);
772+
} else {
773+
Diag(Tok.getLocation(), diag::err_using_enum_not_enum)
774+
<< TemplateId->Name->getName()
775+
<< SourceRange(TemplateId->TemplateNameLoc, TemplateId->RAngleLoc);
776+
}
777+
} else {
742778
Diag(Tok.getLocation(), diag::err_using_enum_expect_identifier)
743779
<< Tok.is(tok::kw_enum);
744780
SkipUntil(tok::semi);
745781
return nullptr;
746782
}
747-
IdentifierInfo *IdentInfo = Tok.getIdentifierInfo();
748-
SourceLocation IdentLoc = ConsumeToken();
749-
Decl *UED = Actions.ActOnUsingEnumDeclaration(
750-
getCurScope(), AS, UsingLoc, UELoc, IdentLoc, *IdentInfo, &SS);
783+
751784
if (!UED) {
752785
SkipUntil(tok::semi);
753786
return nullptr;
@@ -1403,6 +1436,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
14031436
}
14041437

14051438
// Check whether we have a template-id that names a type.
1439+
// FIXME: identifier and annot_template_id handling in ParseUsingDeclaration
1440+
// work very similarly. It should be refactored into a separate function.
14061441
if (Tok.is(tok::annot_template_id)) {
14071442
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
14081443
if (TemplateId->mightBeType()) {

clang/lib/Sema/SemaDeclCXX.cpp

Lines changed: 11 additions & 10 deletions
Original file line numberDiff line numberDiff line change
@@ -12372,23 +12372,24 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS,
1237212372

1237312373
Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
1237412374
SourceLocation UsingLoc,
12375-
SourceLocation EnumLoc,
12376-
SourceLocation IdentLoc,
12377-
IdentifierInfo &II, CXXScopeSpec *SS) {
12375+
SourceLocation EnumLoc, SourceRange TyLoc,
12376+
const IdentifierInfo &II, ParsedType Ty,
12377+
CXXScopeSpec *SS) {
1237812378
assert(!SS->isInvalid() && "ScopeSpec is invalid");
1237912379
TypeSourceInfo *TSI = nullptr;
12380-
QualType EnumTy = GetTypeFromParser(
12381-
getTypeName(II, IdentLoc, S, SS, /*isClassName=*/false,
12382-
/*HasTrailingDot=*/false,
12383-
/*ObjectType=*/nullptr, /*IsCtorOrDtorName=*/false,
12384-
/*WantNontrivialTypeSourceInfo=*/true),
12385-
&TSI);
12380+
SourceLocation IdentLoc = TyLoc.getBegin();
12381+
QualType EnumTy = GetTypeFromParser(Ty, &TSI);
1238612382
if (EnumTy.isNull()) {
1238712383
Diag(IdentLoc, SS && isDependentScopeSpecifier(*SS)
1238812384
? diag::err_using_enum_is_dependent
1238912385
: diag::err_unknown_typename)
1239012386
<< II.getName()
12391-
<< SourceRange(SS ? SS->getBeginLoc() : IdentLoc, IdentLoc);
12387+
<< SourceRange(SS ? SS->getBeginLoc() : IdentLoc, TyLoc.getEnd());
12388+
return nullptr;
12389+
}
12390+
12391+
if (EnumTy->isDependentType()) {
12392+
Diag(IdentLoc, diag::err_using_enum_is_dependent);
1239212393
return nullptr;
1239312394
}
1239412395

clang/test/CXX/drs/cwg26xx.cpp

Lines changed: 2 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,7 @@
77
// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown -pedantic-errors %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
88

99

10-
namespace cwg2621 { // cwg2621: 16
10+
namespace cwg2621 { // cwg2621: sup 2877
1111
#if __cplusplus >= 202002L
1212
enum class E { a };
1313
namespace One {
@@ -17,9 +17,8 @@ auto v = a;
1717
}
1818
namespace Two {
1919
using cwg2621::E;
20-
int E; // we see this
20+
int E; // ignored by type-only lookup
2121
using enum E;
22-
// since-cxx20-error@-1 {{unknown type name E}}
2322
}
2423
#endif
2524
}

clang/test/CXX/drs/cwg28xx.cpp

Lines changed: 3 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -110,22 +110,18 @@ struct A {
110110

111111
} // namespace cwg2858
112112

113-
namespace cwg2877 { // cwg2877: no tentatively ready 2024-05-31
113+
namespace cwg2877 { // cwg2877: 19 tentatively ready 2024-05-31
114114
#if __cplusplus >= 202002L
115115
enum E { x };
116116
void f() {
117117
int E;
118-
// FIXME: OK, names ::E
119-
using enum E;
120-
// since-cxx20-error@-1 {{unknown type name E}}
118+
using enum E; // OK, names ::E
121119
}
122120
using F = E;
123121
using enum F; // OK, designates ::E
124122
template<class T> using EE = T;
125123
void g() {
126-
// FIXME: OK, designates ::E
127-
using enum EE<E>;
128-
// since-cxx20-error@-1 {{using enum requires an enum or typedef name}}
124+
using enum EE<E>; // OK, designates ::E
129125
}
130126
#endif
131127
} // namespace cwg2877

clang/test/SemaCXX/cxx20-using-enum.cpp

Lines changed: 8 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -148,13 +148,10 @@ template <int I> struct C {
148148
enum class D { d,
149149
e,
150150
f };
151-
using enum D;
152-
153-
static constexpr int W = int(f) + I;
151+
using enum D; // expected-error {{using-enum cannot name a dependent type}}
154152
};
155153

156154
static_assert(C<2>::V == 4);
157-
static_assert(C<20>::W == 22);
158155

159156
} // namespace Seven
160157

@@ -241,6 +238,13 @@ TPLa<int> a;
241238

242239
} // namespace Thirteen
243240

241+
namespace Fourteen {
242+
template<typename T>
243+
int A = T();
244+
245+
using enum A<int>; // expected-error {{A is not an enumerated type}}
246+
} // namespace Fourteen
247+
244248
namespace GH58057 {
245249
struct Wrap {
246250
enum Things {

clang/www/cxx_dr_status.html

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -15541,7 +15541,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
1554115541
<td><a href="https://cplusplus.github.io/CWG/issues/2621.html">2621</a></td>
1554215542
<td>C++23</td>
1554315543
<td>Kind of lookup for <TT>using enum</TT> declarations</td>
15544-
<td class="full" align="center">Clang 16</td>
15544+
<td title="Clang 19 implements 2024-05-31 resolution" align="center">Superseded by <a href="#2877">2877</a></td>
1554515545
</tr>
1554615546
<tr id="2622">
1554715547
<td><a href="https://cplusplus.github.io/CWG/issues/2622.html">2622</a></td>
@@ -17078,7 +17078,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
1707817078
<td><a href="https://cplusplus.github.io/CWG/issues/2877.html">2877</a></td>
1707917079
<td>tentatively ready</td>
1708017080
<td>Type-only lookup for <I>using-enum-declarator</I></td>
17081-
<td title="Clang does not implement 2024-05-31 resolution" align="center">Not Resolved*</td>
17081+
<td title="Clang 19 implements 2024-05-31 resolution" align="center">Not Resolved*</td>
1708217082
</tr>
1708317083
<tr class="open" id="2878">
1708417084
<td><a href="https://cplusplus.github.io/CWG/issues/2878.html">2878</a></td>

0 commit comments

Comments
 (0)