https://github.com/offsetof updated https://github.com/llvm/llvm-project/pull/133747
>From 175e2531de9e2fceb72b25aed5073b225e2495ac Mon Sep 17 00:00:00 2001 From: offsetof <offse...@mailo.com> Date: Mon, 31 Mar 2025 16:35:03 +0000 Subject: [PATCH 1/2] [clang] Implement CWG2611 CWG2611 "Missing parentheses in expansion of fold-expression could cause syntactic reinterpretation" --- clang/docs/ReleaseNotes.rst | 1 + clang/lib/Sema/TreeTransform.h | 15 +++++++++--- clang/test/CXX/drs/cwg26xx.cpp | 23 +++++++++++++++++++ clang/test/CXX/temp/temp.param/p10-2a.cpp | 8 +++---- .../instantiate-requires-expr.cpp | 20 ++++++++-------- clang/www/cxx_dr_status.html | 2 +- 6 files changed, 51 insertions(+), 18 deletions(-) diff --git a/clang/docs/ReleaseNotes.rst b/clang/docs/ReleaseNotes.rst index daad01919ecd4..51b575f1b15d1 100644 --- a/clang/docs/ReleaseNotes.rst +++ b/clang/docs/ReleaseNotes.rst @@ -110,6 +110,7 @@ Resolutions to C++ Defect Reports two releases. The improvements to template template parameter matching implemented in the previous release, as described in P3310 and P3579, made this flag unnecessary. +- Implemented `CWG2611 Missing parentheses in expansion of fold-expression could cause syntactic reinterpretation <https://cplusplus.github.io/CWG/issues/2611>`_ - Implemented `CWG2918 Consideration of constraints for address of overloaded ` `function <https://cplusplus.github.io/CWG/issues/2918.html>`_ diff --git a/clang/lib/Sema/TreeTransform.h b/clang/lib/Sema/TreeTransform.h index 8fdb2cf6dce6c..aa23da298864f 100644 --- a/clang/lib/Sema/TreeTransform.h +++ b/clang/lib/Sema/TreeTransform.h @@ -16441,14 +16441,23 @@ TreeTransform<Derived>::TransformCXXFoldExpr(CXXFoldExpr *E) { return true; } - if (ParenExpr *PE = dyn_cast_or_null<ParenExpr>(Result.get())) - PE->setIsProducedByFoldExpansion(); - // If we had no init and an empty pack, and we're not retaining an expansion, // then produce a fallback value or error. if (Result.isUnset()) return getDerived().RebuildEmptyCXXFoldExpr(E->getEllipsisLoc(), E->getOperator()); + + // Wrap the result in a ParenExpr if it isn't already one (see CWG2611). + ParenExpr *PE = dyn_cast<ParenExpr>(Result.get()); + if (!PE) { + Result = getDerived().RebuildParenExpr(Result.get(), E->getLParenLoc(), + E->getRParenLoc()); + if (Result.isInvalid()) + return true; + PE = cast<ParenExpr>(Result.get()); + } + PE->setIsProducedByFoldExpansion(); + return Result; } diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp index 3eb70583b6026..5bb955dedd766 100644 --- a/clang/test/CXX/drs/cwg26xx.cpp +++ b/clang/test/CXX/drs/cwg26xx.cpp @@ -35,6 +35,29 @@ namespace std { template<typename T> T declval(); } // namespace std +namespace cwg2611 { // cwg2611: 21 +#if __cpp_fold_expressions >= 201603 +template<class> class R {}; +template<class... Ts> auto a(Ts... xs) -> R<decltype((xs + ...))>; +template<class... Ts> auto b(Ts... xs) -> R<decltype((..., xs))>; +template<class... Ts> auto c(Ts... xs, int i = 0) -> R<decltype((xs * ... * i))>; +template<class... Ts> auto d(Ts... xs, int i = 0) -> R<decltype((i ^ ... ^ xs))>; +R<int&> i = a(1); +R<int&> j = b(1); +R<int&> k = c(); +R<int&> l = d(); + +template<int... Is> constexpr int w = 0 * (Is + ...); +template<int... Is> constexpr int x = 0 * (... + Is); +template<int... Is> constexpr int y = 0 * (Is + ... + 1); +template<int... Is> constexpr int z = 0 * (1 + ... + Is); +static_assert(w<1, 2> == 0); +static_assert(x<1, 2> == 0); +static_assert(y<1, 2> == 0); +static_assert(z<1, 2> == 0); +#endif +} // namespace cwg2611 + namespace cwg2621 { // cwg2621: sup 2877 #if __cplusplus >= 202002L enum class E { a }; diff --git a/clang/test/CXX/temp/temp.param/p10-2a.cpp b/clang/test/CXX/temp/temp.param/p10-2a.cpp index 4f5fdd3b4809a..281c66bf9da90 100644 --- a/clang/test/CXX/temp/temp.param/p10-2a.cpp +++ b/clang/test/CXX/temp/temp.param/p10-2a.cpp @@ -27,10 +27,10 @@ using b4 = B<short, char>; // expected-error {{constraints not satisfied for ali template<typename... T> concept C3 = (sizeof(T) + ...) == 12; -// expected-note@-1 {{because 'sizeof(char[11]) == 12' (11 == 12) evaluated to false}} -// expected-note@-2 {{because 'sizeof(char[10]) == 12' (10 == 12) evaluated to false}} -// expected-note@-3 3{{because 'sizeof(int) == 12' (4 == 12) evaluated to false}} -// expected-note@-4 6{{because 'sizeof(short) == 12' (2 == 12) evaluated to false}} +// expected-note@-1 {{because '(sizeof(char[11])) == 12' (11 == 12) evaluated to false}} +// expected-note@-2 {{because '(sizeof(char[10])) == 12' (10 == 12) evaluated to false}} +// expected-note@-3 3{{because '(sizeof(int)) == 12' (4 == 12) evaluated to false}} +// expected-note@-4 6{{because '(sizeof(short)) == 12' (2 == 12) evaluated to false}} template<C3 T1, C3 T2, C3 T3> // expected-note@-1 {{because 'char[11]' does not satisfy 'C3'}} diff --git a/clang/test/SemaTemplate/instantiate-requires-expr.cpp b/clang/test/SemaTemplate/instantiate-requires-expr.cpp index a1f5456156a06..2930c5a2eb05d 100644 --- a/clang/test/SemaTemplate/instantiate-requires-expr.cpp +++ b/clang/test/SemaTemplate/instantiate-requires-expr.cpp @@ -35,7 +35,7 @@ using r1i2 = r1<char>; // expected-error {{constraints not satisfied for class t template<typename... Ts> requires false_v<requires (Ts... ts) {requires ((sizeof(ts) == 2) && ...);}> -// expected-note@-1 {{because 'false_v<requires (short ts, unsigned short ts) { requires (sizeof (ts) == 2) && (sizeof (ts) == 2); }>'}} +// expected-note@-1 {{because 'false_v<requires (short ts, unsigned short ts) { requires ((sizeof (ts) == 2) && (sizeof (ts) == 2)); }>'}} // expected-note@-2 {{because 'false_v<requires (short ts) { requires (sizeof (ts) == 2); }>' evaluated to false}} struct r2 {}; @@ -44,8 +44,8 @@ using r2i2 = r2<short>; // expected-error {{constraints not satisfied for class template<typename... Ts> requires false_v<(requires (Ts ts) {requires sizeof(ts) != 0;} && ...)> -// expected-note@-1 {{because 'false_v<requires (short ts) { requires sizeof (ts) != 0; } && requires (unsigned short ts) { requires sizeof (ts) != 0; }>' evaluated to false}} -// expected-note@-2 {{because 'false_v<requires (short ts) { requires sizeof (ts) != 0; }>' evaluated to false}} +// expected-note@-1 {{because 'false_v<(requires (short ts) { requires sizeof (ts) != 0; } && requires (unsigned short ts) { requires sizeof (ts) != 0; })>' evaluated to false}} +// expected-note@-2 {{because 'false_v<(requires (short ts) { requires sizeof (ts) != 0; })>' evaluated to false}} struct r3 {}; using r3i1 = r3<short, unsigned short>; // expected-error {{constraints not satisfied for class template 'r3' [with Ts = <short, unsigned short>]}} @@ -93,19 +93,19 @@ namespace type_requirement { // Parameter pack inside expr template<typename... Ts> requires false_v<(requires { typename Ts::type; } && ...)> - // expected-note@-1 {{because 'false_v<requires { typename identity<short>::type; } && requires { typename identity<int>::type; } && requires { <<error-type>>; }>' evaluated to false}} + // expected-note@-1 {{because 'false_v<(requires { typename identity<short>::type; } && requires { typename identity<int>::type; } && requires { <<error-type>>; })>' evaluated to false}} struct r5 {}; using r5i = r5<identity<short>, identity<int>, short>; // expected-error{{constraints not satisfied for class template 'r5' [with Ts = <identity<short>, identity<int>, short>]}} template<typename... Ts> requires - false_v<(requires { typename void_t<Ts>; } && ...)> // expected-note{{because 'false_v<requires { typename void_t<int>; } && requires { typename void_t<short>; }>' evaluated to false}} + false_v<(requires { typename void_t<Ts>; } && ...)> // expected-note{{because 'false_v<(requires { typename void_t<int>; } && requires { typename void_t<short>; })>' evaluated to false}} struct r6 {}; using r6i = r6<int, short>; // expected-error{{constraints not satisfied for class template 'r6' [with Ts = <int, short>]}} template<typename... Ts> requires false_v<(requires { typename Ts::template aaa<Ts>; } && ...)> - // expected-note@-1 {{because 'false_v<requires { <<error-type>>; } && requires { <<error-type>>; }>' evaluated to false}} + // expected-note@-1 {{because 'false_v<(requires { <<error-type>>; } && requires { <<error-type>>; })>' evaluated to false}} struct r7 {}; using r7i = r7<int, A>; // expected-error{{constraints not satisfied for class template 'r7' [with Ts = <int, type_requirement::A>]}} @@ -160,7 +160,7 @@ namespace expr_requirement { template<typename... Ts> requires false_v<(requires { { 0 } noexcept -> C1<Ts>; } && ...)> - // expected-note@-1 {{because 'false_v<requires { { 0 } noexcept -> C1<int>; } && requires { { 0 } noexcept -> C1<unsigned int>; }>' evaluated to false}} + // expected-note@-1 {{because 'false_v<(requires { { 0 } noexcept -> C1<int>; } && requires { { 0 } noexcept -> C1<unsigned int>; })>' evaluated to false}} struct r3 {}; using r3i = r3<int, unsigned int>; // expected-error{{constraints not satisfied for class template 'r3' [with Ts = <int, unsigned int>]}} @@ -199,7 +199,7 @@ namespace nested_requirement { // Parameter pack inside expr template<typename... Ts> requires false_v<(requires { requires sizeof(Ts) == 0; } && ...)> - // expected-note@-1 {{because 'false_v<requires { requires sizeof(int) == 0; } && requires { requires sizeof(short) == 0; }>' evaluated to false}} + // expected-note@-1 {{because 'false_v<(requires { requires sizeof(int) == 0; } && requires { requires sizeof(short) == 0; })>' evaluated to false}} struct r2 {}; using r2i = r2<int, short>; // expected-error{{constraints not satisfied for class template 'r2' [with Ts = <int, short>]}} @@ -208,14 +208,14 @@ namespace nested_requirement { // Parameter pack inside multiple requirements template<typename... Ts> requires false_v<(requires { requires sizeof(Ts) == 0; sizeof(Ts); } && ...)> -// expected-note@-1 {{because 'false_v<requires { requires sizeof(int) == 0; sizeof(Ts); } && requires { requires sizeof(short) == 0; sizeof(Ts); }>' evaluated to false}} +// expected-note@-1 {{because 'false_v<(requires { requires sizeof(int) == 0; sizeof(Ts); } && requires { requires sizeof(short) == 0; sizeof(Ts); })>' evaluated to false}} struct r4 {}; using r4i = r4<int, short>; // expected-error{{constraints not satisfied for class template 'r4' [with Ts = <int, short>]}} template<typename... Ts> requires false_v<(requires(Ts t) { requires sizeof(t) == 0; t++; } && ...)> -// expected-note@-1 {{because 'false_v<requires (int t) { requires sizeof (t) == 0; t++; } && requires (short t) { requires sizeof (t) == 0; t++; }>' evaluated to false}} +// expected-note@-1 {{because 'false_v<(requires (int t) { requires sizeof (t) == 0; t++; } && requires (short t) { requires sizeof (t) == 0; t++; })>' evaluated to false}} struct r5 {}; using r5i = r5<int, short>; // expected-error{{constraints not satisfied for class template 'r5' [with Ts = <int, short>]}} diff --git a/clang/www/cxx_dr_status.html b/clang/www/cxx_dr_status.html index 138f12facf0ad..55d16a5da0174 100755 --- a/clang/www/cxx_dr_status.html +++ b/clang/www/cxx_dr_status.html @@ -15513,7 +15513,7 @@ <h2 id="cxxdr">C++ defect report implementation status</h2> <td><a href="https://cplusplus.github.io/CWG/issues/2611.html">2611</a></td> <td>C++23</td> <td>Missing parentheses in expansion of fold-expression could cause syntactic reinterpretation</td> - <td class="unknown" align="center">Unknown</td> + <td class="unreleased" align="center">Clang 21</td> </tr> <tr id="2612"> <td><a href="https://cplusplus.github.io/CWG/issues/2612.html">2612</a></td> >From 2b4e67367122f86ee79a1b091329b6fab8bcf679 Mon Sep 17 00:00:00 2001 From: offsetof <offse...@mailo.com> Date: Wed, 2 Apr 2025 14:32:30 +0000 Subject: [PATCH 2/2] fixup! [clang] Implement CWG2611 Replace feature-test macro with `__cplusplus` --- clang/test/CXX/drs/cwg26xx.cpp | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) diff --git a/clang/test/CXX/drs/cwg26xx.cpp b/clang/test/CXX/drs/cwg26xx.cpp index 5bb955dedd766..f86e7908acb57 100644 --- a/clang/test/CXX/drs/cwg26xx.cpp +++ b/clang/test/CXX/drs/cwg26xx.cpp @@ -36,7 +36,7 @@ namespace std { } // namespace std namespace cwg2611 { // cwg2611: 21 -#if __cpp_fold_expressions >= 201603 +#if __cplusplus >= 201703L template<class> class R {}; template<class... Ts> auto a(Ts... xs) -> R<decltype((xs + ...))>; template<class... Ts> auto b(Ts... xs) -> R<decltype((..., xs))>; _______________________________________________ cfe-commits mailing list cfe-commits@lists.llvm.org https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits