>>template <class T> >>struct A >>{ >> void f(T); >>}; >> >>template <class T> >>void A<T>::f(const T) >>{ } >> >>which is certainly questionable code, but is currently also accepted by >>clang and EDG compilers.
I just found out that clang actually correctly reject this code during specialization. (https://www.godbolt.org/z/evjvhqqoo) It all depends on explicit argument which may turn "const" into top-level-cv-qualifier or not. For example, when argument is "int[3]", the function signature of specialization will have to keep the const because it is no longer top-level cv qualifier. template<> void A<int[3]>::f(const int*){} // not matching declaration "void(int*)" Obviously when explicit argument is "int", the const would be dropped and specialization matches declaration. i.e. template<> void A<int>::f(int){} // this matches declaration "void(int)" So, clang is correct to NOT reject template definition when there is no specialization yet. As a comparison, GCC is not able to reject incorrect specialization. Should we file this bug? Or just add this as test case to original 1001 core issue? Again, my patch cannot deal this case as it is not "typename". We may have to fix "tsubst_function_decl" to see any workaround of line "SET_DECL_IMPLICIT_INSTANTIATION (r);" (See my previous email https://gcc.gnu.org/pipermail/gcc-patches/2021-September/580260.html) This macro "DECL_USE_TEMPLATE" is set to 1. However, the comment says "1" is for "implicit specialization", but we are actually dealing with "partial or explicit specialization" which is "2". Here I quote comment from cp-tree.h /* Nonzero iff NODE is a specialization of a template. The value indicates the type of specializations: 1=implicit instantiation 2=partial or explicit specialization, e.g.: template <> int min<int> (int, int), 3=explicit instantiation, e.g.: template int min<int> (int, int); Note that NODE will be marked as a specialization even if the template it is instantiating is not a primary template. For example, given: template <typename T> struct O { void f(); struct I {}; }; both O<int>::f and O<int>::I will be marked as instantiations. If DECL_USE_TEMPLATE is nonzero, then DECL_TEMPLATE_INFO will also be non-NULL. */