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