From 227d45e09c1fa20f35ca0142ba93276fe37e6ab0 Mon Sep 17 00:00:00 2001 From: Shafik Yaghmour Date: Mon, 29 Sep 2025 13:54:54 -0700 Subject: [PATCH 1/5] [Clang][Sema] Fix crash in CheckUsingDeclQualifier due to diagnostic missing an argument Crash report came in and it was pretty obvious the diagnostic line was just missing an argument. I supplied the argument and added a test. Fixes: https://github.com/llvm/llvm-project/issues/161072 --- clang/lib/Sema/SemaDeclCXX.cpp | 2 +- clang/test/SemaCXX/cxx98-compat.cpp | 4 ++++ 2 files changed, 5 insertions(+), 1 deletion(-) diff --git a/clang/lib/Sema/SemaDeclCXX.cpp b/clang/lib/Sema/SemaDeclCXX.cpp index 63ce87b9b0607..7fa411fd817ae 100644 --- a/clang/lib/Sema/SemaDeclCXX.cpp +++ b/clang/lib/Sema/SemaDeclCXX.cpp @@ -13643,7 +13643,7 @@ bool Sema::CheckUsingDeclQualifier(SourceLocation UsingLoc, bool HasTypename, if (Cxx20Enumerator) { Diag(NameLoc, diag::warn_cxx17_compat_using_decl_non_member_enumerator) - << SS.getRange(); + << SS.getScopeRep() << SS.getRange(); return false; } diff --git a/clang/test/SemaCXX/cxx98-compat.cpp b/clang/test/SemaCXX/cxx98-compat.cpp index 8e7acf73923e5..5651eee5a5c41 100644 --- a/clang/test/SemaCXX/cxx98-compat.cpp +++ b/clang/test/SemaCXX/cxx98-compat.cpp @@ -1,6 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify %s // RUN: %clang_cc1 -fsyntax-only -std=c++14 -Wc++98-compat -verify %s -DCXX14COMPAT // RUN: %clang_cc1 -fsyntax-only -std=c++17 -Wc++98-compat -verify %s -DCXX14COMPAT -DCXX17COMPAT +// RUN: %clang_cc1 -fsyntax-only -std=c++20 -Wc++98-compat -verify %s -DCXX14COMPAT -DCXX17COMPAT -DCXX20COMPAT namespace std { struct type_info; @@ -225,9 +226,12 @@ void TrivialButNonPODThroughEllipsis() { Ellipsis(1, TrivialButNonPOD()); // expected-warning {{passing object of trivial but non-POD type 'TrivialButNonPOD' through variadic function is incompatible with C++98}} } +// FIXME I think we generate this diagnostic in C++20 +#ifndef CXX20COMPAT struct HasExplicitConversion { explicit operator bool(); // expected-warning {{explicit conversion functions are incompatible with C++98}} }; +#endif struct Struct {}; enum Enum { enum_val = 0 }; From dece2b9c85709aa5733aeb30f16234ef474a05a7 Mon Sep 17 00:00:00 2001 From: Shafik Yaghmour Date: Mon, 29 Sep 2025 16:25:01 -0700 Subject: [PATCH 2/5] Adding tests. --- clang/test/SemaCXX/cxx98-compat.cpp | 12 ++++++++++++ 1 file changed, 12 insertions(+) diff --git a/clang/test/SemaCXX/cxx98-compat.cpp b/clang/test/SemaCXX/cxx98-compat.cpp index 5651eee5a5c41..104ccb4640c11 100644 --- a/clang/test/SemaCXX/cxx98-compat.cpp +++ b/clang/test/SemaCXX/cxx98-compat.cpp @@ -434,3 +434,15 @@ void ctad_test() { CTAD t = s; // expected-warning {{class template argument deduction is incompatible with C++ standards before C++17}} } #endif + +namespace GH161702 { +struct S { + enum E { A }; + using E::A; // expected-warning {{enumeration type in nested name specifier is incompatible with C++98}} +#ifndef CXX20COMPAT + // expected-error@-2 {{using declaration refers to its own class}} +#else + // expected-warning@-4 {{member using declaration naming non-class ''E'' enumerator is incompatible with C++ standards before C++20}} +#endif +}; +} From 096c6e4dd039947366051d6c41320ffab56974fb Mon Sep 17 00:00:00 2001 From: Shafik Yaghmour Date: Tue, 30 Sep 2025 13:37:40 -0700 Subject: [PATCH 3/5] Update test based on feedback. --- clang/test/SemaCXX/cxx98-compat.cpp | 7 +++---- 1 file changed, 3 insertions(+), 4 deletions(-) diff --git a/clang/test/SemaCXX/cxx98-compat.cpp b/clang/test/SemaCXX/cxx98-compat.cpp index 104ccb4640c11..692289cfa609e 100644 --- a/clang/test/SemaCXX/cxx98-compat.cpp +++ b/clang/test/SemaCXX/cxx98-compat.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify %s // RUN: %clang_cc1 -fsyntax-only -std=c++14 -Wc++98-compat -verify %s -DCXX14COMPAT // RUN: %clang_cc1 -fsyntax-only -std=c++17 -Wc++98-compat -verify %s -DCXX14COMPAT -DCXX17COMPAT -// RUN: %clang_cc1 -fsyntax-only -std=c++20 -Wc++98-compat -verify %s -DCXX14COMPAT -DCXX17COMPAT -DCXX20COMPAT +// RUN: %clang_cc1 -fsyntax-only -std=c++20 -Wc++98-compat -verify=expected,cpp20 %s -DCXX14COMPAT -DCXX17COMPAT -DCXX20COMPAT namespace std { struct type_info; @@ -226,7 +226,7 @@ void TrivialButNonPODThroughEllipsis() { Ellipsis(1, TrivialButNonPOD()); // expected-warning {{passing object of trivial but non-POD type 'TrivialButNonPOD' through variadic function is incompatible with C++98}} } -// FIXME I think we generate this diagnostic in C++20 +// FIXME I think we should generate this diagnostic in C++20 #ifndef CXX20COMPAT struct HasExplicitConversion { explicit operator bool(); // expected-warning {{explicit conversion functions are incompatible with C++98}} @@ -441,8 +441,7 @@ struct S { using E::A; // expected-warning {{enumeration type in nested name specifier is incompatible with C++98}} #ifndef CXX20COMPAT // expected-error@-2 {{using declaration refers to its own class}} -#else - // expected-warning@-4 {{member using declaration naming non-class ''E'' enumerator is incompatible with C++ standards before C++20}} #endif + // cpp20-warning@-4 {{member using declaration naming non-class ''E'' enumerator is incompatible with C++ standards before C++20}} }; } From b923feb16ff2e5720b53af9af8550c11101f709c Mon Sep 17 00:00:00 2001 From: Shafik Yaghmour Date: Wed, 1 Oct 2025 18:24:08 -0700 Subject: [PATCH 4/5] Start using not-cpp20 in verify argument. --- clang/test/SemaCXX/cxx98-compat.cpp | 18 +++++++----------- 1 file changed, 7 insertions(+), 11 deletions(-) diff --git a/clang/test/SemaCXX/cxx98-compat.cpp b/clang/test/SemaCXX/cxx98-compat.cpp index 692289cfa609e..6dc234154cd02 100644 --- a/clang/test/SemaCXX/cxx98-compat.cpp +++ b/clang/test/SemaCXX/cxx98-compat.cpp @@ -1,6 +1,6 @@ -// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify %s -// RUN: %clang_cc1 -fsyntax-only -std=c++14 -Wc++98-compat -verify %s -DCXX14COMPAT -// RUN: %clang_cc1 -fsyntax-only -std=c++17 -Wc++98-compat -verify %s -DCXX14COMPAT -DCXX17COMPAT +// RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify=expected,not-cpp20 %s +// RUN: %clang_cc1 -fsyntax-only -std=c++14 -Wc++98-compat -verify=expected,not-cpp20 %s -DCXX14COMPAT +// RUN: %clang_cc1 -fsyntax-only -std=c++17 -Wc++98-compat -verify=expected,not-cpp20 %s -DCXX14COMPAT -DCXX17COMPAT // RUN: %clang_cc1 -fsyntax-only -std=c++20 -Wc++98-compat -verify=expected,cpp20 %s -DCXX14COMPAT -DCXX17COMPAT -DCXX20COMPAT namespace std { @@ -226,12 +226,10 @@ void TrivialButNonPODThroughEllipsis() { Ellipsis(1, TrivialButNonPOD()); // expected-warning {{passing object of trivial but non-POD type 'TrivialButNonPOD' through variadic function is incompatible with C++98}} } -// FIXME I think we should generate this diagnostic in C++20 -#ifndef CXX20COMPAT struct HasExplicitConversion { - explicit operator bool(); // expected-warning {{explicit conversion functions are incompatible with C++98}} + // FIXME I think we should generate this diagnostic in C++20 + explicit operator bool(); // not-cpp20-warning {{explicit conversion functions are incompatible with C++98}} }; -#endif struct Struct {}; enum Enum { enum_val = 0 }; @@ -439,9 +437,7 @@ namespace GH161702 { struct S { enum E { A }; using E::A; // expected-warning {{enumeration type in nested name specifier is incompatible with C++98}} -#ifndef CXX20COMPAT - // expected-error@-2 {{using declaration refers to its own class}} -#endif - // cpp20-warning@-4 {{member using declaration naming non-class ''E'' enumerator is incompatible with C++ standards before C++20}} + // not-cpp20-error@-1 {{using declaration refers to its own class}} + // cpp20-warning@-2 {{member using declaration naming non-class ''E'' enumerator is incompatible with C++ standards before C++20}} }; } From f6a0806b81152d22913bffb905854bd9e96f91cb Mon Sep 17 00:00:00 2001 From: Shafik Yaghmour Date: Wed, 1 Oct 2025 18:27:30 -0700 Subject: [PATCH 5/5] Removing unneeded bits from the test --- clang/test/SemaCXX/cxx98-compat.cpp | 6 +++--- 1 file changed, 3 insertions(+), 3 deletions(-) diff --git a/clang/test/SemaCXX/cxx98-compat.cpp b/clang/test/SemaCXX/cxx98-compat.cpp index 6dc234154cd02..587c242271a02 100644 --- a/clang/test/SemaCXX/cxx98-compat.cpp +++ b/clang/test/SemaCXX/cxx98-compat.cpp @@ -1,7 +1,7 @@ // RUN: %clang_cc1 -fsyntax-only -std=c++11 -Wc++98-compat -verify=expected,not-cpp20 %s // RUN: %clang_cc1 -fsyntax-only -std=c++14 -Wc++98-compat -verify=expected,not-cpp20 %s -DCXX14COMPAT // RUN: %clang_cc1 -fsyntax-only -std=c++17 -Wc++98-compat -verify=expected,not-cpp20 %s -DCXX14COMPAT -DCXX17COMPAT -// RUN: %clang_cc1 -fsyntax-only -std=c++20 -Wc++98-compat -verify=expected,cpp20 %s -DCXX14COMPAT -DCXX17COMPAT -DCXX20COMPAT +// RUN: %clang_cc1 -fsyntax-only -std=c++20 -Wc++98-compat -verify=expected,cpp20 %s -DCXX14COMPAT -DCXX17COMPAT namespace std { struct type_info; @@ -437,7 +437,7 @@ namespace GH161702 { struct S { enum E { A }; using E::A; // expected-warning {{enumeration type in nested name specifier is incompatible with C++98}} - // not-cpp20-error@-1 {{using declaration refers to its own class}} - // cpp20-warning@-2 {{member using declaration naming non-class ''E'' enumerator is incompatible with C++ standards before C++20}} + // not-cpp20-error@-1 {{using declaration refers to its own class}} + // cpp20-warning@-2 {{member using declaration naming non-class ''E'' enumerator is incompatible with C++ standards before C++20}} }; }