the time of checking, which should now allow the libstdc++ ranges implementation
to work for at least trivial examples. This fixes
`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
^^^^^^^^^^^^^^^^^^^^^
def ext_using_enum_declaration : ExtWarn<
"using enum declaration is a C++20 extension">,
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<
"missing return type for function %0; did you mean the constructor name %1?">;
def err_destructor_tilde_identifier : Error<
"with C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
def err_using_enum_is_dependent : Error<
"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<
"constructor of %0 inherited from multiple base class subobjects">;
def note_ambiguous_inherited_constructor_using : Note<
const ParsedAttributesView &AttrList);
Decl *ActOnUsingEnumDeclaration(Scope *CurScope, AccessSpecifier AS,
SourceLocation UsingLoc,
- SourceLocation EnumLoc, const DeclSpec &);
+ SourceLocation EnumLoc,
+ SourceLocation IdentLoc, IdentifierInfo &II,
+ CXXScopeSpec *SS = nullptr);
Decl *ActOnAliasDeclaration(Scope *CurScope, AccessSpecifier AS,
MultiTemplateParamsArg TemplateParams,
SourceLocation UsingLoc, UnqualifiedId &Name,
///
/// using-enum-declaration: [C++20, dcl.enum]
/// 'using' elaborated-enum-specifier ;
+/// The terminal name of the elaborated-enum-specifier undergoes
+/// ordinary lookup
///
/// elaborated-enum-specifier:
/// 'enum' nested-name-specifier[opt] identifier
DiagnoseCXX11AttributeExtension(PrefixAttrs);
- DeclSpec DS(AttrFactory);
- ParseEnumSpecifier(UELoc, DS, TemplateInfo, AS,
- // DSC_trailing has the semantics we desire
- DeclSpecContext::DSC_trailing);
-
if (TemplateInfo.Kind) {
SourceRange R = TemplateInfo.getSourceRange();
Diag(UsingLoc, diag::err_templated_using_directive_declaration)
<< 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;
}
- Decl *UED = Actions.ActOnUsingEnumDeclaration(getCurScope(), AS, UsingLoc,
- UELoc, DS);
DeclEnd = Tok.getLocation();
if (ExpectAndConsume(tok::semi, diag::err_expected_after,
"using-enum declaration"))
Decl *Sema::ActOnUsingEnumDeclaration(Scope *S, AccessSpecifier AS,
SourceLocation UsingLoc,
SourceLocation EnumLoc,
- const DeclSpec &DS) {
- switch (DS.getTypeSpecType()) {
- case DeclSpec::TST_error:
- // This will already have been diagnosed
+ SourceLocation IdentLoc,
+ IdentifierInfo &II, CXXScopeSpec *SS) {
+ assert(!SS->isInvalid() && "ScopeSpec is invalid");
+ 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;
+ }
- case DeclSpec::TST_enum:
- break;
-
- case DeclSpec::TST_typename:
- Diag(DS.getTypeSpecTypeLoc(), diag::err_using_enum_is_dependent);
+ auto *Enum = dyn_cast_if_present<EnumDecl>(TypeRep.get()->getAsTagDecl());
+ if (!Enum) {
+ Diag(IdentLoc, diag::err_using_enum_not_enum) << TypeRep.get();
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())
Enum = Def;
- auto *UD = BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc,
- DS.getTypeSpecTypeNameLoc(), Enum);
+ auto *UD =
+ BuildUsingEnumDeclaration(S, AS, UsingLoc, EnumLoc, IdentLoc, Enum);
if (UD)
PushOnScopeChains(UD, S, /*AddToContext*/ false);
// 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
template <bool A = false, bool B = false>
namespace N2 {
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
};
namespace A {}
void f() {
- using enum A::+; // expected-error {{expected identifier}}
- using enum; // expected-error {{expected identifier or '{'}}
- using enum class; // expected-error {{expected identifier or '{'}}
- using enum : blah; // expected-error {{unknown type name 'blah'}} expected-error {{unnamed enumeration must be a definition}}
+ using enum A::+; // expected-error {{using enum requires an enum or typedef name}}
+ using enum; // expected-error {{using enum requires an enum or typedef name}}
+ using enum class; // expected-error {{using enum requires an enum or typedef name}}
+ using enum enum q; // expected-error {{using enum does not permit an elaborated enum specifier}}
}
}
enum A { a, // expected-note{{declared here}}
b,
c };
-class C; // expected-note{{previous use}}
+class C;
enum class D : int;
enum class D { d,
e,
#if __cplusplus < 202002
// expected-warning@-2{{is a C++20 extension}}
#endif
-using enum Bob::B; // expected-error{{no enum named 'B'}}
+using enum Bob::B; // expected-error{{unknown type name B}}
#if __cplusplus < 202002
// expected-warning@-2{{is a C++20 extension}}
#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
// expected-warning@-2{{is a C++20 extension}}
#endif
#if __cplusplus < 202002
// expected-warning@-2{{is a C++20 extension}}
#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 Two {