PR c++/71747 - ICE with self-referential partial spec

* pt.c (get_partial_spec_bindings): Replace tparms and spec_args
	parameters with spec_tmpl.  Call push_tinst_level.
	(most_specialized_partial_spec): Adjust.
	(more_specialized_partial_spec): Adjust.

From-SVN: r238785
This commit is contained in:
Jason Merrill 2016-07-27 10:31:30 -04:00 committed by Jason Merrill
parent 8de22ea0b1
commit 270430ff3e
4 changed files with 61 additions and 44 deletions

View File

@ -1,3 +1,11 @@
2016-07-27 Jason Merrill <jason@redhat.com>
PR c++/71747
* pt.c (get_partial_spec_bindings): Replace tparms and spec_args
parameters with spec_tmpl. Call push_tinst_level.
(most_specialized_partial_spec): Adjust.
(more_specialized_partial_spec): Adjust.
2016-07-25 Jason Merrill <jason@redhat.com> 2016-07-25 Jason Merrill <jason@redhat.com>
PR c++/65970 PR c++/65970

View File

@ -140,7 +140,7 @@ static int unify (tree, tree, tree, tree, int, bool);
static void add_pending_template (tree); static void add_pending_template (tree);
static tree reopen_tinst_level (struct tinst_level *); static tree reopen_tinst_level (struct tinst_level *);
static tree tsubst_initializer_list (tree, tree); static tree tsubst_initializer_list (tree, tree);
static tree get_partial_spec_bindings (tree, tree, tree, tree); static tree get_partial_spec_bindings (tree, tree, tree);
static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t, static tree coerce_template_parms (tree, tree, tree, tsubst_flags_t,
bool, bool); bool, bool);
static tree coerce_innermost_template_parms (tree, tree, tree, tsubst_flags_t, static tree coerce_innermost_template_parms (tree, tree, tree, tsubst_flags_t,
@ -20689,8 +20689,6 @@ more_specialized_partial_spec (tree tmpl, tree pat1, tree pat2)
tree tmpl1 = TREE_VALUE (pat1); tree tmpl1 = TREE_VALUE (pat1);
tree tmpl2 = TREE_VALUE (pat2); tree tmpl2 = TREE_VALUE (pat2);
tree parms1 = DECL_INNERMOST_TEMPLATE_PARMS (tmpl1);
tree parms2 = DECL_INNERMOST_TEMPLATE_PARMS (tmpl2);
tree specargs1 = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (tmpl1))); tree specargs1 = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (tmpl1)));
tree specargs2 = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (tmpl2))); tree specargs2 = TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (tmpl2)));
@ -20699,14 +20697,14 @@ more_specialized_partial_spec (tree tmpl, tree pat1, tree pat2)
types in the arguments, and we need our dependency check functions types in the arguments, and we need our dependency check functions
to behave correctly. */ to behave correctly. */
++processing_template_decl; ++processing_template_decl;
targs = get_partial_spec_bindings (tmpl, parms1, specargs1, specargs2); targs = get_partial_spec_bindings (tmpl, tmpl1, specargs2);
if (targs) if (targs)
{ {
--winner; --winner;
any_deductions = true; any_deductions = true;
} }
targs = get_partial_spec_bindings (tmpl, parms2, specargs2, specargs1); targs = get_partial_spec_bindings (tmpl, tmpl2, specargs1);
if (targs) if (targs)
{ {
++winner; ++winner;
@ -20790,23 +20788,23 @@ get_bindings (tree fn, tree decl, tree explicit_args, bool check_rettype)
} }
/* Return the innermost template arguments that, when applied to a partial /* Return the innermost template arguments that, when applied to a partial
specialization of TMPL whose innermost template parameters are specialization SPEC_TMPL of TMPL, yield the ARGS.
TPARMS, and whose specialization arguments are SPEC_ARGS, yield the
ARGS.
For example, suppose we have: For example, suppose we have:
template <class T, class U> struct S {}; template <class T, class U> struct S {};
template <class T> struct S<T*, int> {}; template <class T> struct S<T*, int> {};
Then, suppose we want to get `S<double*, int>'. The TPARMS will be Then, suppose we want to get `S<double*, int>'. SPEC_TMPL will be the
{T}, the SPEC_ARGS will be {T*, int} and the ARGS will be {double*, partial specialization and the ARGS will be {double*, int}. The resulting
int}. The resulting vector will be {double}, indicating that `T' vector will be {double}, indicating that `T' is bound to `double'. */
is bound to `double'. */
static tree static tree
get_partial_spec_bindings (tree tmpl, tree tparms, tree spec_args, tree args) get_partial_spec_bindings (tree tmpl, tree spec_tmpl, tree args)
{ {
tree tparms = DECL_INNERMOST_TEMPLATE_PARMS (spec_tmpl);
tree spec_args
= TI_ARGS (get_template_info (DECL_TEMPLATE_RESULT (spec_tmpl)));
int i, ntparms = TREE_VEC_LENGTH (tparms); int i, ntparms = TREE_VEC_LENGTH (tparms);
tree deduced_args; tree deduced_args;
tree innermost_deduced_args; tree innermost_deduced_args;
@ -20832,6 +20830,13 @@ get_partial_spec_bindings (tree tmpl, tree tparms, tree spec_args, tree args)
if (! TREE_VEC_ELT (innermost_deduced_args, i)) if (! TREE_VEC_ELT (innermost_deduced_args, i))
return NULL_TREE; return NULL_TREE;
tree tinst = build_tree_list (spec_tmpl, deduced_args);
if (!push_tinst_level (tinst))
{
excessive_deduction_depth = true;
return NULL_TREE;
}
/* Verify that nondeduced template arguments agree with the type /* Verify that nondeduced template arguments agree with the type
obtained from argument deduction. obtained from argument deduction.
@ -20848,6 +20853,9 @@ get_partial_spec_bindings (tree tmpl, tree tparms, tree spec_args, tree args)
spec_args = coerce_template_parms (DECL_INNERMOST_TEMPLATE_PARMS (tmpl), spec_args = coerce_template_parms (DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
spec_args, tmpl, spec_args, tmpl,
tf_none, false, false); tf_none, false, false);
pop_tinst_level ();
if (spec_args == error_mark_node if (spec_args == error_mark_node
/* We only need to check the innermost arguments; the other /* We only need to check the innermost arguments; the other
arguments will always agree. */ arguments will always agree. */
@ -21057,44 +21065,21 @@ most_specialized_partial_spec (tree target, tsubst_flags_t complain)
for (t = DECL_TEMPLATE_SPECIALIZATIONS (main_tmpl); t; t = TREE_CHAIN (t)) for (t = DECL_TEMPLATE_SPECIALIZATIONS (main_tmpl); t; t = TREE_CHAIN (t))
{ {
tree partial_spec_args;
tree spec_args; tree spec_args;
tree spec_tmpl = TREE_VALUE (t); tree spec_tmpl = TREE_VALUE (t);
partial_spec_args = TREE_PURPOSE (t);
++processing_template_decl;
if (outer_args) if (outer_args)
{ {
/* Discard the outer levels of args, and then substitute in the /* Substitute in the template args from the enclosing class. */
template args from the enclosing class. */ ++processing_template_decl;
partial_spec_args = INNERMOST_TEMPLATE_ARGS (partial_spec_args);
partial_spec_args = tsubst_template_args
(partial_spec_args, outer_args, tf_none, NULL_TREE);
/* And the same for the partial specialization TEMPLATE_DECL. */
spec_tmpl = tsubst (spec_tmpl, outer_args, tf_none, NULL_TREE); spec_tmpl = tsubst (spec_tmpl, outer_args, tf_none, NULL_TREE);
--processing_template_decl;
} }
partial_spec_args =
coerce_template_parms (DECL_INNERMOST_TEMPLATE_PARMS (tmpl),
partial_spec_args,
tmpl, tf_none,
/*require_all_args=*/true,
/*use_default_args=*/true);
--processing_template_decl;
if (partial_spec_args == error_mark_node)
return error_mark_node;
if (spec_tmpl == error_mark_node) if (spec_tmpl == error_mark_node)
return error_mark_node; return error_mark_node;
tree parms = DECL_INNERMOST_TEMPLATE_PARMS (spec_tmpl); spec_args = get_partial_spec_bindings (tmpl, spec_tmpl, args);
spec_args = get_partial_spec_bindings (tmpl, parms,
partial_spec_args,
args);
if (spec_args) if (spec_args)
{ {
if (outer_args) if (outer_args)

View File

@ -0,0 +1,23 @@
// PR c++/71747
// { dg-do compile { target c++11 } }
// { dg-options -ftemplate-depth=20 }
template < bool > struct A
{
typedef int type;
constexpr bool operator() () const
{
return true;
}
};
template < bool, typename = int > struct F;
template < bool X >
// should be: struct F < X, typename A < A < X > {} () >::type >
struct F < X, typename A < F < X > {} () >::type > // { dg-error "" }
{
};
F < true > f;
// { dg-prune-output "compilation terminated" }

View File

@ -7,11 +7,11 @@ template<bool b> struct if_c {
}; };
template< typename T > struct has_type { template< typename T > struct has_type {
struct gcc_3_2_wknd { struct gcc_3_2_wknd {
template< typename U > static yes_tag test( type_wrapper<U> const volatile* template< typename U > static yes_tag test( type_wrapper<U> const volatile* // { dg-message "required" }
, type_wrapper<typename U::type>* = 0 ); , type_wrapper<typename U::type>* = 0 );
}; };
typedef type_wrapper<T> t_; typedef type_wrapper<T> t_;
static const bool value = sizeof(gcc_3_2_wknd::test(static_cast<t_*>(0))) == static const bool value = sizeof(gcc_3_2_wknd::test(static_cast<t_*>(0))) == // { dg-message "required" }
sizeof(yes_tag); sizeof(yes_tag);
}; };
template <class K, class T, class=void> struct Get_type { template <class K, class T, class=void> struct Get_type {
@ -19,9 +19,10 @@ template <class K, class T, class=void> struct Get_type {
struct FT_tag {}; struct FT_tag {};
struct RT_tag {}; struct RT_tag {};
template <class K> struct Get_type<K, RT_tag, typename if_c< template <class K> struct Get_type<K, RT_tag, typename if_c<
!has_type<Get_type<K, FT_tag> >::value >::type> { }; !has_type<Get_type<K, FT_tag> >::value >::type> { }; // { dg-message "required" }
template <class K> struct Get_type<K, FT_tag, typename if_c< template <class K> struct Get_type<K, FT_tag, typename if_c<
!has_type<Get_type<K, RT_tag> >::value >::type> { }; // { dg-error "depth" } !has_type<Get_type<K, RT_tag> >::value >::type> { }; // { dg-message "required" }
typedef Get_type<int, FT_tag>::type P; typedef Get_type<int, FT_tag>::type P;
// { dg-prune-output "-ftemplate-depth" }
// { dg-prune-output "compilation terminated" } // { dg-prune-output "compilation terminated" }