AntonBikineev created this revision.
AntonBikineev added a reviewer: rsmith.
AntonBikineev added a project: clang.
AntonBikineev requested review of this revision.

This change merely allows nested-name-specifiers for enums in using
declarations but doesn't add support for the "using-enum-declaration"
syntax proposed in P1099 <https://reviews.llvm.org/P1099>.


Repository:
  rC Clang

https://reviews.llvm.org/D99396

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/test/SemaCXX/cxx20-using-enum.cpp
  clang/test/SemaCXX/enum-scoped.cpp

Index: clang/test/SemaCXX/enum-scoped.cpp
===================================================================
--- clang/test/SemaCXX/enum-scoped.cpp
+++ 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}}
 }
 
Index: clang/test/SemaCXX/cxx20-using-enum.cpp
===================================================================
--- /dev/null
+++ 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}}
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ 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<EnumConstantDecl>()) {
-    if (cast<EnumDecl>(ED->getDeclContext())->isScoped()) {
+    if (!LangOpts.CPlusPlus20 &&
+        cast<EnumDecl>(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<EnumDecl>(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<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(
                                  cast<CXXRecordDecl>(NamedContext))) {
       if (CurContext == NamedContext) {
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ 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<
_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to