https://github.com/llvmbot created https://github.com/llvm/llvm-project/pull/196472
Backport 2751c7ed066d08d3c801670e6c5629a39ddfe90e Requested by: @ChuanqiXu9 >From 1b8ebef9fd2de93ae76c81f002aabdbad8d554e7 Mon Sep 17 00:00:00 2001 From: Chuanqi Xu <[email protected]> Date: Fri, 8 May 2026 11:48:54 +0800 Subject: [PATCH] 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. (cherry picked from commit 2751c7ed066d08d3c801670e6c5629a39ddfe90e) --- clang/lib/AST/StmtProfile.cpp | 21 +++++- clang/test/Modules/polluted-operator.cppm | 79 ----------------------- clang/test/SemaCXX/GH190333.cpp | 6 ++ 3 files changed, 26 insertions(+), 80 deletions(-) delete mode 100644 clang/test/Modules/polluted-operator.cppm create mode 100644 clang/test/SemaCXX/GH190333.cpp diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp index a626d043676e0..03b5563854f83 100644 --- a/clang/lib/AST/StmtProfile.cpp +++ b/clang/lib/AST/StmtProfile.cpp @@ -2369,7 +2369,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 different definitions in different modules; first difference 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 different 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'}} _______________________________________________ llvm-branch-commits mailing list [email protected] https://lists.llvm.org/cgi-bin/mailman/listinfo/llvm-branch-commits
