[clang] bc4d50f - [clang] Implement CWG2877 "Type-only lookup for using-enum-declarator" (#95399)
via cfe-commits
cfe-commits at lists.llvm.org
Fri Jun 21 02:49:46 PDT 2024
Author: Vlad Serebrennikov
Date: 2024-06-21T13:49:43+04:00
New Revision: bc4d50f02ded9eea287daccf2b4a39ae5d30abd0
URL: https://github.com/llvm/llvm-project/commit/bc4d50f02ded9eea287daccf2b4a39ae5d30abd0
DIFF: https://github.com/llvm/llvm-project/commit/bc4d50f02ded9eea287daccf2b4a39ae5d30abd0.diff
LOG: [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)
Added:
Modified:
clang/docs/ReleaseNotes.rst
clang/include/clang/Sema/Sema.h
clang/lib/Parse/ParseDeclCXX.cpp
clang/lib/Sema/SemaDeclCXX.cpp
clang/test/CXX/drs/cwg26xx.cpp
clang/test/CXX/drs/cwg28xx.cpp
clang/test/SemaCXX/cxx20-using-enum.cpp
clang/www/cxx_dr_status.html
Removed:
################################################################################
diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 88969a0131038..455c34bce0684 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -287,6 +287,9 @@ Resolutions to C++ Defect Reports
- P0522 implementation is enabled by default in all language versions, and
provisional wording for CWG2398 is implemented.
+- Clang now performs type-only lookup for the name in ``using enum`` declaration.
+ (`CWG2877: Type-only lookup for using-enum-declarator <https://cplusplus.github.io/CWG/issues/2877.html>`_).
+
- Clang now requires a template argument list after a template keyword.
(`CWG96: Syntactic disambiguation using the template keyword <https://cplusplus.github.io/CWG/issues/96.html>`_).
diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h
index 95a732bcba618..e43e5f465361d 100644
--- a/clang/include/clang/Sema/Sema.h
+++ b/clang/include/clang/Sema/Sema.h
@@ -4031,8 +4031,8 @@ class Sema final : public SemaBase {
const ParsedAttributesView &AttrList);
Decl *ActOnUsingEnumDeclaration(Scope *CurScope, AccessSpecifier AS,
SourceLocation UsingLoc,
- SourceLocation EnumLoc,
- SourceLocation IdentLoc, IdentifierInfo &II,
+ SourceLocation EnumLoc, SourceRange TyLoc,
+ const IdentifierInfo &II, ParsedType Ty,
CXXScopeSpec *SS = nullptr);
Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS,
MultiTemplateParamsArg TemplateParams,
diff --git a/clang/lib/Parse/ParseDeclCXX.cpp b/clang/lib/Parse/ParseDeclCXX.cpp
index d02548f6441f9..5e3ee5f0579aa 100644
--- a/clang/lib/Parse/ParseDeclCXX.cpp
+++ b/clang/lib/Parse/ParseDeclCXX.cpp
@@ -692,7 +692,7 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
/// using-enum-declaration: [C++20, dcl.enum]
/// 'using' elaborated-enum-specifier ;
/// The terminal name of the elaborated-enum-specifier undergoes
-/// ordinary lookup
+/// type-only lookup
///
/// elaborated-enum-specifier:
/// 'enum' nested-name-specifier[opt] identifier
@@ -724,7 +724,7 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
/*ObectHasErrors=*/false,
/*EnteringConttext=*/false,
/*MayBePseudoDestructor=*/nullptr,
- /*IsTypename=*/false,
+ /*IsTypename=*/true,
/*IdentifierInfo=*/nullptr,
/*OnlyNamespace=*/false,
/*InUsingDeclaration=*/true)) {
@@ -738,16 +738,49 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
return nullptr;
}
- if (!Tok.is(tok::identifier)) {
+ Decl *UED = nullptr;
+
+ // FIXME: identifier and annot_template_id handling is very similar to
+ // ParseBaseTypeSpecifier. It should be factored out into a function.
+ if (Tok.is(tok::identifier)) {
+ IdentifierInfo *IdentInfo = Tok.getIdentifierInfo();
+ SourceLocation IdentLoc = ConsumeToken();
+
+ ParsedType Type = Actions.getTypeName(
+ *IdentInfo, IdentLoc, getCurScope(), &SS, /*isClassName=*/true,
+ /*HasTrailingDot=*/false,
+ /*ObjectType=*/nullptr, /*IsCtorOrDtorName=*/false,
+ /*WantNontrivialTypeSourceInfo=*/true);
+
+ UED = Actions.ActOnUsingEnumDeclaration(
+ getCurScope(), AS, UsingLoc, UELoc, IdentLoc, *IdentInfo, Type, &SS);
+ } else if (Tok.is(tok::annot_template_id)) {
+ TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
+
+ if (TemplateId->mightBeType()) {
+ AnnotateTemplateIdTokenAsType(SS, ImplicitTypenameContext::No,
+ /*IsClassName=*/true);
+
+ assert(Tok.is(tok::annot_typename) && "template-id -> type failed");
+ TypeResult Type = getTypeAnnotation(Tok);
+ SourceRange Loc = Tok.getAnnotationRange();
+ ConsumeAnnotationToken();
+
+ UED = Actions.ActOnUsingEnumDeclaration(getCurScope(), AS, UsingLoc,
+ UELoc, Loc, *TemplateId->Name,
+ Type.get(), &SS);
+ } else {
+ Diag(Tok.getLocation(), diag::err_using_enum_not_enum)
+ << TemplateId->Name->getName()
+ << SourceRange(TemplateId->TemplateNameLoc, TemplateId->RAngleLoc);
+ }
+ } else {
Diag(Tok.getLocation(), diag::err_using_enum_expect_identifier)
<< Tok.is(tok::kw_enum);
SkipUntil(tok::semi);
return nullptr;
}
- IdentifierInfo *IdentInfo = Tok.getIdentifierInfo();
- SourceLocation IdentLoc = ConsumeToken();
- Decl *UED = Actions.ActOnUsingEnumDeclaration(
- getCurScope(), AS, UsingLoc, UELoc, IdentLoc, *IdentInfo, &SS);
+
if (!UED) {
SkipUntil(tok::semi);
return nullptr;
@@ -1403,6 +1436,8 @@ TypeResult Parser::ParseBaseTypeSpecifier(SourceLocation &BaseLoc,
}
// Check whether we have a template-id that names a type.
+ // FIXME: identifier and annot_template_id handling in ParseUsingDeclaration
+ // work very similarly. It should be refactored into a separate function.
if (Tok.is(tok::annot_template_id)) {
TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok);
if (TemplateId->mightBeType()) {
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index c1189e6935dc9..234e89b91da07 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -12372,23 +12372,24 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS,
Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
- SourceLocation EnumLoc,
- SourceLocation IdentLoc,
- IdentifierInfo &II, CXXScopeSpec *SS) {
+ SourceLocation EnumLoc, SourceRange TyLoc,
+ const IdentifierInfo &II, ParsedType Ty,
+ CXXScopeSpec *SS) {
assert(!SS->isInvalid() && "ScopeSpec is invalid");
TypeSourceInfo *TSI = nullptr;
- QualType EnumTy = GetTypeFromParser(
- getTypeName(II, IdentLoc, S, SS, /*isClassName=*/false,
- /*HasTrailingDot=*/false,
- /*ObjectType=*/nullptr, /*IsCtorOrDtorName=*/false,
- /*WantNontrivialTypeSourceInfo=*/true),
- &TSI);
+ SourceLocation IdentLoc = TyLoc.getBegin();
+ QualType EnumTy = GetTypeFromParser(Ty, &TSI);
if (EnumTy.isNull()) {
Diag(IdentLoc, SS && isDependentScopeSpecifier(*SS)
? diag::err_using_enum_is_dependent
: diag::err_unknown_typename)
<< II.getName()
- << SourceRange(SS ? SS->getBeginLoc() : IdentLoc, IdentLoc);
+ << SourceRange(SS ? SS->getBeginLoc() : IdentLoc, TyLoc.getEnd());
+ return nullptr;
+ }
+
+ if (EnumTy->isDependentType()) {
+ Diag(IdentLoc, diag::err_using_enum_is_dependent);
return nullptr;
}
diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp
index 2b17c8101438d..e180c93011a7e 100644
--- a/clang/test/CXX/drs/cwg26xx.cpp
+++ b/clang/test/CXX/drs/cwg26xx.cpp
@@ -7,7 +7,7 @@
// RUN: %clang_cc1 -std=c++2c -triple x86_64-unknown-unknown -pedantic-errors %s -verify=expected,since-cxx11,since-cxx20,since-cxx23
-namespace cwg2621 { // cwg2621: 16
+namespace cwg2621 { // cwg2621: sup 2877
#if __cplusplus >= 202002L
enum class E { a };
namespace One {
@@ -17,9 +17,8 @@ auto v = a;
}
namespace Two {
using cwg2621::E;
-int E; // we see this
+int E; // ignored by type-only lookup
using enum E;
-// since-cxx20-error at -1 {{unknown type name E}}
}
#endif
}
diff --git a/clang/test/CXX/drs/cwg28xx.cpp b/clang/test/CXX/drs/cwg28xx.cpp
index da81eccc8dc22..67aa34484fe8b 100644
--- a/clang/test/CXX/drs/cwg28xx.cpp
+++ b/clang/test/CXX/drs/cwg28xx.cpp
@@ -110,22 +110,18 @@ struct A {
} // namespace cwg2858
-namespace cwg2877 { // cwg2877: no tentatively ready 2024-05-31
+namespace cwg2877 { // cwg2877: 19 tentatively ready 2024-05-31
#if __cplusplus >= 202002L
enum E { x };
void f() {
int E;
- // FIXME: OK, names ::E
- using enum E;
- // since-cxx20-error at -1 {{unknown type name E}}
+ using enum E; // OK, names ::E
}
using F = E;
using enum F; // OK, designates ::E
template<class T> using EE = T;
void g() {
- // FIXME: OK, designates ::E
- using enum EE<E>;
- // since-cxx20-error at -1 {{using enum requires an enum or typedef name}}
+ using enum EE<E>; // OK, designates ::E
}
#endif
} // namespace cwg2877
diff --git a/clang/test/SemaCXX/cxx20-using-enum.cpp b/clang/test/SemaCXX/cxx20-using-enum.cpp
index d16df4e1b9d3c..14ef4b29925a1 100644
--- a/clang/test/SemaCXX/cxx20-using-enum.cpp
+++ b/clang/test/SemaCXX/cxx20-using-enum.cpp
@@ -148,13 +148,10 @@ template <int I> struct C {
enum class D { d,
e,
f };
- using enum D;
-
- static constexpr int W = int(f) + I;
+ using enum D; // expected-error {{using-enum cannot name a dependent type}}
};
static_assert(C<2>::V == 4);
-static_assert(C<20>::W == 22);
} // namespace Seven
@@ -241,6 +238,13 @@ TPLa<int> a;
} // namespace Thirteen
+namespace Fourteen {
+template<typename T>
+int A = T();
+
+using enum A<int>; // expected-error {{A is not an enumerated type}}
+} // namespace Fourteen
+
namespace GH58057 {
struct Wrap {
enum Things {
diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html
index 1b523cf12854c..7474a4f65585b 100755
--- a/clang/www/cxx_dr_status.html
+++ b/clang/www/cxx_dr_status.html
@@ -15541,7 +15541,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2>
<td><a href="https://cplusplus.github.io/CWG/issues/2621.html">2621</a></td>
<td>C++23</td>
<td>Kind of lookup for <TT>using enum</TT> declarations</td>
- <td class="full" align="center">Clang 16</td>
+ <td title="Clang 19 implements 2024-05-31 resolution" align="center">Superseded by <a href="#2877">2877</a></td>
</tr>
<tr id="2622">
<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>
<td><a href="https://cplusplus.github.io/CWG/issues/2877.html">2877</a></td>
<td>tentatively ready</td>
<td>Type-only lookup for <I>using-enum-declarator</I></td>
- <td title="Clang does not implement 2024-05-31 resolution" align="center">Not Resolved*</td>
+ <td title="Clang 19 implements 2024-05-31 resolution" align="center">Not Resolved*</td>
</tr>
<tr class="open" id="2878">
<td><a href="https://cplusplus.github.io/CWG/issues/2878.html">2878</a></td>
More information about the cfe-commits
mailing list