Skip to content

[clang] [C++20] [Modules] Don't profile UnresolvedLookupExpr in require clause and noexcept clause#194283

Closed
ChuanqiXu9 wants to merge 2 commits into
llvm:mainfrom
ChuanqiXu9:NoProfilingUnresolvedLookupExpr
Closed

[clang] [C++20] [Modules] Don't profile UnresolvedLookupExpr in require clause and noexcept clause#194283
ChuanqiXu9 wants to merge 2 commits into
llvm:mainfrom
ChuanqiXu9:NoProfilingUnresolvedLookupExpr

Conversation

@ChuanqiXu9

@ChuanqiXu9 ChuanqiXu9 commented Apr 27, 2026

Copy link
Copy Markdown
Member

Close #190333

See clang/test/Modules/callable-require-clause-merge.cppm and clang/test/Modules/polluted-operator.cppm for motivating case.

In short, the unrelated global operator may pollute the operator in require clause and noexcept clause, which makes clang emits hard to understand false-positive diagnostic message to end users.

This patch tries to avoid such problems for require clause and noexcept clause specifically.

This may not be perfect. I feel we may face other similar problems in other clause due to the design of UnresolvedLookupExpr. But on the one hand, it is better to fix it fundamentally after we saw more cases so that we can have a better understanding, on the other hand, it is better to stop blooding right now as the approach here is simple enough.

@ChuanqiXu9 ChuanqiXu9 self-assigned this Apr 27, 2026
@ChuanqiXu9 ChuanqiXu9 added clang Clang issues not falling into any other category clang:modules C++20 modules and Clang Header Modules labels Apr 27, 2026
@llvmbot llvmbot added the clang:frontend Language frontend issues, e.g. anything involving "Sema" label Apr 27, 2026
@llvmbot

llvmbot commented Apr 27, 2026

Copy link
Copy Markdown
Member

@llvm/pr-subscribers-clang-modules

@llvm/pr-subscribers-clang

Author: Chuanqi Xu (ChuanqiXu9)

Changes

Close #190333

See clang/test/Modules/callable-require-clause-merge.cppm and clang/test/Modules/polluted-operator.cppm for motivating case.

In short, the unrelated global operator may pollute the operator in require clause and noexcept clause, which makes clang emits hard to understand false-positive diagnostic message to end users.

This patch tries to avoid such problems for require clause and noexcept clause specifically.

This may not be perfect. I feel we may face other similar problems in other clause due to the design of UnresolvedLookupExpr. But on the one hand, it is better to fix it fundamentally after we saw more cases so that we can have a better understanding, on the other hand, it is better to stop blooding right now as the approach here is easy and not bad.


Full diff: https://github.com/llvm/llvm-project/pull/194283.diff

6 Files Affected:

  • (modified) clang/include/clang/AST/Stmt.h (+26-1)
  • (modified) clang/lib/AST/ASTContext.cpp (+6-2)
  • (modified) clang/lib/AST/StmtProfile.cpp (+21-7)
  • (modified) clang/lib/AST/Type.cpp (+9-1)
  • (added) clang/test/Modules/callable-require-clause-merge.cppm (+43)
  • (modified) clang/test/Modules/polluted-operator.cppm (-5)
diff --git a/clang/include/clang/AST/Stmt.h b/clang/include/clang/AST/Stmt.h
index d940aa6562c4c..5461e91ba0aa1 100644
--- a/clang/include/clang/AST/Stmt.h
+++ b/clang/include/clang/AST/Stmt.h
@@ -1617,8 +1617,33 @@ class alignas(void *) Stmt {
   /// other lambda expressions. When true, the lambda expressions with the same
   /// implementation will be considered to be the same. ProfileLambdaExpr should
   /// only be true when we try to merge two declarations within modules.
+  /// \param IgnoringUnresolvedLookupExpr whether or not to ignore
+  /// UnresolvedLookupExpr when profiling. When true,
+  /// IgnoringUnresolvedLookupExpr won't be invoked during profiling. This is
+  /// useful in case we don't hope the unresolved lookup expr to pollute the
+  /// profile result. e.g.,
+  ///
+  /// "a.h"
+  ///
+  ///   #pragma once
+  ///   struct F {
+  ///     template <typename... T> requires ((sizeof(T) > 0) && ...)
+  ///     void operator()(T...) {}
+  ///   } f;
+  ///
+  /// and
+  ///
+  /// "c.h"
+  ///
+  ///   void operator&&(struct X, struct X);
+  ///   #include "a.h"
+  ///
+  /// Here the `F::operator()` may produce different profiling results depending
+  /// on whether there is a freestanding `operator&&` declared before it. And
+  /// this affects declaration merging in modules.
   void Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
-               bool Canonical, bool ProfileLambdaExpr = false) const;
+               bool Canonical, bool ProfileLambdaExpr = false,
+               bool IgnoringUnresolvedLookupExpr = false) const;
 
   /// Calculate a unique representation for a statement that is
   /// stable across compiler invocations.
diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp
index abf5f8a832043..d2298bd1b30e7 100644
--- a/clang/lib/AST/ASTContext.cpp
+++ b/clang/lib/AST/ASTContext.cpp
@@ -7454,8 +7454,12 @@ bool ASTContext::isSameConstraintExpr(const Expr *XCE, const Expr *YCE) const {
     return true;
 
   llvm::FoldingSetNodeID XCEID, YCEID;
-  XCE->Profile(XCEID, *this, /*Canonical=*/true, /*ProfileLambdaExpr=*/true);
-  YCE->Profile(YCEID, *this, /*Canonical=*/true, /*ProfileLambdaExpr=*/true);
+  /// The unresolved lookup expr may misguide the profiling results. See
+  /// clang/test/Modules/callable-require-clause-merge.cppm for an example.
+  XCE->Profile(XCEID, *this, /*Canonical=*/true, /*ProfileLambdaExpr=*/true,
+               /*IgnoringUnresolvedLookupExpr=*/true);
+  YCE->Profile(YCEID, *this, /*Canonical=*/true, /*ProfileLambdaExpr=*/true,
+               /*IgnoringUnresolvedLookupExpr=*/true);
   return XCEID == YCEID;
 }
 
diff --git a/clang/lib/AST/StmtProfile.cpp b/clang/lib/AST/StmtProfile.cpp
index 8219e57644be6..a9c81f0aa027a 100644
--- a/clang/lib/AST/StmtProfile.cpp
+++ b/clang/lib/AST/StmtProfile.cpp
@@ -30,11 +30,13 @@ namespace {
     llvm::FoldingSetNodeID &ID;
     bool Canonical;
     bool ProfileLambdaExpr;
+    bool IgnoringUnresolvedLookupExpr;
 
   public:
     StmtProfiler(llvm::FoldingSetNodeID &ID, bool Canonical,
-                 bool ProfileLambdaExpr)
-        : ID(ID), Canonical(Canonical), ProfileLambdaExpr(ProfileLambdaExpr) {}
+                 bool ProfileLambdaExpr, bool IgnoringUnresolvedLookupExpr)
+        : ID(ID), Canonical(Canonical), ProfileLambdaExpr(ProfileLambdaExpr),
+          IgnoringUnresolvedLookupExpr(IgnoringUnresolvedLookupExpr) {}
 
     virtual ~StmtProfiler() {}
 
@@ -86,8 +88,11 @@ namespace {
   public:
     StmtProfilerWithPointers(llvm::FoldingSetNodeID &ID,
                              const ASTContext &Context, bool Canonical,
-                             bool ProfileLambdaExpr)
-        : StmtProfiler(ID, Canonical, ProfileLambdaExpr), Context(Context) {}
+                             bool ProfileLambdaExpr,
+                             bool IgnoringUnresolvedLookupExpr)
+        : StmtProfiler(ID, Canonical, ProfileLambdaExpr,
+                       IgnoringUnresolvedLookupExpr),
+          Context(Context) {}
 
   private:
     void HandleStmtClass(Stmt::StmtClass SC) override {
@@ -184,8 +189,11 @@ namespace {
   class StmtProfilerWithoutPointers : public StmtProfiler {
     ODRHash &Hash;
   public:
+    // Set IgnoringUnresolvedLookupExpr as we don't want the unresolved lookup
+    // expr affecting the merging results.
     StmtProfilerWithoutPointers(llvm::FoldingSetNodeID &ID, ODRHash &Hash)
-        : StmtProfiler(ID, /*Canonical=*/false, /*ProfileLambdaExpr=*/false),
+        : StmtProfiler(ID, /*Canonical=*/false, /*ProfileLambdaExpr=*/false,
+                       /*IgnoringUnresolvedLookupExpr=*/true),
           Hash(Hash) {}
 
   private:
@@ -2269,6 +2277,10 @@ void StmtProfiler::VisitOverloadExpr(const OverloadExpr *S) {
 
 void
 StmtProfiler::VisitUnresolvedLookupExpr(const UnresolvedLookupExpr *S) {
+  if (IgnoringUnresolvedLookupExpr) {
+    ID.AddInteger(0);
+    return;
+  }
   VisitOverloadExpr(S);
 }
 
@@ -2951,8 +2963,10 @@ void StmtProfiler::VisitHLSLOutArgExpr(const HLSLOutArgExpr *S) {
 }
 
 void Stmt::Profile(llvm::FoldingSetNodeID &ID, const ASTContext &Context,
-                   bool Canonical, bool ProfileLambdaExpr) const {
-  StmtProfilerWithPointers Profiler(ID, Context, Canonical, ProfileLambdaExpr);
+                   bool Canonical, bool ProfileLambdaExpr,
+                   bool IgnoringUnresolvedLookupExpr) const {
+  StmtProfilerWithPointers Profiler(ID, Context, Canonical, ProfileLambdaExpr,
+                                    IgnoringUnresolvedLookupExpr);
   Profiler.Visit(this);
 }
 
diff --git a/clang/lib/AST/Type.cpp b/clang/lib/AST/Type.cpp
index 6c295c1a9c409..87ab7cd3ad185 100644
--- a/clang/lib/AST/Type.cpp
+++ b/clang/lib/AST/Type.cpp
@@ -4035,7 +4035,15 @@ void FunctionProtoType::Profile(llvm::FoldingSetNodeID &ID, QualType Result,
     for (QualType Ex : epi.ExceptionSpec.Exceptions)
       ID.AddPointer(Ex.getAsOpaquePtr());
   } else if (isComputedNoexcept(epi.ExceptionSpec.Type)) {
-    epi.ExceptionSpec.NoexceptExpr->Profile(ID, Context, Canonical);
+    // Make sure the profiling result of the noexcept expression
+    // won't be affected by the unresolved lookup expressions.
+    // See clang/test/Modules/polluted-operator.cppm for an example
+    // for it.
+    //
+    // ProfileLambdaExpr=false is the default value.
+    epi.ExceptionSpec.NoexceptExpr->Profile(
+        ID, Context, Canonical, /*ProfileLambdaExpr=*/false,
+        /*IgnoringUnresolvedLookupExpr=*/true);
   } else if (epi.ExceptionSpec.Type == EST_Uninstantiated ||
              epi.ExceptionSpec.Type == EST_Unevaluated) {
     ID.AddPointer(epi.ExceptionSpec.SourceDecl->getCanonicalDecl());
diff --git a/clang/test/Modules/callable-require-clause-merge.cppm b/clang/test/Modules/callable-require-clause-merge.cppm
new file mode 100644
index 0000000000000..6cdb369639a39
--- /dev/null
+++ b/clang/test/Modules/callable-require-clause-merge.cppm
@@ -0,0 +1,43 @@
+// RUN: rm -rf %t
+// RUN: mkdir -p %t
+// RUN: split-file %s %t
+//
+// RUN: %clang_cc1 -std=c++20 %t/mymod.cppm -emit-module-interface -o %t/mymod.pcm
+// RUN: %clang_cc1 -std=c++20 %t/consumer.cpp -fprebuilt-module-path=%t -fsyntax-only -verify
+//
+// RUN: %clang_cc1 -std=c++20 %t/mymod.cppm -emit-reduced-module-interface -o %t/mymod.pcm
+// RUN: %clang_cc1 -std=c++20 %t/consumer.cpp -fprebuilt-module-path=%t -fsyntax-only -verify
+
+// RUN: %clang_cc1 -std=c++20 -fskip-odr-check-in-gmf %t/mymod.cppm -emit-module-interface -o %t/mymod.pcm
+// RUN: %clang_cc1 -std=c++20 -fskip-odr-check-in-gmf %t/consumer.cpp -fprebuilt-module-path=%t -fsyntax-only -verify
+//
+// RUN: %clang_cc1 -std=c++20 -fskip-odr-check-in-gmf %t/mymod.cppm -emit-reduced-module-interface -o %t/mymod.pcm
+// RUN: %clang_cc1 -std=c++20 -fskip-odr-check-in-gmf %t/consumer.cpp -fprebuilt-module-path=%t -fsyntax-only -verify
+
+//--- r.h
+struct F {
+  template <typename... T> requires ((sizeof(T) > 0) && ...)
+  void operator()(T...) {}
+} f;
+
+struct G {
+  template <typename T, typename U>
+    requires requires(T t, U u) { t + u; }
+  void operator()(T, U) {}
+} g;
+
+//--- mymod.cppm
+module;
+#include "r.h"
+export module mymod;
+export using ::f;
+export using ::g;
+
+//--- consumer.cpp
+// expected-no-diagnostics
+void operator&&(struct X, struct X);
+void operator+(struct X, struct Y);
+#include "r.h"
+import mymod;
+
+void h() { f(); g(1, 2); }
diff --git a/clang/test/Modules/polluted-operator.cppm b/clang/test/Modules/polluted-operator.cppm
index 45cc5e37d6a64..e6f0cdf092414 100644
--- a/clang/test/Modules/polluted-operator.cppm
+++ b/clang/test/Modules/polluted-operator.cppm
@@ -71,9 +71,4 @@ export namespace std {
   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

@mizvekov mizvekov left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This problem has a mirror in that the same difficulties are encountered when profiling CXXOperatorCallExpr, and the same solution we have implemented for that applies here.

Comment thread clang/lib/AST/Type.cpp Outdated
Comment on lines +4044 to +4046
epi.ExceptionSpec.NoexceptExpr->Profile(
ID, Context, Canonical, /*ProfileLambdaExpr=*/false,
/*IgnoringUnresolvedLookupExpr=*/true);

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

This will make us ignore a bunch of differences in noexcept signatures, even when modules are not concerned at all.

Copy link
Copy Markdown
Member Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Adding some path to only ignore it when we're merging entities.

…re clause and noexcept clause

Close llvm#190333

See clang/test/Modules/callable-require-clause-merge.cppm and
clang/test/Modules/polluted-operator.cppm for motivating case.

In short, the unrelated global operator may pollute the operator in
require clause and noexcept clause, which makes clang emits hard to
understand false-positive diagnostic message to end users.

This patch tries to avoid such problems for require clause and noexcept
clause specifically.

This may not be perfect. I feel we may face other similar problems
in other clause due to the design of UnresolvedLookupExpr. But on the
one hand, it is better to fix it fundamentally after we saw more cases
so that we can have a better understanding and have more insights,
on the other hand, it is better to stop blooding right now as the
approach here is easy and not bad.
@ChuanqiXu9
ChuanqiXu9 force-pushed the NoProfilingUnresolvedLookupExpr branch from 6997a12 to 744b424 Compare April 28, 2026 03:17
@ChuanqiXu9

ChuanqiXu9 commented Apr 28, 2026

Copy link
Copy Markdown
Member Author

This problem has a mirror in that the same difficulties are encountered when profiling CXXOperatorCallExpr, and the same solution we have implemented for that applies here.

Could you elaborate? I can only guess right now.

If you're saying we should extract the operator kind for UnresolvedLookupExpr? If yes, I feel it may not work. As the expression is nullptr in another context. See https://godbolt.org/z/rc5br469M for an example.

If you're saying we should perform more trick in CXXFoldExpr? I feel we've already done that in #190732 . But with CXXOperatorCallExpr, we have https://godbolt.org/z/rc5br469M , I mean it doesn't working right now. Do you think we need to improve in VisitCXXOperatorCallExpr?

@mizvekov

Copy link
Copy Markdown
Contributor

This problem has a mirror in that the same difficulties are encountered when profiling CXXOperatorCallExpr, and the same solution we have implemented for that applies here.

Could you elaborate? I can only guess right now.

If you're saying we should extract the operator kind for UnresolvedLookupExpr? If yes, I feel it may not work. As the expression is nullptr in another context. See https://godbolt.org/z/rc5br469M for an example.

The StmtProfiler needs to profile the expression syntactically, ignoring implicit differences purely caused by semantic analysis.

So for exemple, VisitCXXOperatorCallExpr deals with that same problem as the issue this is trying to solve, because Sema can produce a CXXOperatorCallExpr expression when an overloaded operator is available, and another kind when it's not.

So we profile both cases the same as if the overloaded operator was not there, by pretending that instead of having a CXXOperatorCallExpr, we had an expression which used the underlying syntactic operator instead (ie UnaryOperator, BinaryOperator, etc).

@ChuanqiXu9

Copy link
Copy Markdown
Member Author

This problem has a mirror in that the same difficulties are encountered when profiling CXXOperatorCallExpr, and the same solution we have implemented for that applies here.

Could you elaborate? I can only guess right now.
If you're saying we should extract the operator kind for UnresolvedLookupExpr? If yes, I feel it may not work. As the expression is nullptr in another context. See https://godbolt.org/z/rc5br469M for an example.

The StmtProfiler needs to profile the expression syntactically, ignoring implicit differences purely caused by semantic analysis.

So for exemple, VisitCXXOperatorCallExpr deals with that same problem as the issue this is trying to solve, because Sema can produce a CXXOperatorCallExpr expression when an overloaded operator is available, and another kind when it's not.

So we profile both cases the same as if the overloaded operator was not there, by pretending that instead of having a CXXOperatorCallExpr, we had an expression which used the underlying syntactic operator instead (ie UnaryOperator, BinaryOperator, etc).

I guess I got your point. What you want may look like

void VisitCXXFoldExpr(const CXXFoldExpr *S) {
      if (UnresolvedLookupExpr *ULE = S->getCallee()) {
              Expr *Underlying = ULE->getUnderlyingOperator(); // fake API
              Visit(Underlying);
      } else
         ID.AddInteger(0);
      ...
}

Right?

If yes, it can't solve the problem. As it will still produce different results for the fold expression which have no operator&& in the context.

I think if we want to solve the problems, we have to profiling UnresolvedLookupExpr as nullptr in these cases.

@ChuanqiXu9

Copy link
Copy Markdown
Member Author

FWIW, CXXFoldExpr already have profiled the underlying operator:

ID.AddInteger(S->getOperator());
}

So it looks like, my previous PR is already what you want?

@mizvekov

Copy link
Copy Markdown
Contributor

It's not about profiling the underlying operator, it's about profiling an expression kind as if it were a different kind.

So you have to perform a notional rewrite of an expression that involves an operator into the equivalent expression that would have been produced if you had not.

@ChuanqiXu9

Copy link
Copy Markdown
Member Author

It's not about profiling the underlying operator, it's about profiling an expression kind as if it were a different kind.

So you have to perform a notional rewrite of an expression that involves an operator into the equivalent expression that would have been produced if you had not.

I am not sure if I understood. I feel like what you're saying is the same thing as I had in 4c2e49d

could you elaborate?

@mizvekov

Copy link
Copy Markdown
Contributor

I am not sure if I understood. I feel like what you're saying is the same thing as I had in 4c2e49d

could you elaborate?

I think its close to what that commit proposes to do, but there are some problems.

For example, it skips a VisitStmtNoChildren call to the FoldExpr, which could introduce ambiguities.

It would have helped to explain in a comment that it intentionally doesn't profile the callee sub-expression, and that's basically the difference between what existed before.

@ChuanqiXu9

Copy link
Copy Markdown
Member Author

I am not sure if I understood. I feel like what you're saying is the same thing as I had in 4c2e49d
could you elaborate?

I think its close to what that commit proposes to do, but there are some problems.

For example, it skips a VisitStmtNoChildren call to the FoldExpr, which could introduce ambiguities.

It would have helped to explain in a comment that it intentionally doesn't profile the callee sub-expression, and that's basically the difference between what existed before.

Thanks. Sent #195983

ChuanqiXu9 added a commit to ChuanqiXu9/llvm-project that referenced this pull request May 6, 2026
…lvm#190732)

Close llvm#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 llvm#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.
ChuanqiXu9 added a commit that referenced this pull request May 8, 2026
…190732) (#195983)

Close #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 #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.
llvm-sync Bot pushed a commit to arm/arm-toolchain that referenced this pull request May 8, 2026
…FoldExpr (#190732) (#195983)

Close llvm/llvm-project#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 llvm/llvm-project#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.
cpullvm-upstream-sync Bot pushed a commit to navaneethshan/cpullvm-toolchain-1 that referenced this pull request May 8, 2026
…FoldExpr (#190732) (#195983)

Close llvm/llvm-project#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 llvm/llvm-project#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.
llvm-upstreamsync Bot pushed a commit to qualcomm/cpullvm-toolchain that referenced this pull request May 8, 2026
…FoldExpr (#190732) (#195983)

Close llvm/llvm-project#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 llvm/llvm-project#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.
@mizvekov

Copy link
Copy Markdown
Contributor

Closing as superseded by #195983

@mizvekov mizvekov closed this May 11, 2026
moar55 pushed a commit to moar55/llvm-project that referenced this pull request May 12, 2026
…lvm#190732) (llvm#195983)

Close llvm#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 llvm#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.
EuphoricThinking pushed a commit to EuphoricThinking/llvm-project that referenced this pull request May 14, 2026
…lvm#190732) (llvm#195983)

Close llvm#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 llvm#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.
pedroMVicente pushed a commit to pedroMVicente/llvm-project that referenced this pull request May 19, 2026
…lvm#190732) (llvm#195983)

Close llvm#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 llvm#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.
c-rhodes pushed a commit to llvmbot/llvm-project that referenced this pull request May 26, 2026
…lvm#190732) (llvm#195983)

Close llvm#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 llvm#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 2751c7e)
llvm-sync Bot pushed a commit to arm/arm-toolchain that referenced this pull request May 26, 2026
…FoldExpr (#190732) (#195983)

Close llvm/llvm-project#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 llvm/llvm-project#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 2751c7e)
daunabomba pushed a commit to daunabomba/llvm-project that referenced this pull request Jun 2, 2026
…lvm#190732) (llvm#195983)

Close llvm#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 llvm#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 2751c7e)
plfj pushed a commit to zrsx/llvm-project that referenced this pull request Jun 5, 2026
…190732) (#195983)

Close llvm/llvm-project#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 llvm/llvm-project#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)
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

clang:frontend Language frontend issues, e.g. anything involving "Sema" clang:modules C++20 modules and Clang Header Modules clang Clang issues not falling into any other category

Projects

None yet

Development

Successfully merging this pull request may close these issues.

[clang][modules] ambiguity when an inline variable is visible both through a header and through a module

3 participants