return false;
}
- if (!isSameConstraintExpr(FuncX->getTrailingRequiresClause(),
- FuncY->getTrailingRequiresClause()))
+ // The trailing require clause of instantiated function may change during
+ // the semantic analysis. Trying to get the primary template function (if
+ // exists) to compare the primary trailing require clause.
+ auto TryToGetPrimaryTemplatedFunction =
+ [](const FunctionDecl *FD) -> const FunctionDecl * {
+ switch (FD->getTemplatedKind()) {
+ case FunctionDecl::TK_DependentNonTemplate:
+ return FD->getInstantiatedFromDecl();
+ case FunctionDecl::TK_FunctionTemplate:
+ return FD->getDescribedFunctionTemplate()->getTemplatedDecl();
+ case FunctionDecl::TK_MemberSpecialization:
+ return FD->getInstantiatedFromMemberFunction();
+ case FunctionDecl::TK_FunctionTemplateSpecialization:
+ return FD->getPrimaryTemplate()->getTemplatedDecl();
+ default:
+ return FD;
+ }
+ };
+ const FunctionDecl *PrimaryX = TryToGetPrimaryTemplatedFunction(FuncX);
+ const FunctionDecl *PrimaryY = TryToGetPrimaryTemplatedFunction(FuncY);
+ if (!isSameConstraintExpr(PrimaryX->getTrailingRequiresClause(),
+ PrimaryY->getTrailingRequiresClause()))
return false;
auto GetTypeAsWritten = [](const FunctionDecl *FD) {
--- /dev/null
+// https://github.com/llvm/llvm-project/issues/60890
+//
+// 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 -emit-module-interface %t/b.cppm -fprebuilt-module-path=%t -o %t/b.pcm
+// RUN: %clang_cc1 -std=c++20 -emit-module-interface %t/c.cppm -fprebuilt-module-path=%t -o %t/c.pcm
+// RUN: %clang_cc1 -std=c++20 %t/d.cpp -fprebuilt-module-path=%t -S -emit-llvm -o -
+
+//--- a.cppm
+export module a;
+
+export template<typename T>
+struct a {
+ friend void aa(a x) requires(true) {}
+ void aaa() requires(true) {}
+};
+
+export template struct a<double>;
+
+export template<typename T>
+void foo(T) requires(true) {}
+
+export template void foo<double>(double);
+
+export template <typename T>
+class A {
+ friend void foo<>(A);
+};
+
+//--- b.cppm
+export module b;
+
+import a;
+
+void b() {
+ a<int> _;
+ a<double> __;
+}
+
+//--- c.cppm
+export module c;
+
+import a;
+
+struct c {
+ void f() const {
+ a<int> _;
+ aa(_);
+ _.aaa();
+
+ a<double> __;
+ aa(__);
+ __.aaa();
+
+ foo<int>(5);
+ foo<double>(3.0);
+ foo(A<int>());
+ }
+};
+
+//--- d.cpp
+// expected-no-diagnostics
+import a;
+import b;
+import c;
+
+void d() {
+ a<int> _;
+ aa(_);
+ _.aaa();
+
+ a<double> __;
+ aa(__);
+ __.aaa();
+
+ foo<int>(5);
+ foo<double>(3.0);
+ foo(A<int>());
+}