https://gcc.gnu.org/bugzilla/show_bug.cgi?id=99686
--- Comment #7 from Steven Sun <StevenSun2021 at hotmail dot com> --- After digging for two days, I think I may know what's happening inside. Under std=c++20 and my code in comment 1, the flow when parsing a full function specialization would be 1. Found a full specialization of function. 2. Instantiate all possible primary function templates. 3. Find the most suitable instantiation (here, the concept constrained is chosen) 4. Then replace it with full specialization. (this is done in `reregister_specialization` in `gcc/cp/pt.c`) So when performing overloading in the main function, there would be one instantiation and one full specialization to choose. (To be specific, those two are in the hash table `decl_specialization` defined in `gcc/cp/pt.c`) While in the c++17 mode, step 4 is broken. So there will be 2 implicit instantiation to choose when overloading. Step 4 is performed in the function `duplicate_decls` defined in `gcc/cp/decl.c`. Certain conditions must be satisfied to replace the instantiation. The one failed here is: "the compiler thinks the full specialization has a different concepts constraint with primary template (because the primary template has contraints but the full specialization doesn't)" So the reregistration is never triggered. This is the source of the bug. After getting the whole picture, I simplify the test case as https://godbolt.org/z/9MM6rEf77 ----------------------- std=c++17 -fconcepts template <typename T> requires requires(T t) { ++t; } void func(T &&arg) { } template <> void func(int&& arg) { } int main() { func(1); } ----------------------- I'll give more details in the next comment in case any developer would like to fix it.