Author: Chuanqi Xu
Date: 2026-05-08T03:48:54Z
New Revision: 2751c7ed066d08d3c801670e6c5629a39ddfe90e

URL: 
https://github.com/llvm/llvm-project/commit/2751c7ed066d08d3c801670e6c5629a39ddfe90e
DIFF: 
https://github.com/llvm/llvm-project/commit/2751c7ed066d08d3c801670e6c5629a39ddfe90e.diff

LOG: Reland [C++20] [Modules] Don't profiling the callee of CXXFoldExpr 
(#190732) (#195983)

Close https://github.com/llvm/llvm-project/issues/190333

For the test case, the root cause of the problem is, the compiler
thought the declaration of `operator &&` in consumer.cpp may change the
meaning of '&&' in the requrie clause of `F::operator()`. But it doesn't
make sense. Here we skip profiling the callee to solve the problem. Note
that we've already record the kind of the operator. So '&&' and '||'
won't be confused.

---

See the discussion in https://github.com/llvm/llvm-project/pull/194283

For the new found pattern that we may have other binary operator (e.g.,
operator +) in the require clause, e.g.,

```C++
template <typename T, typename U>
    requires requires(T t, U u) { t + u; }
  void operator()(T, U) {}
```

This is a new problem and we need to solve it in other PR.

Added: 
    clang/test/SemaCXX/GH190333.cpp

Modified: 
    clang/lib/AST/StmtProfile.cpp

Removed: 
    clang/test/Modules/polluted-operator.cppm


################################################################################
diff  --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 8219e57644be6..eb25e5260fd1a 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -2400,7 +2400,26 @@ void StmtProfiler::VisitMaterializeTemporaryExpr(
 }
 
 void StmtProfiler::VisitCXXFoldExpr(const CXXFoldExpr *S) {
-  VisitExpr(S);
+  VisitStmtNoChildren(S);
+  // The callee sub-expression is not part of how the expression is written,
+  // so it's not added to the profile.
+  //
+  // Example:
+  // template <typename... T> requires ((sizeof(T) > 0) && ...) void f() {}
+  // class A;
+  // void operator&&(A, A);
+  // template <typename... T> requires ((sizeof(T) > 0) && ...) void f() {}
+  //
+  // Both definitions have identically written fold expressions, but semantic
+  // analysis adds the overloaded operator to the second one.
+  if (S->getLHS())
+    Visit(S->getLHS());
+  else
+    ID.AddInteger(0);
+  if (S->getRHS())
+    Visit(S->getRHS());
+  else
+    ID.AddInteger(0);
   ID.AddInteger(S->getOperator());
 }
 

diff  --git a/clang/test/Modules/polluted-operator.cppm 
b/clang/test/Modules/polluted-operator.cppm
deleted file mode 100644
index 45cc5e37d6a64..0000000000000
--- a/clang/test/Modules/polluted-operator.cppm
+++ /dev/null
@@ -1,79 +0,0 @@
-// RUN: rm -rf %t
-// RUN: mkdir -p %t
-// RUN: split-file %s %t
-//
-// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/a.cppm -o %t/a.pcm
-// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fprebuilt-module-path=%t 
-emit-module-interface -o %t/b.pcm -verify
-//
-// Testing the behavior of `-fskip-odr-check-in-gmf`
-// RUN: %clang_cc1 -std=c++20 -fskip-odr-check-in-gmf  -emit-module-interface 
%t/a.cppm -o \
-// RUN:   %t/a.pcm
-// RUN: %clang_cc1 -std=c++20 -fskip-odr-check-in-gmf  %t/b.cppm 
-fprebuilt-module-path=%t \
-// RUN:   -emit-module-interface -DSKIP_ODR_CHECK_IN_GMF -o %t/b.pcm -verify
-
-// RUN: %clang_cc1 -std=c++20 -emit-reduced-module-interface %t/a.cppm -o 
%t/a.pcm
-// RUN: %clang_cc1 -std=c++20 %t/b.cppm -fprebuilt-module-path=%t 
-emit-reduced-module-interface \
-// RUN:     -o %t/b.pcm -verify -DREDUCED
-
-//--- foo.h
-
-namespace std
-{
-    template<class _Dom1>
-    void operator &&(_Dom1 __v, _Dom1 __w)
-    { 
-        return;
-    }
-}
-
-//--- bar.h
-namespace std 
-{
-  template<typename... _Types>
-    struct _Traits
-    {
-      static constexpr bool _S_copy_ctor =
-   (__is_trivial(_Types) && ...);
-    };
-
-  template<typename... _Types>
-    struct variant
-    {
-      void
-      swap(variant& __rhs)
-      noexcept((__is_trivial(_Types) && ...))
-      {
-      }
-    };
-}
-
-//--- a.cppm
-module;
-// The operator&& defined in 'foo.h' will pollute the 
-// expression '__is_trivial(_Types) && ...' in bar.h
-#include "foo.h"
-#include "bar.h"
-export module a;
-export namespace std {
-  using std::variant;
-  using std::_Traits;
-  using std::operator&&;
-}
-
-//--- b.cppm
-module;
-#include "bar.h"
-export module b;
-import a;
-export namespace std {
-  using std::variant;
-  using std::_Traits;
-  using std::operator&&;
-}
-
-#ifdef SKIP_ODR_CHECK_IN_GMF
-// expected-no-diagnostics
-#else
-// expected-error@* {{has 
diff erent definitions in 
diff erent modules; first 
diff erence is defined here found data member '_S_copy_ctor' with an 
initializer}}
-// expected-note@* {{but in 'a.<global>' found data member '_S_copy_ctor' with 
a 
diff erent initializer}}
-#endif

diff  --git a/clang/test/SemaCXX/GH190333.cpp b/clang/test/SemaCXX/GH190333.cpp
new file mode 100644
index 0000000000000..2c43eb7a16d8a
--- /dev/null
+++ b/clang/test/SemaCXX/GH190333.cpp
@@ -0,0 +1,6 @@
+// RUN: %clang_cc1 -std=c++20 -fsyntax-only -verify %s
+
+template <typename... T> requires ((sizeof(T) > 0) && ...) void f() {} // 
expected-note{{previous definition is here}}
+class A;
+void operator&&(A, A);
+template <typename... T> requires ((sizeof(T) > 0) && ...) void f() {} // 
expected-error{{redefinition of 'f'}}


        
_______________________________________________
cfe-commits mailing list
[email protected]
https://lists.llvm.org/cgi-bin/mailman/listinfo/cfe-commits

Reply via email to