diff --git a/clang/include/clang/Basic/DiagnosticSemaKinds.td b/clang/include/clang/Basic/DiagnosticSemaKinds.td --- a/clang/include/clang/Basic/DiagnosticSemaKinds.td +++ b/clang/include/clang/Basic/DiagnosticSemaKinds.td @@ -539,7 +539,7 @@ def err_using_decl_can_not_refer_to_namespace : Error< "using declaration cannot refer to a namespace">; def err_using_decl_can_not_refer_to_scoped_enum : Error< - "using declaration cannot refer to a scoped enumerator">; + "using declaration cannot refer to a scoped enumerator before C++20">; def err_using_decl_constructor : Error< "using declaration cannot refer to a constructor">; def warn_cxx98_compat_using_decl_constructor : Warning< diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -12231,7 +12231,8 @@ // C++14 [namespace.udecl]p7: // A using-declaration shall not name a scoped enumerator. if (auto *ED = R.getAsSingle()) { - if (cast(ED->getDeclContext())->isScoped()) { + if (!LangOpts.CPlusPlus20 && + cast(ED->getDeclContext())->isScoped()) { Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_scoped_enum) << SS.getRange(); return BuildInvalid(); @@ -12392,10 +12393,13 @@ // C++03 [namespace.udecl]p3: // C++0x [namespace.udecl]p8: // A using-declaration for a class member shall be a member-declaration. + // C++20 [namespace.udecl]p7: + // A using-declaration that names a class member other than an enumerator + // shall be a member-declaration. // If we weren't able to compute a valid scope, it might validly be a - // dependent class scope or a dependent enumeration unscoped scope. If - // we have a 'typename' keyword, the scope must resolve to a class type. + // dependent class scope or a dependent scoped/unscoped enumeration scope. + // If we have a 'typename' keyword, the scope must resolve to a class type. if ((HasTypename && !NamedContext) || (NamedContext && NamedContext->getRedeclContext()->isRecord())) { auto *RD = NamedContext @@ -12484,7 +12488,11 @@ return false; } - if (!NamedContext->isRecord()) { + bool IsCXX20ScopedEnum = LangOpts.CPlusPlus20 && + NamedContext->getDeclKind() == Decl::Enum && + cast(NamedContext)->isScoped(); + + if (!NamedContext->isRecord() && !IsCXX20ScopedEnum) { // Ideally this would point at the last name in the specifier, // but we don't have that level of source info. Diag(SS.getRange().getBegin(), @@ -12503,6 +12511,13 @@ // nested-name-specifier shall name a base class of the class // being defined. + // C++20 [namespace.udecl]p3: + // In a using-declaration used as a member-declaration, each + // using-declarator shall either name an enumerator or have a + // nested-name-specifier naming a base class of the class being defined. + if (IsCXX20ScopedEnum) + return false; + if (cast(CurContext)->isProvablyNotDerivedFrom( cast(NamedContext))) { if (CurContext == NamedContext) { diff --git a/clang/test/SemaCXX/cxx20-using-enum.cpp b/clang/test/SemaCXX/cxx20-using-enum.cpp new file mode 100644 --- /dev/null +++ b/clang/test/SemaCXX/cxx20-using-enum.cpp @@ -0,0 +1,38 @@ +// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s + +enum class E { + e1, + e2 +}; + +void foo() { + using E::e1; + auto a = e1; +} + +namespace N { +using E::e2; +constexpr auto a = e2; +} // namespace N + +struct C { + using E::e1; + E e = e1; +}; + +namespace N1 { +enum class E { + e1, +}; +using E::e1; +auto a = e1; +} // namespace N1 + +enum class E1 { + e1 // expected-note{{conflicting declaration}} +}; +enum class E2 { + e1 // expected-note{{target of using declaration}} +}; +using E1::e1; +using E2::e1; // expected-error{{target of using declaration conflicts with declaration already in scope}} diff --git a/clang/test/SemaCXX/enum-scoped.cpp b/clang/test/SemaCXX/enum-scoped.cpp --- a/clang/test/SemaCXX/enum-scoped.cpp +++ b/clang/test/SemaCXX/enum-scoped.cpp @@ -301,7 +301,7 @@ int E::*p; // expected-error {{does not point into a class}} using E::f; // expected-error {{no member named 'f'}} - using E::a; // expected-error {{using declaration cannot refer to a scoped enumerator}} + using E::a; // expected-error {{using declaration cannot refer to a scoped enumerator before C++20}} E b = a; // expected-error {{undeclared}} }