https://github.com/Endilll created https://github.com/llvm/llvm-project/pull/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`. I also found out 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) >From a7b6a8b667d48d8e70f3e5fcbaaa44a72ad885db Mon Sep 17 00:00:00 2001 From: Vlad Serebrennikov <serebrennikov.vladis...@gmail.com> Date: Thu, 13 Jun 2024 14:35:08 +0300 Subject: [PATCH 1/2] [clang] Implement CWG2877 "Type-only lookup for using-enum-declarator" --- clang/include/clang/Sema/Sema.h | 2 +- clang/lib/Parse/ParseDeclCXX.cpp | 44 +++++++++++++++++++++---- clang/lib/Sema/SemaDeclCXX.cpp | 19 ++++++----- clang/test/CXX/drs/cwg26xx.cpp | 5 ++- clang/test/CXX/drs/cwg28xx.cpp | 10 ++---- clang/test/SemaCXX/cxx20-using-enum.cpp | 12 ++++--- clang/www/cxx_dr_status.html | 10 ++++-- 7 files changed, 70 insertions(+), 32 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index 4d4579fcfd456..ccabd4925b8a3 100644 --- a/clang/include/clang/Sema/Sema.h +++ b/clang/include/clang/Sema/Sema.h @@ -4032,7 +4032,7 @@ class Sema final : public SemaBase { Decl *ActOnUsingEnumDeclaration(Scope *CurScope, AccessSpecifier AS, SourceLocation UsingLoc, SourceLocation EnumLoc, - SourceLocation IdentLoc, IdentifierInfo &II, + 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 9a4a777f575b2..189fcc5440292 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 @@ -738,16 +738,48 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration( return nullptr; } - if (!Tok.is(tok::identifier)) { + Decl *UED = nullptr; + + 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; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 37f0df2a6a27d..fb9e38d6b5bc9 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -12395,22 +12395,23 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, SourceLocation EnumLoc, - SourceLocation IdentLoc, - IdentifierInfo &II, CXXScopeSpec *SS) { + 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@-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@-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@-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 5e2ab06701703..31f5dbde05908 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -15534,7 +15534,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> @@ -17071,7 +17071,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> @@ -17198,6 +17198,12 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <td>open</td> <td>Clarify implicit conversion sequence from <I>cv</I> <TT>T</TT> to <TT>T</TT></td> <td align="center">Not resolved</td> + </tr> + <tr class="open" id="2899"> + <td><a href="https://cplusplus.github.io/CWG/issues/2899.html">2899</a></td> + <td>open</td> + <td>Bad value representations should cause undefined behavior</td> + <td align="center">Not resolved</td> </tr></table> </div> >From 40ad6801cd84cfc5a20abfaedc8e122f99891cac Mon Sep 17 00:00:00 2001 From: Vlad Serebrennikov <serebrennikov.vladis...@gmail.com> Date: Thu, 13 Jun 2024 14:50:13 +0300 Subject: [PATCH 2/2] Run clang-format --- clang/include/clang/Sema/Sema.h | 4 ++-- clang/lib/Parse/ParseDeclCXX.cpp | 25 ++++++++++++------------- clang/lib/Sema/SemaDeclCXX.cpp | 6 +++--- 3 files changed, 17 insertions(+), 18 deletions(-) diff --git a/clang/include/clang/Sema/Sema.h b/clang/include/clang/Sema/Sema.h index ccabd4925b8a3..dc059f781dcb2 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, - SourceRange TyLoc, const IdentifierInfo &II, ParsedType Ty, + 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 189fcc5440292..51e065a6c6a86 100644 --- a/clang/lib/Parse/ParseDeclCXX.cpp +++ b/clang/lib/Parse/ParseDeclCXX.cpp @@ -744,15 +744,15 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration( 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); + 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)) { + } else if (Tok.is(tok::annot_template_id)) { TemplateIdAnnotation *TemplateId = takeTemplateIdAnnotation(Tok); if (TemplateId->mightBeType()) { @@ -764,22 +764,21 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration( SourceRange Loc = Tok.getAnnotationRange(); ConsumeAnnotationToken(); - UED = Actions.ActOnUsingEnumDeclaration( - getCurScope(), AS, UsingLoc, UELoc, Loc, *TemplateId->Name, Type.get(), &SS); - } - else { + 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 { + } else { Diag(Tok.getLocation(), diag::err_using_enum_expect_identifier) << Tok.is(tok::kw_enum); SkipUntil(tok::semi); return nullptr; } - + if (!UED) { SkipUntil(tok::semi); return nullptr; diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index fb9e38d6b5bc9..d65c7df585bac 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -12394,9 +12394,9 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS, Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS, SourceLocation UsingLoc, - SourceLocation EnumLoc, - SourceRange TyLoc, const IdentifierInfo &II, - ParsedType Ty, CXXScopeSpec *SS) { + SourceLocation EnumLoc, SourceRange TyLoc, + const IdentifierInfo &II, ParsedType Ty, + CXXScopeSpec *SS) { assert(!SS->isInvalid() && "ScopeSpec is invalid"); TypeSourceInfo *TSI = nullptr; SourceLocation IdentLoc = TyLoc.getBegin(); _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits