>>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. */