Message ID | 54FF12D4.3060603@oracle.com |
---|---|
State | New |
Headers | show |
On 03/10/2015 11:50 AM, Paolo Carlini wrote: > + /* Don't get fooled by, eg: > + > + template <typename> class C > + { > + template <typename U> > + C(const C<U>&, bool = false); > + }; > + > + template <> > + template <typename U> > + C<int>::C(const C<U>&, bool); */ > + > + if (DECL_FUNCTION_MEMBER_P (decl) > + && CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P (DECL_CONTEXT (decl))) > + return; Wouldn't this also allow template<> template<typename U> C<int>::C(const C<U>&, bool = false); ? Would it work to avoid calling this function if the DECL_SOURCE_LOCATION of the new decl matches the location of the old decl? Jason
Hi, On 03/10/2015 05:19 PM, Jason Merrill wrote: > On 03/10/2015 11:50 AM, Paolo Carlini wrote: >> + /* Don't get fooled by, eg: >> + >> + template <typename> class C >> + { >> + template <typename U> >> + C(const C<U>&, bool = false); >> + }; >> + >> + template <> >> + template <typename U> >> + C<int>::C(const C<U>&, bool); */ >> + >> + if (DECL_FUNCTION_MEMBER_P (decl) >> + && CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P >> (DECL_CONTEXT (decl))) >> + return; > > Wouldn't this also allow > > template<> > template<typename U> > C<int>::C(const C<U>&, bool = false); > > ? Good question, but we don't have this issue, because for that we emit anyway: 65370.C:11:36: error: default argument specified in explicit specialization [-fpermissive] C<int>::C(const C<U>&, bool = false); nothing changes about that kind of testcase, usual behavior. Thanks, Paolo.
On 03/10/2015 01:03 PM, Paolo Carlini wrote: > Good question, but we don't have this issue, because for that we emit > anyway: > > 65370.C:11:36: error: default argument specified in explicit > specialization [-fpermissive] > C<int>::C(const C<U>&, bool = false); > > nothing changes about that kind of testcase, usual behavior. Ah. So here we can ignore any template instantiation or specialization, with a comment that check_explicit_specialization will handle them. But I suspect that checking the decl itself will be better; I would expect checking the context to lead you to accept template<> class C<int> { template <typename U> C(const C<U>&, bool); }; template <typename U> C<int>::C(const C<U>&, bool = false); Since here C<int> is a specialization of C, but the constructor is not itself a partial instantiation. Jason
Index: cp/decl.c =================================================================== --- cp/decl.c (revision 221317) +++ cp/decl.c (working copy) @@ -1271,6 +1271,22 @@ check_redeclaration_no_default_args (tree decl) { gcc_assert (DECL_DECLARES_FUNCTION_P (decl)); + /* Don't get fooled by, eg: + + template <typename> class C + { + template <typename U> + C(const C<U>&, bool = false); + }; + + template <> + template <typename U> + C<int>::C(const C<U>&, bool); */ + + if (DECL_FUNCTION_MEMBER_P (decl) + && CLASSTYPE_SPECIALIZATION_OF_PRIMARY_TEMPLATE_P (DECL_CONTEXT (decl))) + return; + for (tree t = FUNCTION_FIRST_USER_PARMTYPE (decl); t && t != void_list_node; t = TREE_CHAIN (t)) if (TREE_PURPOSE (t)) Index: testsuite/g++.dg/other/default11.C =================================================================== --- testsuite/g++.dg/other/default11.C (revision 0) +++ testsuite/g++.dg/other/default11.C (working copy) @@ -0,0 +1,11 @@ +// PR c++/65370 + +template <typename> class C +{ + template <typename U> + C(const C<U>&, bool = false); +}; + +template <> +template <typename U> +C<int>::C(const C<U>&, bool);