forked from OSchip/llvm-project
[clang][DR2621] using enum NAME lookup fix
Although using-enum's grammar is 'using elaborated-enum-specifier', the lookup for the enum is ordinary lookup (and not the tagged-type lookup that normally occurs wth an tagged-type specifier). Thus (a) we can find typedefs and (b) do not find enum tags hidden by a non-tag name (the struct stat thing). This reimplements that part of using-enum handling, to address DR2621, where clang's behaviour does not match std intent (and other compilers). Reviewed By: aaron.ballman Differential Revision: https://reviews.llvm.org/D134283
This commit is contained in:
parent
868a8fd88f
commit
3d2080683f
|
@ -356,6 +356,8 @@ C++20 Feature Support
|
||||||
the time of checking, which should now allow the libstdc++ ranges implementation
|
the time of checking, which should now allow the libstdc++ ranges implementation
|
||||||
to work for at least trivial examples. This fixes
|
to work for at least trivial examples. This fixes
|
||||||
`Issue 44178 <https://github.com/llvm/llvm-project/issues/44178>`_.
|
`Issue 44178 <https://github.com/llvm/llvm-project/issues/44178>`_.
|
||||||
|
- Clang implements DR2621, correcting a defect in ``using enum`` handling. The
|
||||||
|
name is found via ordinary lookup so typedefs are found.
|
||||||
|
|
||||||
C++2b Feature Support
|
C++2b Feature Support
|
||||||
^^^^^^^^^^^^^^^^^^^^^
|
^^^^^^^^^^^^^^^^^^^^^
|
||||||
|
|
|
@ -607,6 +607,9 @@ def warn_cxx17_compat_using_enum_declaration : Warning<
|
||||||
def ext_using_enum_declaration : ExtWarn<
|
def ext_using_enum_declaration : ExtWarn<
|
||||||
"using enum declaration is a C++20 extension">,
|
"using enum declaration is a C++20 extension">,
|
||||||
InGroup<CXX20>;
|
InGroup<CXX20>;
|
||||||
|
def err_using_enum_expect_identifier : Error<
|
||||||
|
"using enum %select{requires an enum or typedef name|"
|
||||||
|
"does not permit an elaborated enum specifier}0">;
|
||||||
def err_constructor_bad_name : Error<
|
def err_constructor_bad_name : Error<
|
||||||
"missing return type for function %0; did you mean the constructor name %1?">;
|
"missing return type for function %0; did you mean the constructor name %1?">;
|
||||||
def err_destructor_tilde_identifier : Error<
|
def err_destructor_tilde_identifier : Error<
|
||||||
|
|
|
@ -562,6 +562,8 @@ def warn_cxx17_compat_using_decl_class_member_enumerator : Warning<
|
||||||
"with C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
|
"with C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
|
||||||
def err_using_enum_is_dependent : Error<
|
def err_using_enum_is_dependent : Error<
|
||||||
"using-enum cannot name a dependent type">;
|
"using-enum cannot name a dependent type">;
|
||||||
|
def err_using_enum_not_enum : Error<
|
||||||
|
"%0 is not an enumerated type">;
|
||||||
def err_ambiguous_inherited_constructor : Error<
|
def err_ambiguous_inherited_constructor : Error<
|
||||||
"constructor of %0 inherited from multiple base class subobjects">;
|
"constructor of %0 inherited from multiple base class subobjects">;
|
||||||
def note_ambiguous_inherited_constructor_using : Note<
|
def note_ambiguous_inherited_constructor_using : Note<
|
||||||
|
|
|
@ -6125,7 +6125,9 @@ public:
|
||||||
const ParsedAttributesView &AttrList);
|
const ParsedAttributesView &AttrList);
|
||||||
Decl *ActOnUsingEnumDeclaration(Scope *CurScope, AccessSpecifier AS,
|
Decl *ActOnUsingEnumDeclaration(Scope *CurScope, AccessSpecifier AS,
|
||||||
SourceLocation UsingLoc,
|
SourceLocation UsingLoc,
|
||||||
SourceLocation EnumLoc, const DeclSpec &);
|
SourceLocation EnumLoc,
|
||||||
|
SourceLocation IdentLoc, IdentifierInfo &II,
|
||||||
|
CXXScopeSpec *SS = nullptr);
|
||||||
Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS,
|
Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS,
|
||||||
MultiTemplateParamsArg TemplateParams,
|
MultiTemplateParamsArg TemplateParams,
|
||||||
SourceLocation UsingLoc, UnqualifiedId &Name,
|
SourceLocation UsingLoc, UnqualifiedId &Name,
|
||||||
|
|
|
@ -678,6 +678,8 @@ bool Parser::ParseUsingDeclarator(DeclaratorContext Context,
|
||||||
///
|
///
|
||||||
/// using-enum-declaration: [C++20, dcl.enum]
|
/// using-enum-declaration: [C++20, dcl.enum]
|
||||||
/// 'using' elaborated-enum-specifier ;
|
/// 'using' elaborated-enum-specifier ;
|
||||||
|
/// The terminal name of the elaborated-enum-specifier undergoes
|
||||||
|
/// ordinary lookup
|
||||||
///
|
///
|
||||||
/// elaborated-enum-specifier:
|
/// elaborated-enum-specifier:
|
||||||
/// 'enum' nested-name-specifier[opt] identifier
|
/// 'enum' nested-name-specifier[opt] identifier
|
||||||
|
@ -697,21 +699,47 @@ Parser::DeclGroupPtrTy Parser::ParseUsingDeclaration(
|
||||||
|
|
||||||
DiagnoseCXX11AttributeExtension(PrefixAttrs);
|
DiagnoseCXX11AttributeExtension(PrefixAttrs);
|
||||||
|
|
||||||
DeclSpec DS(AttrFactory);
|
|
||||||
ParseEnumSpecifier(UELoc, DS, TemplateInfo, AS,
|
|
||||||
// DSC_trailing has the semantics we desire
|
|
||||||
DeclSpecContext::DSC_trailing);
|
|
||||||
|
|
||||||
if (TemplateInfo.Kind) {
|
if (TemplateInfo.Kind) {
|
||||||
SourceRange R = TemplateInfo.getSourceRange();
|
SourceRange R = TemplateInfo.getSourceRange();
|
||||||
Diag(UsingLoc, diag::err_templated_using_directive_declaration)
|
Diag(UsingLoc, diag::err_templated_using_directive_declaration)
|
||||||
<< 1 /* declaration */ << R << FixItHint::CreateRemoval(R);
|
<< 1 /* declaration */ << R << FixItHint::CreateRemoval(R);
|
||||||
|
SkipUntil(tok::semi);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
CXXScopeSpec SS;
|
||||||
|
if (ParseOptionalCXXScopeSpecifier(SS, /*ParsedType=*/nullptr,
|
||||||
|
/*ObectHasErrors=*/false,
|
||||||
|
/*EnteringConttext=*/false,
|
||||||
|
/*MayBePseudoDestructor=*/nullptr,
|
||||||
|
/*IsTypename=*/false,
|
||||||
|
/*IdentifierInfo=*/nullptr,
|
||||||
|
/*OnlyNamespace=*/false,
|
||||||
|
/*InUsingDeclaration=*/true)) {
|
||||||
|
SkipUntil(tok::semi);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (Tok.is(tok::code_completion)) {
|
||||||
|
cutOffParsing();
|
||||||
|
Actions.CodeCompleteUsing(getCurScope());
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
if (!Tok.is(tok::identifier)) {
|
||||||
|
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;
|
return nullptr;
|
||||||
}
|
}
|
||||||
|
|
||||||
Decl *UED = Actions.ActOnUsingEnumDeclaration(getCurScope(), AS, UsingLoc,
|
|
||||||
UELoc, DS);
|
|
||||||
DeclEnd = Tok.getLocation();
|
DeclEnd = Tok.getLocation();
|
||||||
if (ExpectAndConsume(tok::semi, diag::err_expected_after,
|
if (ExpectAndConsume(tok::semi, diag::err_expected_after,
|
||||||
"using-enum declaration"))
|
"using-enum declaration"))
|
||||||
|
|
|
@ -11851,30 +11851,30 @@ Decl *Sema::ActOnUsingDeclaration(Scope *S, AccessSpecifier AS,
|
||||||
Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
|
Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
|
||||||
SourceLocation UsingLoc,
|
SourceLocation UsingLoc,
|
||||||
SourceLocation EnumLoc,
|
SourceLocation EnumLoc,
|
||||||
const DeclSpec &DS) {
|
SourceLocation IdentLoc,
|
||||||
switch (DS.getTypeSpecType()) {
|
IdentifierInfo &II, CXXScopeSpec *SS) {
|
||||||
case DeclSpec::TST_error:
|
assert(!SS->isInvalid() && "ScopeSpec is invalid");
|
||||||
// This will already have been diagnosed
|
ParsedType TypeRep = getTypeName(II, IdentLoc, S, SS);
|
||||||
|
if (!TypeRep) {
|
||||||
|
Diag(IdentLoc, SS && isDependentScopeSpecifier(*SS)
|
||||||
|
? diag::err_using_enum_is_dependent
|
||||||
|
: diag::err_unknown_typename)
|
||||||
|
<< II.getName()
|
||||||
|
<< SourceRange(SS ? SS->getBeginLoc() : IdentLoc, IdentLoc);
|
||||||
|
return nullptr;
|
||||||
|
}
|
||||||
|
|
||||||
|
auto *Enum = dyn_cast_if_present<EnumDecl>(TypeRep.get()->getAsTagDecl());
|
||||||
|
if (!Enum) {
|
||||||
|
Diag(IdentLoc, diag::err_using_enum_not_enum) << TypeRep.get();
|
||||||
return nullptr;
|
return nullptr;
|
||||||
|
|
||||||
case DeclSpec::TST_enum:
|
|
||||||
break;
|
|
||||||
|
|
||||||
case DeclSpec::TST_typename:
|
|
||||||
Diag(DS.getTypeSpecTypeLoc(), diag::err_using_enum_is_dependent);
|
|
||||||
return nullptr;
|
|
||||||
|
|
||||||
default:
|
|
||||||
llvm_unreachable("unexpected DeclSpec type");
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// As with enum-decls, we ignore attributes for now.
|
|
||||||
auto *Enum = cast<EnumDecl>(DS.getRepAsDecl());
|
|
||||||
if (auto *Def = Enum->getDefinition())
|
if (auto *Def = Enum->getDefinition())
|
||||||
Enum = Def;
|
Enum = Def;
|
||||||
|
|
||||||
auto *UD = BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc,
|
auto *UD =
|
||||||
DS.getTypeSpecTypeNameLoc(), Enum);
|
BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc, IdentLoc, Enum);
|
||||||
if (UD)
|
if (UD)
|
||||||
PushOnScopeChains(UD, S, /*AddToContext*/ false);
|
PushOnScopeChains(UD, S, /*AddToContext*/ false);
|
||||||
|
|
||||||
|
|
|
@ -1,5 +1,19 @@
|
||||||
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify
|
// RUN: %clang_cc1 -std=c++20 -triple x86_64-unknown-unknown %s -verify
|
||||||
|
|
||||||
|
namespace dr2621 { // dr2621: yes
|
||||||
|
enum class E { a };
|
||||||
|
namespace One {
|
||||||
|
using E_t = E;
|
||||||
|
using enum E_t; // typedef ok
|
||||||
|
auto v = a;
|
||||||
|
}
|
||||||
|
namespace Two {
|
||||||
|
using dr2621::E;
|
||||||
|
int E; // we see this
|
||||||
|
using enum E; // expected-error {{unknown type name E}}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
namespace dr2628 { // dr2628: yes
|
namespace dr2628 { // dr2628: yes
|
||||||
|
|
||||||
template <bool A = false, bool B = false>
|
template <bool A = false, bool B = false>
|
||||||
|
|
|
@ -2,6 +2,6 @@ enum class AAA { X, Y, Z };
|
||||||
|
|
||||||
namespace N2 {
|
namespace N2 {
|
||||||
using enum AAA;
|
using enum AAA;
|
||||||
// RUN: %clang_cc1 -fsyntax-only -code-completion-at=%s:4:14 %s | FileCheck -check-prefix=CHECK-CC1 %s
|
// RUN: %clang_cc1 -std=c++20 -fsyntax-only -code-completion-at=%s:4:14 %s | FileCheck -check-prefix=CHECK-CC1 %s
|
||||||
// CHECK-CC1: COMPLETION: AAA
|
// CHECK-CC1: COMPLETION: AAA
|
||||||
};
|
};
|
||||||
|
|
|
@ -4,9 +4,9 @@ namespace GH57347 {
|
||||||
namespace A {}
|
namespace A {}
|
||||||
|
|
||||||
void f() {
|
void f() {
|
||||||
using enum A::+; // expected-error {{expected identifier}}
|
using enum A::+; // expected-error {{using enum requires an enum or typedef name}}
|
||||||
using enum; // expected-error {{expected identifier or '{'}}
|
using enum; // expected-error {{using enum requires an enum or typedef name}}
|
||||||
using enum class; // expected-error {{expected identifier or '{'}}
|
using enum class; // expected-error {{using enum requires an enum or typedef name}}
|
||||||
using enum : blah; // expected-error {{unknown type name 'blah'}} expected-error {{unnamed enumeration must be a definition}}
|
using enum enum q; // expected-error {{using enum does not permit an elaborated enum specifier}}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
|
@ -8,7 +8,7 @@ namespace Bob {
|
||||||
enum A { a, // expected-note{{declared here}}
|
enum A { a, // expected-note{{declared here}}
|
||||||
b,
|
b,
|
||||||
c };
|
c };
|
||||||
class C; // expected-note{{previous use}}
|
class C;
|
||||||
enum class D : int;
|
enum class D : int;
|
||||||
enum class D { d,
|
enum class D { d,
|
||||||
e,
|
e,
|
||||||
|
@ -20,11 +20,11 @@ using enum Bob::A;
|
||||||
#if __cplusplus < 202002
|
#if __cplusplus < 202002
|
||||||
// expected-warning@-2{{is a C++20 extension}}
|
// expected-warning@-2{{is a C++20 extension}}
|
||||||
#endif
|
#endif
|
||||||
using enum Bob::B; // expected-error{{no enum named 'B'}}
|
using enum Bob::B; // expected-error{{unknown type name B}}
|
||||||
#if __cplusplus < 202002
|
#if __cplusplus < 202002
|
||||||
// expected-warning@-2{{is a C++20 extension}}
|
// expected-warning@-2{{is a C++20 extension}}
|
||||||
#endif
|
#endif
|
||||||
using enum Bob::C; // expected-error{{tag type that does not match}}
|
using enum Bob::C; // expected-error{{'Bob::C' is not an enumerated type}}
|
||||||
#if __cplusplus < 202002
|
#if __cplusplus < 202002
|
||||||
// expected-warning@-2{{is a C++20 extension}}
|
// expected-warning@-2{{is a C++20 extension}}
|
||||||
#endif
|
#endif
|
||||||
|
@ -38,6 +38,16 @@ using enum Bob::D;
|
||||||
#if __cplusplus < 202002
|
#if __cplusplus < 202002
|
||||||
// expected-warning@-2{{is a C++20 extension}}
|
// expected-warning@-2{{is a C++20 extension}}
|
||||||
#endif
|
#endif
|
||||||
|
|
||||||
|
void DR2621() {
|
||||||
|
using A_t = Bob::A;
|
||||||
|
using enum A_t;
|
||||||
|
#if __cplusplus < 202002
|
||||||
|
// expected-warning@-2{{is a C++20 extension}}
|
||||||
|
#endif
|
||||||
|
A_t x = a;
|
||||||
|
}
|
||||||
|
|
||||||
} // namespace One
|
} // namespace One
|
||||||
|
|
||||||
namespace Two {
|
namespace Two {
|
||||||
|
|
Loading…
Reference in New Issue