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

Reply via email to