On 9/12/24 1:07 PM, Patrick Palka wrote:
(Sorry to resurrect this thread so late, I lost track of this patch...)
On Fri, 2 Dec 2022, Jason Merrill wrote:
On 12/2/22 09:30, Patrick Palka wrote:
On Thu, 1 Dec 2022, Jason Merrill wrote:
On 12/1/22 14:51, Patrick Palka wrote:
On Thu, 1 Dec 2022, Jason Merrill wrote:
On 12/1/22 11:37, Patrick Palka wrote:
When defining a explicit specialization of a constrained member
template
(of a class template) such as f and g in the below testcase, the
DECL_TEMPLATE_PARMS of the corresponding TEMPLATE_DECL are partially
instantiated, whereas its associated constraints are carried over
from the original template and thus are in terms of the original
DECL_TEMPLATE_PARMS.
But why are they carried over? We wrote a specification of the
constraints in
terms of the template parameters of the specialization, why are we
throwing
that away?
Using the partially instantiated constraints would require adding a
special case to satisfaction since during satisfaction we currently
always use the full set of template arguments (relative to the most
general template).
But not for partial specializations, right? It seems natural to handle
this
explicit instantiation the way we handle partial specializations, as both
have
their constraints written in terms of their template parameters.
True, but what about the general rule that we don't partially instantiate
constraints outside of declaration matching? Checking satisfaction of
partially instantiated constraints here can introduce hard errors during
normalization, e.g.
template<class T>
concept C1 = __same_as(T, void);
template<class T>
concept C2 = C1<typename T::type>;
template<int N>
concept D = (N == 42);
template<class T>
struct A {
template<int N>
static void f() requires C2<T> || D<N>;
};
template<>
template<int N>
void A<int>::f() requires C2<int> || D<N> { }
int main() {
A<int>::f<42>();
}
Normalization of the the partially instantiated constraints will give a
hard error due to 'int::type' being ill-formed, whereas the uninstantiated
constraints are fine.
Hmm, interesting point, but in this example that happens because the
specialization is nonsensical: we wouldn't be normalizing the
partially-instantiated constraints so much as the ones that the user
explicitly wrote, so a hard error seems justified.
While the written partially-instantiated constraints are nonsensical,
aren't they only needed for sake of declaration matching? It doesn't
seem to necessarily imply that that form of constraints is what should
prevail. This is where the analogy with partial specializations breaks
down IMHO: partial specializations own their constraints.
Hmm, I suppose you're right, we aren't overwriting the partially
instantiated decl, just matching against it. Your original patch is OK.
It would be nice to have predicate functions to distinguish between
partial specializations and member specializations so we don't have to
get into the lower-level details here.
Jason