diff --git a/clang/lib/AST/ASTContext.cpp b/clang/lib/AST/ASTContext.cpp --- a/clang/lib/AST/ASTContext.cpp +++ b/clang/lib/AST/ASTContext.cpp @@ -6683,8 +6683,28 @@ 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) { diff --git a/clang/test/Modules/pr60890.cppm b/clang/test/Modules/pr60890.cppm new file mode 100644 --- /dev/null +++ b/clang/test/Modules/pr60890.cppm @@ -0,0 +1,82 @@ +// 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 +struct a { + friend void aa(a x) requires(true) {} + void aaa() requires(true) {} +}; + +export template struct a; + +export template +void foo(T) requires(true) {} + +export template void foo(double); + +export template +class A { + friend void foo<>(A); +}; + +//--- b.cppm +export module b; + +import a; + +void b() { + a _; + a __; +} + +//--- c.cppm +export module c; + +import a; + +struct c { + void f() const { + a _; + aa(_); + _.aaa(); + + a __; + aa(__); + __.aaa(); + + foo(5); + foo(3.0); + foo(A()); + } +}; + +//--- d.cpp +// expected-no-diagnostics +import a; +import b; +import c; + +void d() { + a _; + aa(_); + _.aaa(); + + a __; + aa(__); + __.aaa(); + + foo(5); + foo(3.0); + foo(A()); +}