urnathan updated this revision to Diff 337416.
urnathan added a comment.

Remove orthogonal lbstdc++ FIXME comment


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

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,149 @@
+// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 -verify %s
+
+// p1099 'using SCOPEDENUM::MEMBER;'
+
+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
+};
+}
+
+using Bob::Kevin::Stuart;
+#if __cplusplus < 202002L
+// expected-error@-2{{using declaration cannot refer to a scoped enumerator}}
+#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}}
+}
+#endif
+
+
+namespace One {
+
+// derived from [namespace.udecl]/3
+enum class button { up, down };
+struct S {
+  using button::up;
+#if __cplusplus < 202002L
+  // expected-error@-2{{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 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 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-error@-4{{using declaration cannot refer to a scoped enumerator}}
+#else
+auto a = e4;
+auto b = e5;
+#endif
+}
+
+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-error@-2{{cannot refer to a scoped enumerator}}
+#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-error@-2{{'TPL<float>::E1::', which is not a class}}
+  // expected-error@-3{{'TPL<int>::E1::', which is not a class}}
+#endif
+  using TPL<T>::E3::e3; // expected-error{{is a protected member}}
+#if __cplusplus < 202002L
+  // expected-error@-2{{'TPL<float>::E3::', which is not a class}}
+  // expected-error@-3{{'TPL<int>::E3::', which is not a class}}
+#endif
+  
+  using E4::e4;
+#if __cplusplus < 202002L
+  // expected-error@-2{{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
+}
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();
 };
 
Index: clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
===================================================================
--- clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
+++ clang/lib/Sema/SemaTemplateInstantiateDecl.cpp
@@ -3063,10 +3063,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);
@@ -3075,6 +3074,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
@@ -12006,12 +12006,15 @@
                                   SS, IdentLoc, Previous))
     return nullptr;
 
-  // Check for bad qualifiers.
-  if (CheckUsingDeclQualifier(UsingLoc, HasTypenameKeyword, SS, NameInfo,
-                              IdentLoc))
+  DeclContext *LookupContext = computeDeclContext(SS);
+
+  // Check for bad qualifiers.  This will not necessarily detect all badness, as
+  // C++20 permits enumerators to cross the class-heirarchy boundary
+  if (!LookupContext
+      && CheckUsingDeclQualifier(UsingLoc, HasTypenameKeyword, SS,
+                                 NameInfo, IdentLoc))
     return nullptr;
 
-  DeclContext *LookupContext = computeDeclContext(SS);
   NamedDecl *D;
   NestedNameSpecifierLoc QualifierLoc = SS.getWithLocInContext(Context);
   if (!LookupContext || EllipsisLoc.isValid()) {
@@ -12065,6 +12068,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
@@ -12165,15 +12173,19 @@
     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();
+  if (!getLangOpts().CPlusPlus20) {
+    // C++14 [namespace.udecl]p7:
+    // A using-declaration shall not name a scoped enumerator.
+    // C++20 p1099 permits enumerators.
+    if (auto *ED = R.getAsSingle<EnumConstantDecl>()) {
+      if (cast<EnumDecl>(ED->getDeclContext())->isScoped()) {
+        Diag(IdentLoc, diag::err_cxx14_using_decl_can_not_refer_to_scoped_enum)
+            << SS.getRange();
+        return BuildInvalid();
+      }
     }
   }
+  
 
   UsingDecl *UD = BuildValid();
 
@@ -12318,44 +12330,61 @@
 /// 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.
+/// 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");
+
+  if (getLangOpts().CPlusPlus20) {
+    // There could be a type-tag and an enum.  There must only be an enum
+    EnumConstantDecl *ED = nullptr;
+    if (R)
+      ED = R->getAsSingle<EnumConstantDecl>();
+    else if (UD && UD->shadow_size () == 1)
+      ED = dyn_cast<EnumConstantDecl>(UD->shadow_begin()->getTargetDecl());
+
+    if (ED)
+      // Naming an enumerator is ok, regardless of heirarchy.  We check
+      // accessibility elsewhere.
+      return false;
+  }
 
   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;
-
+    if (NamedContext ? NamedContext->getRedeclContext()->isRecord()
+        : HasTypename) {
       Diag(NameLoc, 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)
+      if (!NamedContext)
         return true;
 
-      // Find what this using-declaration was referring to.
-      LookupResult R(*this, NameInfo, LookupOrdinaryName);
-      R.setHideTags(false);
-      R.suppressDiagnostics();
-      LookupQualifiedName(R, RD);
+      auto *RD = cast<CXXRecordDecl>(NamedContext->getRedeclContext());
+      if (RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), RD))
+        return true;
 
-      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)
@@ -12372,7 +12401,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;
@@ -12385,7 +12414,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.
@@ -12404,12 +12433,10 @@
       return true;
     }
 
-    // Otherwise, this might be valid.
+    // Otherwise ok
     return false;
   }
 
-  // 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
@@ -12421,6 +12448,8 @@
     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.
@@ -12506,6 +12535,7 @@
   return true;
 }
 
+
 Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
                                   MultiTemplateParamsArg TemplateParamLists,
                                   SourceLocation UsingLoc, UnqualifiedId &Name,
Index: clang/include/clang/Sema/Sema.h
===================================================================
--- clang/include/clang/Sema/Sema.h
+++ clang/include/clang/Sema/Sema.h
@@ -5545,7 +5545,9 @@
                                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
@@ -530,8 +530,8 @@
   "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 err_cxx14_using_decl_can_not_refer_to_scoped_enum : Error<
+  "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