Author: Yanzuo Liu
Date: 2025-07-05T14:30:28+08:00
New Revision: 3d6f4fb5f7acb1cecd8ee143627d2538781a6241

URL: 
https://github.com/llvm/llvm-project/commit/3d6f4fb5f7acb1cecd8ee143627d2538781a6241
DIFF: 
https://github.com/llvm/llvm-project/commit/3d6f4fb5f7acb1cecd8ee143627d2538781a6241.diff

LOG: [Clang][Sema] Do not perform error recovery for invalid member 
using-declaration in C++20+ mode (#147003)

Previously, Clang tried to perform error recovery for invalid member
using-declaration whose nested-name-specifier refers to its own class in
C++20+ mode, which causes crash.

```cpp
template <typename...> struct V {};
struct S : V<> {
  using S::V; // error recovery here
  V<> v; // crash
};
```

This PR disables the error recovery to fix the crash.

Fixes #63254

Added: 
    

Modified: 
    clang/docs/ReleaseNotes.rst
    clang/lib/Sema/SemaDeclCXX.cpp
    clang/test/SemaCXX/nested-name-spec.cpp

Removed: 
    


################################################################################
diff  --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst
index 3cd4508db9202..9a94c4bcd9980 100644
--- a/clang/docs/ReleaseNotes.rst
+++ b/clang/docs/ReleaseNotes.rst
@@ -900,6 +900,7 @@ Bug Fixes to C++ Support
 - Fixed an access checking bug when substituting into concepts (#GH115838)
 - Fix a bug where private access specifier of overloaded function not 
respected. (#GH107629)
 - Correctly handle allocations in the condition of a ``if 
constexpr``.(#GH120197) (#GH134820)
+- Fixed a crash when handling invalid member using-declaration in C++20+ mode. 
(#GH63254)
 
 Bug Fixes to AST Handling
 ^^^^^^^^^^^^^^^^^^^^^^^^^

diff  --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp
index 773148500f0af..f0247f865ba40 100644
--- a/clang/lib/Sema/SemaDeclCXX.cpp
+++ b/clang/lib/Sema/SemaDeclCXX.cpp
@@ -13638,7 +13638,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation 
UsingLoc, bool HasTypename,
       Diag(SS.getBeginLoc(),
            diag::err_using_decl_nested_name_specifier_is_current_class)
           << SS.getRange();
-      return !getLangOpts().CPlusPlus20;
+      return true;
     }
 
     if (!cast<CXXRecordDecl>(NamedContext)->isInvalidDecl()) {

diff  --git a/clang/test/SemaCXX/nested-name-spec.cpp 
b/clang/test/SemaCXX/nested-name-spec.cpp
index abeaba9d8dde2..fedbb3070070b 100644
--- a/clang/test/SemaCXX/nested-name-spec.cpp
+++ b/clang/test/SemaCXX/nested-name-spec.cpp
@@ -1,4 +1,11 @@
-// RUN: %clang_cc1 -fsyntax-only -std=c++98 -verify -fblocks %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++98 -verify=expected,cxx98,cxx98-11 
-fblocks %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++11 
-verify=expected,since-cxx11,cxx98-11 -fblocks %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++14 -verify=expected,since-cxx11 
-fblocks %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++17 -verify=expected,since-cxx11 
-fblocks %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++20 
-verify=expected,since-cxx11,since-cxx20 -fblocks %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++23 
-verify=expected,since-cxx11,since-cxx20 -fblocks %s
+// RUN: %clang_cc1 -fsyntax-only -std=c++26 
-verify=expected,since-cxx11,since-cxx20 -fblocks %s
+
 namespace A {
   struct C {
     static int cx;
@@ -118,7 +125,7 @@ namespace E {
     };
 
     int f() {
-      return E::X; // expected-warning{{use of enumeration in a nested name 
specifier is a C++11 extension}}
+      return E::X; // cxx98-warning{{use of enumeration in a nested name 
specifier is a C++11 extension}}
     }
   }
 }
@@ -170,8 +177,9 @@ void ::global_func2(int) { } // expected-warning{{extra 
qualification on member
 
 void N::f() { } // okay
 
-struct Y;  // expected-note{{forward declaration of 'Y'}}
-Y::foo y; // expected-error{{incomplete type 'Y' named in nested name 
specifier}}
+// FIXME (GH147000): duplicate diagnostics
+struct Y;  // expected-note{{forward declaration of 'Y'}} 
since-cxx20-note{{forward declaration of 'Y'}}
+Y::foo y; // expected-error{{incomplete type 'Y' named in nested name 
specifier}} since-cxx20-error{{incomplete type 'Y' named in nested name 
specifier}}
 
 namespace PR25156 {
 struct Y;  // expected-note{{forward declaration of 'PR25156::Y'}}
@@ -189,7 +197,9 @@ bool (foo_S::value);
 
 
 namespace somens {
-  struct a { }; // expected-note{{candidate constructor (the implicit copy 
constructor)}}
+  struct a { };
+  // expected-note@-1 {{candidate constructor (the implicit copy constructor)}}
+  // since-cxx11-note@-2 {{candidate constructor (the implicit move 
constructor)}}
 }
 
 template <typename T>
@@ -432,20 +442,20 @@ namespace PR16951 {
     };
   }
 
-  int x1 = ns::an_enumeration::ENUMERATOR; // expected-warning{{use of 
enumeration in a nested name specifier is a C++11 extension}}
+  int x1 = ns::an_enumeration::ENUMERATOR; // cxx98-warning{{use of 
enumeration in a nested name specifier is a C++11 extension}}
 
-  int x2 = ns::an_enumeration::ENUMERATOR::vvv; // expected-warning{{use of 
enumeration in a nested name specifier is a C++11 extension}} \
+  int x2 = ns::an_enumeration::ENUMERATOR::vvv; // cxx98-warning{{use of 
enumeration in a nested name specifier is a C++11 extension}} \
                                                 // 
expected-error{{'ENUMERATOR' is not a class, namespace, or enumeration}} \
 
-  int x3 = ns::an_enumeration::X; // expected-warning{{use of enumeration in a 
nested name specifier is a C++11 extension}} \
+  int x3 = ns::an_enumeration::X; // cxx98-warning {{use of enumeration in a 
nested name specifier is a C++11 extension}} \
                                   // expected-error{{no member named 'X'}}
 
   enum enumerator_2 {
     ENUMERATOR_2
   };
 
-  int x4 = enumerator_2::ENUMERATOR_2; // expected-warning{{use of enumeration 
in a nested name specifier is a C++11 extension}}
-  int x5 = enumerator_2::X2; // expected-warning{{use of enumeration in a 
nested name specifier is a C++11 extension}} \
+  int x4 = enumerator_2::ENUMERATOR_2; // cxx98-warning{{use of enumeration in 
a nested name specifier is a C++11 extension}}
+  int x5 = enumerator_2::X2; // cxx98-warning{{use of enumeration in a nested 
name specifier is a C++11 extension}} \
                              // expected-error{{no member named 'X2' in 
'PR16951::enumerator_2'}} \
                              // expected-error{{cannot initialize a variable 
of type 'int' with an lvalue of type 'int (*)()'}}
 
@@ -487,7 +497,7 @@ struct x; // expected-note {{template is declared here}}
 
 template <typename T>
 int issue55962 = x::a; // expected-error {{use of class template 'x' requires 
template arguments}} \
-                       // expected-warning {{variable templates are a C++14 
extension}}
+                       // cxx98-11-warning {{variable templates are a C++14 
extension}}
 
 namespace ForwardDeclared {
   typedef class A B;
@@ -496,3 +506,11 @@ namespace ForwardDeclared {
     void F(B::C);
   };
 }
+
+namespace GH63254 {
+template <typename...> struct V {}; // cxx98-warning {{variadic templates are 
a C++11 extension}}
+struct S : V<> {
+  using S::V; // expected-error {{using declaration refers to its own class}}
+  V<> v; // no crash
+};
+}


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

Reply via email to