From 5b3e3d5b66bd45d9d08c274134bd49dbdb250fef Mon Sep 17 00:00:00 2001 From: Corentin Jabot Date: Thu, 9 Oct 2025 11:06:10 +0200 Subject: [PATCH] [Clang] Ensure compound requirements do not contain placeholder expressions The name of an overloasd set is not a valid id expression. Fixes #51246 Fixes #97753 --- clang/docs/ReleaseNotes.rst | 1 + clang/lib/Parse/ParseExprCXX.cpp | 4 ++ .../AST/ByteCode/libcxx/deref-to-array.cpp | 2 +- clang/test/SemaTemplate/concepts.cpp | 42 ++++++++++++++++--- 4 files changed, 43 insertions(+), 6 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index 9a0d69c6c1b0e..12c632ed0c24a 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -455,6 +455,7 @@ Bug Fixes to C++ Support - Fix a crash when attempting to deduce a deduction guide from a non deducible template template parameter. (#130604) - Fix for clang incorrectly rejecting the default construction of a union with nontrivial member when another member has an initializer. (#GH81774) +- Diagnose unresolved overload sets in non-dependent compound requirements. (#GH51246) (#GH97753) Bug Fixes to AST Handling ^^^^^^^^^^^^^^^^^^^^^^^^^ diff --git a/clang/lib/Parse/ParseExprCXX.cpp b/clang/lib/Parse/ParseExprCXX.cpp index a2c69578d5087..90191b0aeb666 100644 --- a/clang/lib/Parse/ParseExprCXX.cpp +++ b/clang/lib/Parse/ParseExprCXX.cpp @@ -3200,6 +3200,8 @@ ExprResult Parser::ParseRequiresExpression() { BalancedDelimiterTracker ExprBraces(*this, tok::l_brace); ExprBraces.consumeOpen(); ExprResult Expression = ParseExpression(); + if (Expression.isUsable()) + Expression = Actions.CheckPlaceholderExpr(Expression.get()); if (!Expression.isUsable()) { ExprBraces.skipToEnd(); SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); @@ -3369,6 +3371,8 @@ ExprResult Parser::ParseRequiresExpression() { // expression ';' SourceLocation StartLoc = Tok.getLocation(); ExprResult Expression = ParseExpression(); + if (Expression.isUsable()) + Expression = Actions.CheckPlaceholderExpr(Expression.get()); if (!Expression.isUsable()) { SkipUntil(tok::semi, tok::r_brace, SkipUntilFlags::StopBeforeMatch); break; diff --git a/clang/test/AST/ByteCode/libcxx/deref-to-array.cpp b/clang/test/AST/ByteCode/libcxx/deref-to-array.cpp index 2a527ab336a0d..7cfcd76b3965a 100644 --- a/clang/test/AST/ByteCode/libcxx/deref-to-array.cpp +++ b/clang/test/AST/ByteCode/libcxx/deref-to-array.cpp @@ -270,7 +270,7 @@ template void __is_derived_from_view_interface(); template bool enable_view = derived_from<_Tp, int> || - requires { ranges::__is_derived_from_view_interface; }; + requires { ranges::__is_derived_from_view_interface<_Tp, int>(); }; template concept range = requires { ranges::end; }; template diff --git a/clang/test/SemaTemplate/concepts.cpp b/clang/test/SemaTemplate/concepts.cpp index 3b7c138f83364..768af09afe9e2 100644 --- a/clang/test/SemaTemplate/concepts.cpp +++ b/clang/test/SemaTemplate/concepts.cpp @@ -1037,7 +1037,7 @@ void test() { namespace GH66612 { template - auto end(C c) ->int; + auto end(C c) ->int; // expected-note {{possible target for call}} template concept Iterator = true; @@ -1047,9 +1047,8 @@ namespace GH66612 { { end } -> Iterator; // #66612GH_END }; - static_assert(Container);// expected-error{{static assertion failed}} - // expected-note@-1{{because 'int' does not satisfy 'Container'}} - // expected-note@#66612GH_END{{because 'end' would be invalid: reference to overloaded function could not be resolved; did you mean to call it?}} + static_assert(Container); + // expected-error@#66612GH_END{{reference to overloaded function could not be resolved; did you mean to call it?}} } namespace GH66938 { @@ -1407,7 +1406,6 @@ static_assert(!std::is_constructible_v, array>); } - namespace GH162125 { template concept true_int = (size, true); @@ -1444,3 +1442,37 @@ struct s { void(*test)(int) = &s::f; } +namespace GH51246 { +void f(); // expected-note {{possible target for call}} +void f(int); // expected-note {{possible target for call}} +void g(); +static_assert(requires { f; }); // expected-error {{reference to overloaded function could not be resolved}} +static_assert(requires { g; }); +struct S { + void mf() { + static_assert(requires { mf(); }); + static_assert(requires { mf; }); // expected-error {{reference to non-static member function must be called}} + static_assert(requires { S::mf; }); // expected-error {{reference to non-static member function must be called}} + } + void mf2(int); // expected-note 2{{possible target for call}} + void mf2() { // expected-note 2{{possible target for call}} + static_assert(requires { mf2; }); // expected-error {{reference to non-static member function must be called}} + static_assert(requires { S::mf2; }); // expected-error {{reference to non-static member function must be called}} + } +}; + +} // namespace GH51246 + + +namespace GH97753 { + +void f(); // expected-note {{possible target for call}} +void f(int); // expected-note {{possible target for call}} + +template +concept C = sizeof(T) == 42; + +static_assert( requires {{ &f } -> C;} ); // expected-error {{reference to overloaded function could not be resolved;}} +// expected-error@-1 {{static assertion failed due to requirement 'requires { { &f() } -> C; }'}} + +}