https://github.com/zwuis updated 
https://github.com/llvm/llvm-project/pull/143492

>From 658f3d3cb72ff9fbdb2315f894f39956eeabf135 Mon Sep 17 00:00:00 2001
From: Yanzuo Liu <zw...@outlook.com>
Date: Tue, 10 Jun 2025 16:41:57 +0800
Subject: [PATCH 1/2] Apply CWG400 'Using-declarations and the "struct hack"'
 to C++98 mode

---
 clang/docs/ReleaseNotes.rst                   |  2 +
 clang/lib/Sema/SemaDeclCXX.cpp                | 92 +++++--------------
 .../CXX/class.access/class.access.dcl/p1.cpp  |  7 +-
 .../basic.namespace/namespace.udecl/p3.cpp    | 25 ++---
 .../basic.namespace/namespace.udecl/p4.cpp    | 12 +--
 5 files changed, 35 insertions(+), 103 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index beed0da6883d6..d8f09a275c1f0 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -840,6 +840,8 @@ Bug Fixes to C++ Support
 - Fixed a pack substitution bug in deducing class template partial 
specializations. (#GH53609)
 - Fixed a crash when constant evaluating some explicit object member 
assignment operators. (#GH142835)
 - Fixed an access checking bug when substituting into concepts (#GH115838)
+- Correctly rejects invalid member using-declaration whose nested name 
specifier
+  refers to its own class in C++98 mode.
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 5ef2ae3ee857f..84c666578b79a 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -13632,82 +13632,36 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation 
UsingLoc, bool HasTypename,
       RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), NamedContext))
     return true;
 
-  if (getLangOpts().CPlusPlus11) {
-    // C++11 [namespace.udecl]p3:
-    //   In a using-declaration used as a member-declaration, the
-    //   nested-name-specifier shall name a base class of the class
-    //   being defined.
+  // CWG400 [namespace.udecl]p3:
+  //   In a using-declaration used as a member-declaration, the
+  //   nested-name-specifier shall name a base class of the class being 
defined.
 
-    if (cast<CXXRecordDecl>(CurContext)->isProvablyNotDerivedFrom(
-                                 cast<CXXRecordDecl>(NamedContext))) {
+  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(SS.getBeginLoc(),
-             diag::err_using_decl_nested_name_specifier_is_current_class)
-            << SS.getRange();
-        return !getLangOpts().CPlusPlus20;
-      }
-
-      if (!cast<CXXRecordDecl>(NamedContext)->isInvalidDecl()) {
-        Diag(SS.getBeginLoc(),
-             diag::err_using_decl_nested_name_specifier_is_not_base_class)
-            << SS.getScopeRep() << cast<CXXRecordDecl>(CurContext)
-            << SS.getRange();
-      }
-      return true;
+    if (Cxx20Enumerator) {
+      Diag(NameLoc, diag::warn_cxx17_compat_using_decl_non_member_enumerator)
+          << SS.getRange();
+      return false;
     }
 
-    return false;
-  }
-
-  // C++03 [namespace.udecl]p4:
-  //   A using-declaration used as a member-declaration shall refer
-  //   to a member of a base class of the class being defined [etc.].
-
-  // Salient point: SS doesn't have to name a base class as long as
-  // lookup only finds members from base classes.  Therefore we can
-  // diagnose here only if we can prove that can't happen,
-  // i.e. if the class hierarchies provably don't intersect.
-
-  // TODO: it would be nice if "definitely valid" results were cached
-  // in the UsingDecl and UsingShadowDecl so that these checks didn't
-  // need to be repeated.
+    if (CurContext == NamedContext) {
+      Diag(SS.getBeginLoc(),
+           diag::err_using_decl_nested_name_specifier_is_current_class)
+          << SS.getRange();
+      return !getLangOpts().CPlusPlus20;
+    }
 
-  llvm::SmallPtrSet<const CXXRecordDecl *, 4> Bases;
-  auto Collect = [&Bases](const CXXRecordDecl *Base) {
-    Bases.insert(Base);
+    if (!cast<CXXRecordDecl>(NamedContext)->isInvalidDecl()) {
+      Diag(SS.getBeginLoc(),
+           diag::err_using_decl_nested_name_specifier_is_not_base_class)
+          << SS.getScopeRep() << cast<CXXRecordDecl>(CurContext)
+          << SS.getRange();
+    }
     return true;
-  };
-
-  // Collect all bases. Return false if we find a dependent base.
-  if (!cast<CXXRecordDecl>(CurContext)->forallBases(Collect))
-    return false;
-
-  // Returns true if the base is dependent or is one of the accumulated base
-  // classes.
-  auto IsNotBase = [&Bases](const CXXRecordDecl *Base) {
-    return !Bases.count(Base);
-  };
-
-  // Return false if the class has a dependent base or if it or one
-  // of its bases is present in the base set of the current context.
-  if (Bases.count(cast<CXXRecordDecl>(NamedContext)) ||
-      !cast<CXXRecordDecl>(NamedContext)->forallBases(IsNotBase))
-    return false;
-
-  Diag(SS.getRange().getBegin(),
-       diag::err_using_decl_nested_name_specifier_is_not_base_class)
-    << SS.getScopeRep()
-    << cast<CXXRecordDecl>(CurContext)
-    << SS.getRange();
+  }
 
-  return true;
+  return false;
 }
 
 Decl *Sema::ActOnAliasDeclaration(Scope *S, AccessSpecifier AS,
diff --git a/clang/test/CXX/class.access/class.access.dcl/p1.cpp 
b/clang/test/CXX/class.access/class.access.dcl/p1.cpp
index fdb1373dd9b12..1ad4135e32ba5 100644
--- a/clang/test/CXX/class.access/class.access.dcl/p1.cpp
+++ b/clang/test/CXX/class.access/class.access.dcl/p1.cpp
@@ -323,21 +323,18 @@ namespace test4 {
     // expected-warning@-2 {{access declarations are deprecated; use using 
declarations instead}}
 #else
     // expected-error@-4 {{ISO C++11 does not allow access declarations; use 
using declarations instead}}
-    // expected-error@-5 {{using declaration refers to its own class}}
 #endif
+    // expected-error@-6 {{using declaration refers to its own class}}
 
     Subclass::foo; // legal in C++03
 #if __cplusplus <= 199711L
     // expected-warning@-2 {{access declarations are deprecated; use using 
declarations instead}}
 #else
     // expected-error@-4 {{ISO C++11 does not allow access declarations; use 
using declarations instead}}
-    // expected-error@-5 {{using declaration refers into 'Subclass', which is 
not a base class of 'C'}}
 #endif
+    // expected-error@-6 {{using declaration refers into 'Subclass', which is 
not a base class of 'C'}}
 
     int bar();
-#if __cplusplus <= 199711L
-    //expected-note@-2 {{target of using declaration}}
-#endif
     C::bar;
 #if __cplusplus <= 199711L
     // expected-warning@-2 {{access declarations are deprecated; use using 
declarations instead}}
diff --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp 
b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp
index 657695657e0f7..bcc26bf4f4356 100644
--- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp
+++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p3.cpp
@@ -30,17 +30,10 @@ class D2 : public B {
   using B::x;
   using C::g; // expected-error{{using declaration refers into 'C', which is 
not a base class of 'D2'}}
 
-  // These are valid in C++98 but not in C++11.
-  using D::f2;
-  using D::E2;
-  using D::e2;
-  using D::x2;
-#if __cplusplus >= 201103L
-  // expected-error@-5 {{using declaration refers into 'D', which is not a 
base class of 'D2'}}
-  // expected-error@-5 {{using declaration refers into 'D', which is not a 
base class of 'D2'}}
-  // expected-error@-5 {{using declaration refers into 'D', which is not a 
base class of 'D2'}}
-  // expected-error@-5 {{using declaration refers into 'D', which is not a 
base class of 'D2'}}
-#endif
+  using D::f2; // expected-error {{using declaration refers into 'D', which is 
not a base class of 'D2'}}
+  using D::E2; // expected-error {{using declaration refers into 'D', which is 
not a base class of 'D2'}}
+  using D::e2; // expected-error {{using declaration refers into 'D', which is 
not a base class of 'D2'}}
+  using D::x2; // expected-error {{using declaration refers into 'D', which is 
not a base class of 'D2'}}
 
   using B::EC;
   using B::EC::ec; // expected-warning {{a C++20 extension}} expected-warning 
0-1 {{C++11}}
@@ -71,13 +64,7 @@ namespace test1 {
     using Base::bar; // expected-error {{no member named 'bar'}}
     using Unrelated::foo; // expected-error {{not a base class}}
 
-    // In C++98, it's hard to see that these are invalid, because indirect
-    // references to base class members are permitted.
-    using C::foo;
-    using Subclass::foo;
-#if __cplusplus >= 201103L
-    // expected-error@-3 {{refers to its own class}}
-    // expected-error@-3 {{not a base class}}
-#endif
+    using C::foo; // expected-error {{refers to its own class}}
+    using Subclass::foo; // expected-error {{not a base class}}
   };
 }
diff --git a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp 
b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp
index 973cd77279f19..26b66350b86d9 100644
--- a/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp
+++ b/clang/test/CXX/dcl.dcl/basic.namespace/namespace.udecl/p4.cpp
@@ -206,17 +206,9 @@ namespace test4 {
     using InnerNS::foo; // expected-error {{not a class}}
     using Base::bar; // expected-error {{no member named 'bar'}}
     using Unrelated::foo; // expected-error {{not a base class}}
-    using C::foo; // legal in C++03
-    using Subclass::foo; // legal in C++03
-#if __cplusplus >= 201103L
-    // expected-error@-3 {{refers to its own class}}
-    // expected-error@-3 {{refers into 'Subclass', which is not a base class}}
-#endif
-
+    using C::foo; // expected-error {{refers to its own class}}
+    using Subclass::foo; // expected-error {{refers into 'Subclass', which is 
not a base class}}
     int bar();
-#if __cplusplus < 201103L
-    // expected-note@-2 {{target of using declaration}}
-#endif
     using C::bar; // expected-error {{refers to its own class}}
   };
 }

>From 380eb58f7ec1180caf0d5d143b9d3b9720231a66 Mon Sep 17 00:00:00 2001
From: Yanzuo Liu <zw...@outlook.com>
Date: Mon, 16 Jun 2025 21:14:31 +0800
Subject: [PATCH 2/2] Add tests, modify comments and release notes

---
 clang/docs/ReleaseNotes.rst                         |  7 +++++--
 clang/lib/Sema/SemaDeclCXX.cpp                      | 10 +++++++---
 clang/test/CXX/class.access/class.access.dcl/p1.cpp |  4 ++--
 clang/test/CXX/drs/cwg4xx.cpp                       |  7 +++++++
 4 files changed, 21 insertions(+), 7 deletions(-)

diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index d8f09a275c1f0..10f2e0bd8c0a4 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -159,6 +159,11 @@ Resolutions to C++ Defect Reports
 
 - Implemented `CWG2496 ref-qualifiers and virtual overriding 
<https://wg21.link/CWG2496>`_.
 
+- Fully implemented `CWG400 Using-declarations and the "struct hack" `
+  `<https://wg21.link/CWG400>`_. Correctly rejected invalid member
+  using-declaration whose nested-name-specifier doesn't refer to a base class 
of
+  the current class in C++98 mode.
+
 C Language Changes
 ------------------
 
@@ -840,8 +845,6 @@ Bug Fixes to C++ Support
 - Fixed a pack substitution bug in deducing class template partial 
specializations. (#GH53609)
 - Fixed a crash when constant evaluating some explicit object member 
assignment operators. (#GH142835)
 - Fixed an access checking bug when substituting into concepts (#GH115838)
-- Correctly rejects invalid member using-declaration whose nested name 
specifier
-  refers to its own class in C++98 mode.
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^
diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 84c666578b79a..841c245da1714 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -13632,9 +13632,13 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation 
UsingLoc, bool HasTypename,
       RequireCompleteDeclContext(const_cast<CXXScopeSpec&>(SS), NamedContext))
     return true;
 
-  // CWG400 [namespace.udecl]p3:
-  //   In a using-declaration used as a member-declaration, the
-  //   nested-name-specifier shall name a base class of the class being 
defined.
+  // C++26 [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 current class
+  //   ([expr.prim.this]). ...
+  // "have a nested-name-specifier naming a base class of the current class"
+  // was introduced by CWG400.
 
   if (cast<CXXRecordDecl>(CurContext)
           ->isProvablyNotDerivedFrom(cast<CXXRecordDecl>(NamedContext))) {
diff --git a/clang/test/CXX/class.access/class.access.dcl/p1.cpp 
b/clang/test/CXX/class.access/class.access.dcl/p1.cpp
index 1ad4135e32ba5..b7ee6c9a7c04b 100644
--- a/clang/test/CXX/class.access/class.access.dcl/p1.cpp
+++ b/clang/test/CXX/class.access/class.access.dcl/p1.cpp
@@ -318,7 +318,7 @@ namespace test4 {
     // expected-error@-4 {{ISO C++11 does not allow access declarations; use 
using declarations instead}}
 #endif
 
-    C::foo; // legal in C++03
+    C::foo;
 #if __cplusplus <= 199711L
     // expected-warning@-2 {{access declarations are deprecated; use using 
declarations instead}}
 #else
@@ -326,7 +326,7 @@ namespace test4 {
 #endif
     // expected-error@-6 {{using declaration refers to its own class}}
 
-    Subclass::foo; // legal in C++03
+    Subclass::foo;
 #if __cplusplus <= 199711L
     // expected-warning@-2 {{access declarations are deprecated; use using 
declarations instead}}
 #else
diff --git a/clang/test/CXX/drs/cwg4xx.cpp b/clang/test/CXX/drs/cwg4xx.cpp
index 210f7ae71ec04..0f8b684eebdd1 100644
--- a/clang/test/CXX/drs/cwg4xx.cpp
+++ b/clang/test/CXX/drs/cwg4xx.cpp
@@ -36,6 +36,13 @@ namespace cwg400 { // cwg400: 2.7
   // expected-error@-1 {{member 'a' found in multiple base classes of 
different types}}
   //   expected-note@#cwg400-A {{member type 'cwg400::A::a' found by ambiguous 
name lookup}}
   //   expected-note@#cwg400-B {{member type 'cwg400::B::a' found by ambiguous 
name lookup}}
+  struct F : A {};
+  struct G : A {
+    using G::A;
+    // expected-error@-1 {{using declaration refers to its own class}}
+    using F::a;
+    // expected-error@-1 {{using declaration refers into 'F', which is not a 
base class of 'G'}}
+  };
 } // namespace cwg400
 
 namespace cwg401 { // cwg401: 2.8

_______________________________________________
cfe-commits mailing list
cfe-commits@lists.llvm.org
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to