urnathan updated this revision to Diff 344396.
urnathan edited the summary of this revision.
urnathan edited reviewers, added: davrec; removed: Quuxplusone.
urnathan added a comment.

This update relies upon D101777 <https://reviews.llvm.org/D101777> & D102239 
<https://reviews.llvm.org/D102239> (let's see if I can figure out how to note 
that elsewhere)


CHANGES SINCE LAST ACTION
  https://reviews.llvm.org/D100276/new/

https://reviews.llvm.org/D100276

Files:
  clang/include/clang/Basic/DiagnosticSemaKinds.td
  clang/include/clang/Sema/Sema.h
  clang/lib/Sema/SemaDeclCXX.cpp
  clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
  clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp
  clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p7-cxx20.cpp
  clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p7.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,8 +301,8 @@
   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}}
-  E b = a; // expected-error {{undeclared}}
+  using E::a; // expected-warning {{using declaration naming a scoped enumerator is a C++20 extension}}
+  E b = a;
 }
 
 namespace test11 {
Index: clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p7.cpp
===================================================================
--- clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p7.cpp
+++ clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p7.cpp
@@ -1,4 +1,11 @@
 // RUN: %clang_cc1 -std=c++11 -verify %s
+// RUN: %clang_cc1 -std=c++17 -verify %s
+// RUN: %clang_cc1 -std=c++20 -verify %s
 
 enum class EC { ec };
-using EC::ec; // expected-error {{using declaration cannot refer to a scoped enumerator}}
+using EC::ec;
+#if __cplusplus < 202002
+// expected-warning@-2 {{using declaration naming a scoped enumerator is a C++20 extension}}
+#else
+// expected-no-diagnostics
+#endif
Index: clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p7-cxx20.cpp
===================================================================
--- /dev/null
+++ clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p7-cxx20.cpp
@@ -0,0 +1,271 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
+
+// p1099 'using SCOPEDENUM::MEMBER;'
+
+namespace Zero {
+namespace Bob {
+enum class Kevin {
+  Stuart,
+  AlsoStuart
+#if __cplusplus >= 202002L
+// expected-note@-3{{target of using declaration}}
+// expected-note@-3{{target of using declaration}}
+#endif
+};
+} // namespace Bob
+
+using Bob::Kevin::Stuart;
+#if __cplusplus < 202002L
+// expected-warning@-2{{using declaration naming a scoped enumerator is a C++20 extension}}
+#else
+using Bob::Kevin::Stuart;
+
+auto b = Stuart;
+
+namespace Foo {
+int Stuart;               // expected-note{{conflicting declaration}}
+using Bob::Kevin::Stuart; // expected-error{{target of using declaration conflicts}}
+
+using Bob::Kevin::AlsoStuart; // expected-note{{using declaration}}
+int AlsoStuart;               // expected-error{{declaration conflicts with target}}
+} // namespace Foo
+#endif
+
+} // namespace Zero
+
+namespace One {
+
+// derived from [namespace.udecl]/3
+enum class button { up,
+                    down };
+struct S {
+  using button::up;
+#if __cplusplus < 202002L
+  // expected-warning@-2{{a C++20 extension}}
+  // expected-error@-3{{using declaration in class}}
+#else
+  button b = up;
+#endif
+};
+
+#if __cplusplus >= 202002L
+// some more
+struct T : S {
+  button c = up;
+};
+#endif
+enum E2 { e2 };
+} // namespace One
+
+namespace Two {
+enum class E1 { e1 };
+
+struct S {
+  using One::e2;
+#if __cplusplus < 202002L
+  // expected-error@-2{{using declaration in class}}
+#else
+  One::E2 c = e2;
+#endif
+};
+
+} // namespace Two
+
+namespace Three {
+
+enum E3 { e3 };
+struct e3;
+
+struct S {
+  using Three::e3; // expected-error{{using declaration in class}}
+
+  enum class E4 { e4 };
+  enum E5 { e5 };
+};
+
+using S::e5;
+using S::E4::e4;
+#if __cplusplus < 202002L
+// expected-error@-3{{using declaration cannot refer to class member}}
+// expected-note@-4{{use a constexpr variable instead}}
+// expected-warning@-4{{a C++20 extension}}
+// expected-error@-5{{using declaration cannot refer to class member}}
+// expected-note@-6{{use a constexpr variable instead}}
+#else
+auto a = e4;
+auto b = e5;
+#endif
+} // namespace Three
+
+namespace Four {
+
+template <typename T>
+struct TPL {
+  enum class E1 { e1 };
+  struct IN {
+    enum class E2 { e2 };
+  };
+
+protected:
+  enum class E3 { e3 }; // expected-note{{declared protected here}}
+};
+
+using TPL<int>::E1::e1;
+#if __cplusplus < 202002L
+// expected-warning@-2{{a C++20 extension}}
+// expected-error@-3{{using declaration cannot refer to class member}}
+// expected-note@-4{{use a constexpr variable instead}}
+#else
+using TPL<float>::IN::E2::e2;
+
+auto a = e1;
+auto b = e2;
+#endif
+
+enum class E4 { e4 };
+template <typename T>
+struct DER : TPL<int> {
+  using TPL<T>::E1::e1;
+#if __cplusplus < 202002L
+  // expected-warning@-2{{a C++20 extension}}
+  // expected-warning@-3{{using declaration naming a scoped}}
+  // expected-error@-4{{which is not a base}}
+#endif
+  using TPL<T>::E3::e3; // expected-error{{is a protected member}}
+#if __cplusplus < 202002L
+  // expected-warning@-2 2{{using declaration naming a scoped}}
+  // expected-error@-3{{which is not a base}}
+#endif
+
+  using E4::e4;
+#if __cplusplus < 202002L
+  // expected-warning@-2{{a C++20 extension}}
+  // expected-error@-3{{which is not a class}}
+#else
+  auto Foo() { return e1; }
+  auto Bar() { return e2; }
+#endif
+};
+
+DER<float> x; // expected-note{{requested here}}
+DER<int> y;
+#if __cplusplus < 202002L
+// expected-note@-2{{requested here}}
+#else
+auto y1 = y.Foo();
+auto y2 = y.Bar();
+#endif
+} // namespace Four
+
+namespace Five {
+template <unsigned I, unsigned K>
+struct Quux {
+  enum class Q : unsigned; // expected-note{{member is declared here}}
+  enum class R : unsigned { i = I,
+                            k = K };
+};
+
+using Quux<1, 2>::Q::nothing; // expected-error{{implicit instantiation of undefined}}
+using Quux<1, 2>::R::i;
+#if __cplusplus < 202002L
+// expected-warning@-2{{a C++20 extension}}
+// expected-error@-3{{using declaration cannot refer to class member}}
+// expected-note@-4{{use a constexpr variable instead}}
+#endif
+
+} // namespace Five
+
+namespace Six {
+template <unsigned I, unsigned K>
+struct Quux {
+  enum class Q : unsigned; // expected-note{{member is declared here}}
+  enum class R : unsigned { i = I,
+                            k = K };
+};
+
+template <unsigned I> struct Fido {
+  using Quux<I, I>::Q::nothing; // expected-error{{implicit instantiation of undefined}}
+};
+
+Fido<2> a; // expected-note{{in instantiation}}
+
+} // namespace Six
+
+namespace Seven {
+template <unsigned I, unsigned K>
+struct Quux {
+  enum class R : unsigned { i = I,
+                            k = K };
+};
+
+template <unsigned I> struct Toto {
+  using Quux<I, I>::R::i;
+#if __cplusplus < 202002L
+  // expected-warning@-2{{a C++20 extension}}
+// expected-error@-3{{refers into}}
+#else
+  static_assert(unsigned(i) == I);
+#endif
+};
+
+Toto<2> b;
+#if __cplusplus < 202002L
+// expected-note@-2{{in instantiation}}
+#endif
+
+} // namespace Seven
+
+namespace Eight {
+struct Kevin {
+  enum class B { a };
+  enum a {};
+};
+
+using Kevin::B::a;
+#if __cplusplus < 202002L
+// expected-warning@-2{{a C++20 extension}}
+// expected-error@-3{{using declaration cannot refer to class member}}
+// expected-note@-4{{use a constexpr variable instead}}
+#endif
+using Kevin::B::a;
+#if __cplusplus < 202002L
+// expected-warning@-2{{a C++20 extension}}
+// expected-error@-3{{using declaration cannot refer to class member}}
+// expected-note@-4{{use a constexpr variable instead}}
+#endif
+
+class X : Kevin {
+  using Kevin::B::a; // expected-note{{previous using declaration}}
+#if __cplusplus < 202002L
+// expected-warning@-2{{a C++20 extension}}
+#endif
+  using Kevin::a;
+  using Kevin::B::a; // expected-error{{redeclaration of using declaration}}
+};
+
+} // namespace Eight
+
+namespace Nine {
+namespace Q {
+enum class Bob { a };
+using Bob::a;
+#if __cplusplus < 202002L
+// expected-warning@-2{{a C++20 extension}}
+#endif
+} // namespace Q
+
+using Q::a;
+using Q::Bob::a;
+#if __cplusplus < 202002L
+// expected-warning@-2{{a C++20 extension}}
+#endif
+
+#if __cplusplus >= 202002L
+struct Foo {
+  using Q::a; // expected-note{{previous using declaration}}
+  using Q::Bob::a;
+  using Q::a; // expected-error{{redeclaration of using declaration}}
+};
+#endif
+} // namespace Nine
Index: clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp
===================================================================
--- clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp
+++ clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp
@@ -17,6 +17,7 @@
 };
 
 class C {
+public:
   int g();
 };
 
@@ -42,7 +43,7 @@
 #endif
 
   using B::EC;
-  using B::EC::ec; // expected-error {{not a class}} expected-warning 0-1 {{C++11}}
+  using B::EC::ec; // expected-warning {{a C++20 extension}} expected-warning 0-1 {{C++11}}
 };
 
 namespace test1 {
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3034,10 +3034,9 @@
   }
 
   if (!NewUD->isInvalidDecl() &&
-      SemaRef.CheckUsingDeclQualifier(D->getUsingLoc(), D->hasTypename(),
-                                      SS, NameInfo, D->getLocation()))
+      SemaRef.CheckUsingDeclQualifier(D->getUsingLoc(), D->hasTypename(), SS,
+                                      NameInfo, D->getLocation(), nullptr, D))
     NewUD->setInvalidDecl();
-
   SemaRef.Context.setInstantiatedFromUsingDecl(NewUD, D);
   NewUD->setAccess(D->getAccess());
   Owner->addDecl(NewUD);
@@ -3046,6 +3045,9 @@
   if (NewUD->isInvalidDecl())
     return NewUD;
 
+  // If the using scope was dependent, or we had dependent bases, we need to
+  // recheck the inheritance
+
   if (NameInfo.getName().getNameKind() == DeclarationName::CXXConstructorName)
     SemaRef.CheckInheritingConstructorUsingDecl(NewUD);
 
Index: clang/lib/Sema/SemaDeclCXX.cpp
===================================================================
--- clang/lib/Sema/SemaDeclCXX.cpp
+++ clang/lib/Sema/SemaDeclCXX.cpp
@@ -11636,7 +11636,7 @@
   // This is invalid (during instantiation) in C++03 because B::foo
   // resolves to the using decl in B, which is not a base class of D<T>.
   // We can't diagnose it immediately because C<T> is an unknown
-  // specialization.  The UsingShadowDecl in D<T> then points directly
+  // specialization. The UsingShadowDecl in D<T> then points directly
   // to A::foo, which will look well-formed when we instantiate.
   // The right solution is to not collapse the shadow-decl chain.
   if (!getLangOpts().CPlusPlus11 && CurContext->isRecord())
@@ -12050,15 +12050,16 @@
                                   SS, IdentLoc, Previous))
     return nullptr;
 
-  // Check for bad qualifiers.
-  if (CheckUsingDeclQualifier(UsingLoc, HasTypenameKeyword, SS, NameInfo,
-                              IdentLoc))
-    return nullptr;
-
   DeclContext *LookupContext = computeDeclContext(SS);
+
   NamedDecl *D;
   NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
   if (!LookupContext || EllipsisLoc.isValid()) {
+    // Dependent scope, or an unexpanded pack
+    if (!LookupContext && CheckUsingDeclQualifier(UsingLoc, HasTypenameKeyword,
+                                                  SS, NameInfo, IdentLoc))
+      return nullptr;
+
     if (HasTypenameKeyword) {
       // FIXME: not all declaration name kinds are legal here
       D = UnresolvedUsingTypenameDecl::Create(Context, CurContext,
@@ -12109,6 +12110,11 @@
 
   LookupQualifiedName(R, LookupContext);
 
+  // Validate the context, now we have a lookup
+  if (CheckUsingDeclQualifier(UsingLoc, HasTypenameKeyword, SS, NameInfo,
+                              IdentLoc, &R))
+    return nullptr;
+
   // Try to correct typos if possible. If constructor name lookup finds no
   // results, that means the named class has no explicit constructors, and we
   // suppressed declaring implicit ones (probably because it's dependent or
@@ -12208,16 +12214,6 @@
     return BuildInvalid();
   }
 
-  // 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()) {
-      Diag(IdentLoc, diag::err_using_decl_can_not_refer_to_scoped_enum)
-        << SS.getRange();
-      return BuildInvalid();
-    }
-  }
-
   UsingDecl *UD = BuildValid();
 
   // Some additional rules apply to inheriting constructors.
@@ -12357,48 +12353,83 @@
   return false;
 }
 
-
 /// Checks that the given nested-name qualifier used in a using decl
 /// in the current context is appropriately related to the current
 /// scope.  If an error is found, diagnoses it and returns true.
-bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc,
-                                   bool HasTypename,
+/// R is nullptr, if the caller has not (yet) done a lookup, otherwise it's the
+/// result of that lookup. UD is likewise nullptr, except when we have an
+/// already-populated UsingDecl whose shadow decls contain the same information
+/// (i.e. we're instantiating a UsingDecl with non-dependent scope).
+bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename,
                                    const CXXScopeSpec &SS,
                                    const DeclarationNameInfo &NameInfo,
-                                   SourceLocation NameLoc) {
+                                   SourceLocation NameLoc,
+                                   const LookupResult *R, const UsingDecl *UD) {
   DeclContext *NamedContext = computeDeclContext(SS);
+  assert(bool(NamedContext) == (R || UD) && !(R && UD) &&
+         "resolvable context must have exactly one set of decls");
+
+  // C++ 20 permits using an enumerator that does not have a class-hierarchy
+  // relationship.
+  bool Cxx20Enumerator = false;
+  if (NamedContext) {
+    EnumConstantDecl *EC = nullptr;
+    if (R)
+      EC = R->getAsSingle<EnumConstantDecl>();
+    else if (UD && UD->shadow_size() == 1)
+      EC = dyn_cast<EnumConstantDecl>(UD->shadow_begin()->getTargetDecl());
+    if (EC)
+      Cxx20Enumerator = getLangOpts().CPlusPlus20;
+
+    if (auto *ED = dyn_cast<EnumDecl>(NamedContext)) {
+      // C++14 [namespace.udecl]p7:
+      // A using-declaration shall not name a scoped enumerator.
+      // C++20 p1099 permits enumerators.
+      if (EC && R && ED->isScoped())
+        Diag(SS.getBeginLoc(),
+             getLangOpts().CPlusPlus20
+                 ? diag::warn_cxx17_compat_using_decl_scoped_enumerator
+                 : diag::ext_using_decl_scoped_enumerator)
+            << SS.getRange();
+
+      // We want to consider the scope of the enumerator
+      NamedContext = ED->getDeclContext();
+    }
+  }
 
   if (!CurContext->isRecord()) {
     // 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
+    //   ... other than an enumerator ...
 
     // 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.
-    if ((HasTypename && !NamedContext) ||
-        (NamedContext && NamedContext->getRedeclContext()->isRecord())) {
-      auto *RD = NamedContext
-                     ? cast<CXXRecordDecl>(NamedContext->getRedeclContext())
-                     : nullptr;
-      if (RD && RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), RD))
-        RD = nullptr;
-
-      Diag(NameLoc, diag::err_using_decl_can_not_refer_to_class_member)
+    // dependent class or enumeration scope. If we have a 'typename' keyword,
+    // the scope must resolve to a class type.
+    if (NamedContext ? !NamedContext->getRedeclContext()->isRecord()
+                     : !HasTypename)
+      return false; // OK
+
+    Diag(NameLoc,
+         Cxx20Enumerator
+             ? diag::warn_cxx17_compat_using_decl_class_member_enumerator
+             : diag::err_using_decl_can_not_refer_to_class_member)
         << SS.getRange();
 
-      // If we have a complete, non-dependent source type, try to suggest a
-      // way to get the same effect.
-      if (!RD)
-        return true;
+    if (Cxx20Enumerator)
+      return false; // OK
 
-      // Find what this using-declaration was referring to.
-      LookupResult R(*this, NameInfo, LookupOrdinaryName);
-      R.setHideTags(false);
-      R.suppressDiagnostics();
-      LookupQualifiedName(R, RD);
+    auto *RD = NamedContext
+                   ? cast<CXXRecordDecl>(NamedContext->getRedeclContext())
+                   : nullptr;
+    if (RD && !RequireCompleteDeclContext(const_cast<CXXScopeSpec &>(SS), RD)) {
+      // See if there's a helpful fixit
 
-      if (R.getAsSingle<TypeDecl>()) {
+      if (!R) {
+        // We will have already diagnosed the problem on the template
+        // definition,  Maybe we should do so again?
+      } else if (R->getAsSingle<TypeDecl>()) {
         if (getLangOpts().CPlusPlus11) {
           // Convert 'using X::Y;' to 'using Y = X::Y;'.
           Diag(SS.getBeginLoc(), diag::note_using_decl_class_member_workaround)
@@ -12415,7 +12446,7 @@
             << FixItHint::CreateInsertion(
                    InsertLoc, " " + NameInfo.getName().getAsString());
         }
-      } else if (R.getAsSingle<VarDecl>()) {
+      } else if (R->getAsSingle<VarDecl>()) {
         // Don't provide a fixit outside C++11 mode; we don't want to suggest
         // repeating the type of the static data member here.
         FixItHint FixIt;
@@ -12428,7 +12459,7 @@
         Diag(UsingLoc, diag::note_using_decl_class_member_workaround)
           << 2 // reference declaration
           << FixIt;
-      } else if (R.getAsSingle<EnumConstantDecl>()) {
+      } else if (R->getAsSingle<EnumConstantDecl>()) {
         // Don't provide a fixit outside C++11 mode; we don't want to suggest
         // repeating the type of the enumeration here, and we can't do so if
         // the type is anonymous.
@@ -12444,15 +12475,11 @@
           << (getLangOpts().CPlusPlus11 ? 4 : 3) // const[expr] variable
           << FixIt;
       }
-      return true;
     }
 
-    // Otherwise, this might be valid.
-    return false;
+    return true; // Fail
   }
 
-  // The current scope is a record.
-
   // If the named context is dependent, we can't decide much.
   if (!NamedContext) {
     // FIXME: in C++0x, we can diagnose if we can prove that the
@@ -12464,12 +12491,19 @@
     return false;
   }
 
+  // The current scope is a record.
   if (!NamedContext->isRecord()) {
     // 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(),
-         diag::err_using_decl_nested_name_specifier_is_not_class)
-      << SS.getScopeRep() << SS.getRange();
+    Diag(SS.getBeginLoc(),
+         Cxx20Enumerator
+             ? diag::warn_cxx17_compat_using_decl_non_member_enumerator
+             : diag::err_using_decl_nested_name_specifier_is_not_class)
+        << SS.getScopeRep() << SS.getRange();
+
+    if (Cxx20Enumerator)
+      return false; // OK
+
     return true;
   }
 
@@ -12485,19 +12519,25 @@
 
     if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(
                                  cast<CXXRecordDecl>(NamedContext))) {
+
+      if (Cxx20Enumerator) {
+        Diag(NameLoc, diag::warn_cxx17_compat_using_decl_non_member_enumerator)
+            << SS.getRange();
+        return false;
+      }
+
       if (CurContext == NamedContext) {
-        Diag(NameLoc,
+        Diag(SS.getBeginLoc(),
              diag::err_using_decl_nested_name_specifier_is_current_class)
-          << SS.getRange();
-        return true;
+            << SS.getRange();
+        return !getLangOpts().CPlusPlus20;
       }
 
       if (!cast<CXXRecordDecl>(NamedContext)->isInvalidDecl()) {
-        Diag(SS.getRange().getBegin(),
+        Diag(SS.getBeginLoc(),
              diag::err_using_decl_nested_name_specifier_is_not_base_class)
-          << SS.getScopeRep()
-          << cast<CXXRecordDecl>(CurContext)
-          << SS.getRange();
+            << SS.getScopeRep() << cast<CXXRecordDecl>(CurContext)
+            << SS.getRange();
       }
       return true;
     }
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -5684,11 +5684,12 @@
                                    const CXXScopeSpec &SS,
                                    SourceLocation NameLoc,
                                    const LookupResult &Previous);
-  bool CheckUsingDeclQualifier(SourceLocation UsingLoc,
-                               bool HasTypename,
+  bool CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename,
                                const CXXScopeSpec &SS,
                                const DeclarationNameInfo &NameInfo,
-                               SourceLocation NameLoc);
+                               SourceLocation NameLoc,
+                               const LookupResult *R = nullptr,
+                               const UsingDecl *UD = nullptr);
 
   NamedDecl *BuildUsingDeclaration(
       Scope *S, AccessSpecifier AS, SourceLocation UsingLoc,
Index: clang/include/clang/Basic/DiagnosticSemaKinds.td
===================================================================
--- clang/include/clang/Basic/DiagnosticSemaKinds.td
+++ clang/include/clang/Basic/DiagnosticSemaKinds.td
@@ -531,6 +531,10 @@
   "dependent using declaration resolved to type without 'typename'">;
 def err_using_decl_nested_name_specifier_is_not_class : Error<
   "using declaration in class refers into '%0', which is not a class">;
+def warn_cxx17_compat_using_decl_non_member_enumerator : Warning<
+  "member using declaration naming non-class '%0' enumerator is "
+  "incompatible with C++ standards before C++20">, InGroup<CXXPre20Compat>,
+  DefaultIgnore;
 def err_using_decl_nested_name_specifier_is_current_class : Error<
   "using declaration refers to its own class">;
 def err_using_decl_nested_name_specifier_is_not_base_class : Error<
@@ -539,6 +543,16 @@
   "%0 is not a direct base of %1, cannot inherit constructors">;
 def err_using_decl_can_not_refer_to_class_member : Error<
   "using declaration cannot refer to class member">;
+def warn_cxx17_compat_using_decl_class_member_enumerator : Warning<
+  "member using declaration naming a non-member enumerator is incompatible "
+  "with C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
+def ext_using_decl_class_member_enumerator : ExtWarn<
+  "member using declaration naming a non-member enumerator is "
+  "a C++20 extension">, InGroup<CXX20>;
+def err_using_enum_lacks_definition : Error<
+  "enum named by using-enum declaration lacks a definition">;
+def err_using_enum_is_dependent : Error<
+  "using-enum cannot name a dependent type">;
 def err_ambiguous_inherited_constructor : Error<
   "constructor of %0 inherited from multiple base class subobjects">;
 def note_ambiguous_inherited_constructor_using : Note<
@@ -548,8 +562,12 @@
   "a const variable|a constexpr variable}0 instead">;
 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">;
+def warn_cxx17_compat_using_decl_scoped_enumerator: Warning<
+  "using declaration naming a scoped enumerator is incompatible with "
+  "C++ standards before C++20">, InGroup<CXXPre20Compat>, DefaultIgnore;
+def ext_using_decl_scoped_enumerator : ExtWarn<
+  "using declaration naming a scoped enumerator is a C++20 extension">,
+  InGroup<CXX20>;
 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