Close https://github.com/llvm/llvm-project/issues/60890.
For the following example:
export module a; export template<typename T> struct a { friend void aa(a) requires(true) { } };
export module b; import a; struct b { a<int> m; };
export module c; import a; struct c { void f() const { aa(a<int>()); } };
import a; import b; import c; void d() { aa(a<int>()); }
The current clang will reject this incorrectly. The reason is that the require clause will be replaced with the evaluated version (https://github.com/llvm/llvm-project/blob/efae3174f09560353fb0f3d528bcbffe060d5438/clang/lib/Sema/SemaConcept.cpp#L664-L665). In module 'b', the friend function is instantiated but not used so the require clause of the friend function is (true). However, in module 'c', the friend function is used so the require clause is true. So deserializer classify these two function to two different functions instead of one. Then here is the bug report.
The proposed solution is to try to compare the trailing require clause of the primary template when performing ODR checking.
If this is necessary here, I'd expect it to be necessary in a lot of other places too. (For example, we perform basically the same comparison when doing redeclaration checking.) Which declarations have the wrong requires-clause attached to them? Why would the requires-clause be modified from the one written in the original declaration?
(I could imagine this happening for explicit instantiations, where the requires clause might not be specified at all, but we could address that by looking at the canonical declaration for a trailing requires-clause, rather than looking at the template pattern.)