diff options
author | Mark Mitchell <mark@markmitchell.com> | 1998-08-30 10:59:18 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 1998-08-30 10:59:18 +0000 |
commit | 8b5b8b7cc1d7f2fe67798c5b8648286309cabd73 (patch) | |
tree | c4e48d9ad7dd1a564c89ac395d7a6bf8971959ca /gcc | |
parent | 38f477fe90bc4792590bd96499d384d723fde816 (diff) | |
download | gcc-8b5b8b7cc1d7f2fe67798c5b8648286309cabd73.zip gcc-8b5b8b7cc1d7f2fe67798c5b8648286309cabd73.tar.gz gcc-8b5b8b7cc1d7f2fe67798c5b8648286309cabd73.tar.bz2 |
pt.c (convert_template_argument): New function, split out from...
* pt.c (convert_template_argument): New function, split out
from...
(coerce_template_parms): Here.
(tsubst): Attempt better error-recovery.
From-SVN: r22099
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 7 | ||||
-rw-r--r-- | gcc/cp/pt.c | 512 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.pt/crash22.C | 9 |
3 files changed, 265 insertions, 263 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 7edce86..fc79d48 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,10 @@ +1998-08-30 Mark Mitchell <mark@markmitchell.com> + + * pt.c (convert_template_argument): New function, split out + from... + (coerce_template_parms): Here. + (tsubst): Attempt better error-recovery. + 1998-08-28 Benjamin Kosnik <bkoz@loony.cygnus.com> * pt.c (decl_template_parm_p): Add checks for diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 364fd52..fff3fbc 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -95,6 +95,8 @@ static int type_unification_real PROTO((tree, tree, tree, tree, static void note_template_header PROTO((int)); static tree maybe_fold_nontype_arg PROTO((tree)); static tree convert_nontype_argument PROTO((tree, tree)); +static tree convert_template_argument PROTO ((tree, tree, tree, int, + int , tree)); static tree get_bindings_overload PROTO((tree, tree, tree)); static int for_each_template_parm PROTO((tree, tree_fn_t, void*)); static tree build_template_parm_index PROTO((int, int, int, tree, tree)); @@ -2596,11 +2598,207 @@ coerce_template_template_parms (parm_parms, arg_parms, in_decl, outer_args) return 1; } -/* Convert all template arguments to their appropriate types, and return - a vector containing the resulting values. If any error occurs, return - error_mark_node, and, if COMPLAIN is non-zero, issue an error message. - Some error messages are issued even if COMPLAIN is zero; for - instance, if a template argument is composed from a local class. + +/* Convert the indicated template ARG as necessary to match the + indicated template PARM. Returns the converted ARG, or + error_mark_node if the conversion was unsuccessful. Error messages + are issued if COMPLAIN is non-zero. This conversion is for the Ith + parameter in the parameter list. ARGS is the full set of template + arguments deduced so far. */ + +static tree +convert_template_argument (parm, arg, args, complain, i, in_decl) + tree parm; + tree arg; + tree args; + int complain; + int i; + tree in_decl; +{ + tree val; + tree inner_args; + int is_type, requires_type, is_tmpl_type, requires_tmpl_type; + + inner_args = innermost_args (args); + + if (TREE_CODE (arg) == TREE_LIST + && TREE_TYPE (arg) != NULL_TREE + && TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE) + { + /* The template argument was the name of some + member function. That's usually + illegal, but static members are OK. In any + case, grab the underlying fields/functions + and issue an error later if required. */ + arg = TREE_VALUE (arg); + TREE_TYPE (arg) = unknown_type_node; + } + + requires_tmpl_type = TREE_CODE (parm) == TEMPLATE_DECL; + requires_type = (TREE_CODE (parm) == TYPE_DECL + || requires_tmpl_type); + + /* Check if it is a class template. If REQUIRES_TMPL_TYPE is true, + we also accept implicitly created TYPE_DECL as a valid argument. + This is necessary to handle the case where we pass a template name + to a template template parameter in a scope where we've derived from + in instantiation of that template, so the template name refers to that + instantiation. We really ought to handle this better. */ + is_tmpl_type + = ((TREE_CODE (arg) == TEMPLATE_DECL + && TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL) + || (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM + && !CLASSTYPE_TEMPLATE_INFO (arg)) + || (TREE_CODE (arg) == RECORD_TYPE + && CLASSTYPE_TEMPLATE_INFO (arg) + && TREE_CODE (TYPE_NAME (arg)) == TYPE_DECL + && DECL_ARTIFICIAL (TYPE_NAME (arg)) + && requires_tmpl_type + && current_class_type + /* FIXME what about nested types? */ + && get_binfo (arg, current_class_type, 0))); + if (is_tmpl_type && TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM) + arg = TYPE_STUB_DECL (arg); + else if (is_tmpl_type && TREE_CODE (arg) == RECORD_TYPE) + arg = CLASSTYPE_TI_TEMPLATE (arg); + + is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't' || is_tmpl_type; + + if (requires_type && ! is_type && TREE_CODE (arg) == SCOPE_REF + && TREE_CODE (TREE_OPERAND (arg, 0)) == TEMPLATE_TYPE_PARM) + { + cp_pedwarn ("to refer to a type member of a template parameter,"); + cp_pedwarn (" use `typename %E'", arg); + + arg = make_typename_type (TREE_OPERAND (arg, 0), + TREE_OPERAND (arg, 1)); + is_type = 1; + } + if (is_type != requires_type) + { + if (in_decl) + { + if (complain) + { + cp_error ("type/value mismatch at argument %d in template parameter list for `%D'", + i + 1, in_decl); + if (is_type) + cp_error (" expected a constant of type `%T', got `%T'", + TREE_TYPE (parm), + (is_tmpl_type ? DECL_NAME (arg) : arg)); + else + cp_error (" expected a type, got `%E'", arg); + } + } + return error_mark_node; + } + if (is_tmpl_type ^ requires_tmpl_type) + { + if (in_decl && complain) + { + cp_error ("type/value mismatch at argument %d in template parameter list for `%D'", + i + 1, in_decl); + if (is_tmpl_type) + cp_error (" expected a type, got `%T'", DECL_NAME (arg)); + else + cp_error (" expected a class template, got `%T'", arg); + } + return error_mark_node; + } + + if (is_type) + { + if (requires_tmpl_type) + { + tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm); + tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg); + + if (coerce_template_template_parms (parmparm, argparm, + in_decl, inner_args)) + { + val = arg; + + /* TEMPLATE_TEMPLATE_PARM node is preferred over + TEMPLATE_DECL. */ + if (val != error_mark_node + && DECL_TEMPLATE_TEMPLATE_PARM_P (val)) + val = TREE_TYPE (val); + } + else + { + if (in_decl && complain) + { + cp_error ("type/value mismatch at argument %d in template parameter list for `%D'", + i + 1, in_decl); + cp_error (" expected a template of type `%D', got `%D'", parm, arg); + } + + val = error_mark_node; + } + } + else + { + val = groktypename (arg); + if (! processing_template_decl) + { + /* [basic.link]: A name with no linkage (notably, the + name of a class or enumeration declared in a local + scope) shall not be used to declare an entity with + linkage. This implies that names with no linkage + cannot be used as template arguments. */ + tree t = no_linkage_check (val); + if (t) + { + if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))) + cp_pedwarn + ("template-argument `%T' uses anonymous type", val); + else + cp_error + ("template-argument `%T' uses local type `%T'", + val, t); + return error_mark_node; + } + } + } + } + else + { + tree t = tsubst (TREE_TYPE (parm), args, in_decl); + + if (processing_template_decl) + arg = maybe_fold_nontype_arg (arg); + + if (!uses_template_parms (arg) && !uses_template_parms (t)) + /* We used to call digest_init here. However, digest_init + will report errors, which we don't want when complain + is zero. More importantly, digest_init will try too + hard to convert things: for example, `0' should not be + converted to pointer type at this point according to + the standard. Accepting this is not merely an + extension, since deciding whether or not these + conversions can occur is part of determining which + function template to call, or whether a given epxlicit + argument specification is legal. */ + val = convert_nontype_argument (t, arg); + else + val = arg; + + if (val == NULL_TREE) + val = error_mark_node; + else if (val == error_mark_node && complain) + cp_error ("could not convert template argument `%E' to `%T'", + arg, t); + } + + return val; +} + +/* Convert all template arguments to their appropriate types, and + return a vector containing the innermost resulting template + arguments. If any error occurs, return error_mark_node, and, if + COMPLAIN is non-zero, issue an error message. Some error messages + are issued even if COMPLAIN is zero; for instance, if a template + argument is composed from a local class. If REQUIRE_ALL_ARGUMENTS is non-zero, all arguments must be provided in ARGLIST, or else trailing parameters must have default @@ -2608,19 +2806,20 @@ coerce_template_template_parms (parm_parms, arg_parms, in_decl, outer_args) deduction for any unspecified trailing arguments. */ static tree -coerce_template_parms (parms, arglist, in_decl, +coerce_template_parms (parms, args, in_decl, complain, require_all_arguments) - tree parms, arglist; + tree parms, args; tree in_decl; int complain; int require_all_arguments; { int nparms, nargs, i, lost = 0; tree inner_args; - tree vec; + tree new_args; + tree new_inner_args; - inner_args = innermost_args (arglist); + inner_args = innermost_args (args); nargs = NUM_TMPL_ARGS (inner_args); nparms = TREE_VEC_LENGTH (parms); @@ -2641,278 +2840,63 @@ coerce_template_parms (parms, arglist, in_decl, return error_mark_node; } - /* Create in VEC the appropriate innermost arguments, and reset - ARGLIST to contain the complete set of arguments. */ - if (inner_args && TREE_CODE (inner_args) == TREE_VEC && nargs == nparms) - { - /* If we already have all the arguments, we can just use them. - This is an optimization over the code in the `else' branch - below, and should be functionally identicial. */ - vec = copy_node (inner_args); - arglist = add_outermost_template_args (arglist, vec); - } - else + new_inner_args = make_tree_vec (nparms); + new_args = add_outermost_template_args (args, new_inner_args); + for (i = 0; i < nparms; i++) { - /* If we don't already have all the arguments we must get what - we can from default template arguments. The tricky bit is - that previous arguments can influence the default values, - e.g.: - - template <class T, class U = T> void foo(); - - If we see `foo<int>' we have to come up with an {int, int} - vector. */ - - tree new_arglist; + tree arg; + tree parm; - vec = make_tree_vec (nparms); - new_arglist = add_outermost_template_args (arglist, vec); + /* Get the Ith template parameter. */ + parm = TREE_VEC_ELT (parms, i); - for (i = 0; i < nparms; i++) + /* Calculate the Ith argument. */ + if (inner_args && TREE_CODE (inner_args) == TREE_LIST) { - tree arg; - tree parm = TREE_VEC_ELT (parms, i); - - if (arglist && TREE_CODE (arglist) == TREE_LIST) - { - arg = arglist; - arglist = TREE_CHAIN (arglist); - - if (arg == error_mark_node) - lost++; - else - arg = TREE_VALUE (arg); - } - else if (i < nargs) - { - arg = TREE_VEC_ELT (inner_args, i); - if (arg == error_mark_node) - lost++; - } - /* If no template argument was supplied, look for a default - value. */ - else if (TREE_PURPOSE (parm) == NULL_TREE) - { - /* There was no default value. */ - my_friendly_assert (!require_all_arguments, 0); - break; - } - else if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL) - arg = tsubst (TREE_PURPOSE (parm), new_arglist, in_decl); - else - arg = tsubst_expr (TREE_PURPOSE (parm), new_arglist, in_decl); - - TREE_VEC_ELT (vec, i) = arg; + arg = TREE_VALUE (inner_args); + inner_args = TREE_CHAIN (inner_args); } + else if (i < nargs) + arg = TREE_VEC_ELT (inner_args, i); + /* If no template argument was supplied, look for a default + value. */ + else if (TREE_PURPOSE (parm) == NULL_TREE) + { + /* There was no default value. */ + my_friendly_assert (!require_all_arguments, 0); + break; + } + else if (TREE_CODE (TREE_VALUE (parm)) == TYPE_DECL) + arg = tsubst (TREE_PURPOSE (parm), new_args, in_decl); + else + arg = tsubst_expr (TREE_PURPOSE (parm), new_args, in_decl); - /* We've left ARGLIST intact up to this point, in order to allow - iteration through it in the case that it was a TREE_LIST, but - from here on it should contain the full set of template - arguments. */ - arglist = new_arglist; - } - - for (i = 0; i < nparms; i++) - { - tree arg = TREE_VEC_ELT (vec, i); - tree parm = TREE_VALUE (TREE_VEC_ELT (parms, i)); - tree val = 0; - int is_type, requires_type, is_tmpl_type, requires_tmpl_type; - + /* Now, convert the Ith argument, as necessary. */ if (arg == NULL_TREE) /* We're out of arguments. */ { my_friendly_assert (!require_all_arguments, 0); break; } - - if (arg == error_mark_node) + else if (arg == error_mark_node) { cp_error ("template argument %d is invalid", i + 1); - lost++; - continue; - } - - if (TREE_CODE (arg) == TREE_LIST - && TREE_TYPE (arg) != NULL_TREE - && TREE_CODE (TREE_TYPE (arg)) == OFFSET_TYPE) - { - /* The template argument was the name of some - member function. That's usually - illegal, but static members are OK. In any - case, grab the underlying fields/functions - and issue an error later if required. */ - arg = TREE_VALUE (arg); - TREE_TYPE (arg) = unknown_type_node; - } - - requires_tmpl_type = TREE_CODE (parm) == TEMPLATE_DECL; - requires_type = TREE_CODE (parm) == TYPE_DECL - || requires_tmpl_type; - - /* Check if it is a class template. If REQUIRES_TMPL_TYPE is true, - we also accept implicitly created TYPE_DECL as a valid argument. - This is necessary to handle the case where we pass a template name - to a template template parameter in a scope where we've derived from - in instantiation of that template, so the template name refers to that - instantiation. We really ought to handle this better. */ - is_tmpl_type = (TREE_CODE (arg) == TEMPLATE_DECL - && TREE_CODE (DECL_TEMPLATE_RESULT (arg)) == TYPE_DECL) - || (TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM - && !CLASSTYPE_TEMPLATE_INFO (arg)) - || (TREE_CODE (arg) == RECORD_TYPE - && CLASSTYPE_TEMPLATE_INFO (arg) - && TREE_CODE (TYPE_NAME (arg)) == TYPE_DECL - && DECL_ARTIFICIAL (TYPE_NAME (arg)) - && requires_tmpl_type - && current_class_type - /* FIXME what about nested types? */ - && get_binfo (arg, current_class_type, 0)); - if (is_tmpl_type && TREE_CODE (arg) == TEMPLATE_TEMPLATE_PARM) - arg = TYPE_STUB_DECL (arg); - else if (is_tmpl_type && TREE_CODE (arg) == RECORD_TYPE) - arg = CLASSTYPE_TI_TEMPLATE (arg); - - is_type = TREE_CODE_CLASS (TREE_CODE (arg)) == 't' || is_tmpl_type; - - if (requires_type && ! is_type && TREE_CODE (arg) == SCOPE_REF - && TREE_CODE (TREE_OPERAND (arg, 0)) == TEMPLATE_TYPE_PARM) - { - cp_pedwarn ("to refer to a type member of a template parameter,"); - cp_pedwarn (" use `typename %E'", arg); - - arg = make_typename_type (TREE_OPERAND (arg, 0), - TREE_OPERAND (arg, 1)); - is_type = 1; - } - if (is_type != requires_type) - { - if (in_decl) - { - if (complain) - { - cp_error ("type/value mismatch at argument %d in template parameter list for `%D'", - i + 1, in_decl); - if (is_type) - cp_error (" expected a constant of type `%T', got `%T'", - TREE_TYPE (parm), - (is_tmpl_type ? DECL_NAME (arg) : arg)); - else - cp_error (" expected a type, got `%E'", arg); - } - } - lost++; - TREE_VEC_ELT (vec, i) = error_mark_node; - continue; - } - if (is_tmpl_type ^ requires_tmpl_type) - { - if (in_decl && complain) - { - cp_error ("type/value mismatch at argument %d in template parameter list for `%D'", - i + 1, in_decl); - if (is_tmpl_type) - cp_error (" expected a type, got `%T'", DECL_NAME (arg)); - else - cp_error (" expected a class template, got `%T'", arg); - } - lost++; - TREE_VEC_ELT (vec, i) = error_mark_node; - continue; - } - - if (is_type) - { - if (requires_tmpl_type) - { - tree parmparm = DECL_INNERMOST_TEMPLATE_PARMS (parm); - tree argparm = DECL_INNERMOST_TEMPLATE_PARMS (arg); - - if (coerce_template_template_parms (parmparm, argparm, - in_decl, vec)) - { - val = arg; - - /* TEMPLATE_TEMPLATE_PARM node is preferred over - TEMPLATE_DECL. */ - if (val != error_mark_node - && DECL_TEMPLATE_TEMPLATE_PARM_P (val)) - val = TREE_TYPE (val); - } - else - { - if (in_decl && complain) - { - cp_error ("type/value mismatch at argument %d in template parameter list for `%D'", - i + 1, in_decl); - cp_error (" expected a template of type `%D', got `%D'", parm, arg); - } - - val = error_mark_node; - } - } - else - { - val = groktypename (arg); - if (! processing_template_decl) - { - /* [basic.link]: A name with no linkage (notably, the - name of a class or enumeration declared in a local - scope) shall not be used to declare an entity with - linkage. This implies that names with no linkage - cannot be used as template arguments. */ - tree t = no_linkage_check (val); - if (t) - { - if (ANON_AGGRNAME_P (TYPE_IDENTIFIER (t))) - cp_pedwarn - ("template-argument `%T' uses anonymous type", val); - else - cp_error - ("template-argument `%T' uses local type `%T'", - val, t); - return error_mark_node; - } - } - } - } - else - { - tree t = tsubst (TREE_TYPE (parm), arglist, in_decl); - - if (processing_template_decl) - arg = maybe_fold_nontype_arg (arg); - - if (!uses_template_parms (arg) && !uses_template_parms (t)) - /* We used to call digest_init here. However, digest_init - will report errors, which we don't want when complain - is zero. More importantly, digest_init will try too - hard to convert things: for example, `0' should not be - converted to pointer type at this point according to - the standard. Accepting this is not merely an - extension, since deciding whether or not these - conversions can occur is part of determining which - function template to call, or whether a given epxlicit - argument specification is legal. */ - val = convert_nontype_argument (t, arg); - else - val = arg; - - if (val == NULL_TREE) - val = error_mark_node; - else if (val == error_mark_node && complain) - cp_error ("could not convert template argument `%E' to `%T'", - arg, t); + arg = error_mark_node; } - - if (val == error_mark_node) + else + arg = convert_template_argument (TREE_VALUE (parm), + arg, new_args, complain, i, + in_decl); + + if (arg == error_mark_node) lost++; - - TREE_VEC_ELT (vec, i) = val; + TREE_VEC_ELT (new_inner_args, i) = arg; } + if (lost) return error_mark_node; - return vec; + + return new_inner_args; } /* Renturns 1 iff the OLDARGS and NEWARGS are in fact identical sets @@ -5317,7 +5301,9 @@ tsubst (t, args, in_decl) if (level <= levels) arg = TMPL_ARG (args, level, idx); - if (arg != NULL_TREE) + if (arg == error_mark_node) + return error_mark_node; + else if (arg != NULL_TREE) { if (TREE_CODE (t) == TEMPLATE_TYPE_PARM) { diff --git a/gcc/testsuite/g++.old-deja/g++.pt/crash22.C b/gcc/testsuite/g++.old-deja/g++.pt/crash22.C new file mode 100644 index 0000000..e947ef3 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.pt/crash22.C @@ -0,0 +1,9 @@ +// Build don't link: + +template <class T> +struct S1 {}; + +template <class T, class U = S1<T> > +struct S2 {}; + +template struct S2<100>; // ERROR - type/value mismatch |