diff options
author | Mark Mitchell <mark@markmitchell.com> | 1999-01-21 14:29:33 +0000 |
---|---|---|
committer | Mark Mitchell <mmitchel@gcc.gnu.org> | 1999-01-21 14:29:33 +0000 |
commit | 297e73d807cc311d7a49f5b96729f03fde333da5 (patch) | |
tree | baf338e3c55393da72e8f2f9e50fa81ec5ca6a34 /gcc | |
parent | 939b4a73dbf5ef563c9567c68c6d8e56708f964d (diff) | |
download | gcc-297e73d807cc311d7a49f5b96729f03fde333da5.zip gcc-297e73d807cc311d7a49f5b96729f03fde333da5.tar.gz gcc-297e73d807cc311d7a49f5b96729f03fde333da5.tar.bz2 |
cp-tree.h (PARM_DECL_EXPR): Delete.
* cp-tree.h (PARM_DECL_EXPR): Delete.
(convert_default_arg): Change prototype.
(check_default_argument): Declare.
(search_tree): Likewise.
* call.c (convert_default_arg): Take the function to which the
default argument belongs as a parameter, and do any necessary
instantiation here, instead of ...
(build_over_call): Here.
* decl.c (local_variable_p): New function.
(check_default_argument): Likewise, split out and tidied from ...
(grokparms): Here.
* error.c (dump_expr): Don't set PARM_DECL_EXPR.
* pt.c (tsubst_call_declarator_parms): New function.
(for_each_template_parm): Handle ARRAY_REFs. Do the obvious thing
with CALL_EXPRs, rather than trying to be clever.
(tsubst): Use tsubst_call_declarator_parms.
* tree.c (search_tree): Don't make it static.
* typeck.c (convert_arguments): Use new interface to
convert_default_arg.
From-SVN: r24803
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/cp/ChangeLog | 22 | ||||
-rw-r--r-- | gcc/cp/call.c | 70 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 8 | ||||
-rw-r--r-- | gcc/cp/decl.c | 145 | ||||
-rw-r--r-- | gcc/cp/error.c | 1 | ||||
-rw-r--r-- | gcc/cp/pt.c | 48 | ||||
-rw-r--r-- | gcc/cp/tree.c | 2 | ||||
-rw-r--r-- | gcc/cp/typeck.c | 7 | ||||
-rw-r--r-- | gcc/testsuite/g++.old-deja/g++.other/defarg1.C | 28 |
9 files changed, 243 insertions, 88 deletions
diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 9b14cda..498560a 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,25 @@ +1999-01-21 Mark Mitchell <mark@markmitchell.com> + + * cp-tree.h (PARM_DECL_EXPR): Delete. + (convert_default_arg): Change prototype. + (check_default_argument): Declare. + (search_tree): Likewise. + * call.c (convert_default_arg): Take the function to which the + default argument belongs as a parameter, and do any necessary + instantiation here, instead of ... + (build_over_call): Here. + * decl.c (local_variable_p): New function. + (check_default_argument): Likewise, split out and tidied from ... + (grokparms): Here. + * error.c (dump_expr): Don't set PARM_DECL_EXPR. + * pt.c (tsubst_call_declarator_parms): New function. + (for_each_template_parm): Handle ARRAY_REFs. Do the obvious thing + with CALL_EXPRs, rather than trying to be clever. + (tsubst): Use tsubst_call_declarator_parms. + * tree.c (search_tree): Don't make it static. + * typeck.c (convert_arguments): Use new interface to + convert_default_arg. + 1999-01-20 Mark Mitchell <mark@markmitchell.com> * error.c (dump_function_decl): Don't print the argument types for diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 356a57d..3891ea7 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -3176,13 +3176,41 @@ convert_arg_to_ellipsis (arg) } /* ARG is a default argument expression being passed to a parameter of - the indicated TYPE. Do any required conversions. Return the - converted value. */ + the indicated TYPE, which is a parameter to FN. Do any required + conversions. Return the converted value. */ tree -convert_default_arg (type, arg) - tree type, arg; +convert_default_arg (type, arg, fn) + tree type; + tree arg; + tree fn; { + if (fn && DECL_TEMPLATE_INFO (fn)) + { + /* This default argument came from a template. Instantiate the + default argument here, not in tsubst. In the case of + something like: + + template <class T> + struct S { + static T t(); + void f(T = t()); + }; + + we must be careful to do name lookup in the scope of S<T>, + rather than in the current class. */ + if (DECL_CLASS_SCOPE_P (fn)) + pushclass (DECL_REAL_CONTEXT (fn), 2); + + arg = tsubst_expr (arg, DECL_TI_ARGS (fn), NULL_TREE); + + if (DECL_CLASS_SCOPE_P (fn)) + popclass (1); + + /* Make sure the default argument is reasonable. */ + arg = check_default_argument (type, arg); + } + arg = break_out_target_exprs (arg); if (TREE_CODE (arg) == CONSTRUCTOR) @@ -3326,34 +3354,12 @@ build_over_call (cand, args, flags) /* Default arguments */ for (; parm && parm != void_list_node; parm = TREE_CHAIN (parm)) - { - tree arg = TREE_PURPOSE (parm); - - if (DECL_TEMPLATE_INFO (fn)) - { - /* This came from a template. Instantiate the default arg here, - not in tsubst. In the case of something like: - - template <class T> - struct S { - static T t(); - void f(T = t()); - }; - - we must be careful to do name lookup in the scope of - S<T>, rather than in the current class. */ - if (DECL_CLASS_SCOPE_P (fn)) - pushclass (DECL_REAL_CONTEXT (fn), 2); - - arg = tsubst_expr (arg, DECL_TI_ARGS (fn), NULL_TREE); - - if (DECL_CLASS_SCOPE_P (fn)) - popclass (1); - } - converted_args = expr_tree_cons - (NULL_TREE, convert_default_arg (TREE_VALUE (parm), arg), - converted_args); - } + converted_args + = expr_tree_cons (NULL_TREE, + convert_default_arg (TREE_VALUE (parm), + TREE_PURPOSE (parm), + fn), + converted_args); /* Ellipsis */ for (; arg; arg = TREE_CHAIN (arg)) diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 18f697a..7dc06ff 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -43,7 +43,6 @@ Boston, MA 02111-1307, USA. */ BINFO_VBASE_MARKED. BINFO_FIELDS_MARKED. TYPE_VIRTUAL_P. - PARM_DECL_EXPR (in SAVE_EXPR). 3: TYPE_USES_VIRTUAL_BASECLASSES (in a class TYPE). BINFO_VTABLE_PATH_MARKED. BINFO_PUSHDECLS_MARKED. @@ -1704,9 +1703,6 @@ extern int flag_new_for_scope; specified in its declaration. */ #define DECL_THIS_STATIC(NODE) (DECL_LANG_FLAG_6(NODE)) -/* Nonzero for SAVE_EXPR if used to initialize a PARM_DECL. */ -#define PARM_DECL_EXPR(NODE) (TREE_LANG_FLAG_2(NODE)) - /* Nonzero in FUNCTION_DECL means it is really an operator. Just used to communicate formatting information to dbxout.c. */ #define DECL_OPERATOR(NODE) (DECL_LANG_SPECIFIC(NODE)->decl_flags.operator_attr) @@ -2645,7 +2641,7 @@ extern tree build_op_delete_call PROTO((enum tree_code, tree, tree, int, tree)) extern int can_convert PROTO((tree, tree)); extern int can_convert_arg PROTO((tree, tree, tree)); extern void enforce_access PROTO((tree, tree)); -extern tree convert_default_arg PROTO((tree, tree)); +extern tree convert_default_arg PROTO((tree, tree, tree)); extern tree convert_arg_to_ellipsis PROTO((tree)); /* in class.c */ @@ -2819,6 +2815,7 @@ extern void fixup_anonymous_union PROTO((tree)); extern int check_static_variable_definition PROTO((tree, tree)); extern void push_local_binding PROTO((tree, tree)); extern void push_class_binding PROTO((tree, tree)); +extern tree check_default_argument PROTO((tree, tree)); /* in decl2.c */ extern int check_java_method PROTO((tree)); @@ -3300,6 +3297,7 @@ extern void push_expression_obstack PROTO((void)); extern tree build_dummy_object PROTO((tree)); extern tree maybe_dummy_object PROTO((tree, tree *)); extern int is_dummy_object PROTO((tree)); +extern tree search_tree PROTO((tree, tree (*)(tree))); #define scratchalloc expralloc #define scratch_tree_cons expr_tree_cons #define build_scratch_list build_expr_list diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index bb2ef72..161876e 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -182,6 +182,7 @@ static boolean typename_compare PROTO((hash_table_key, hash_table_key)); static void push_binding PROTO((tree, tree, struct binding_level*)); static void add_binding PROTO((tree, tree)); static void pop_binding PROTO((tree, tree)); +static tree local_variable_p PROTO((tree)); #if defined (DEBUG_CP_BINDING_LEVELS) static void indent PROTO((void)); @@ -11260,6 +11261,103 @@ require_complete_types_for_parms (parms) } } +/* Returns DECL if DECL is a local variable (or parameter). Returns + NULL_TREE otherwise. */ + +static tree +local_variable_p (t) + tree t; +{ + if ((TREE_CODE (t) == VAR_DECL + /* A VAR_DECL with a context that is a _TYPE is a static data + member. */ + && !TYPE_P (CP_DECL_CONTEXT (t)) + /* Any other non-local variable must be at namespace scope. */ + && TREE_CODE (CP_DECL_CONTEXT (t)) != NAMESPACE_DECL) + || (TREE_CODE (t) == PARM_DECL)) + return t; + + return NULL_TREE; +} + +/* Check that ARG, which is a default-argument expression for a + parameter DECL, is legal. Returns ARG, or ERROR_MARK_NODE, if + something goes wrong. DECL may also be a _TYPE node, rather than a + DECL, if there is no DECL available. */ + +tree +check_default_argument (decl, arg) + tree decl; + tree arg; +{ + tree var; + tree decl_type; + + if (TREE_CODE (arg) == DEFAULT_ARG) + /* We get a DEFAULT_ARG when looking at an in-class declaration + with a default argument. Ignore the argument for now; we'll + deal with it after the class is complete. */ + return arg; + + if (processing_template_decl || uses_template_parms (arg)) + /* We don't do anything checking until instantiation-time. Note + that there may be uninstantiated arguments even for an + instantiated function, since default arguments are not + instantiated until they are needed. */ + return arg; + + if (TYPE_P (decl)) + { + decl_type = decl; + decl = NULL_TREE; + } + else + decl_type = TREE_TYPE (decl); + + if (arg == error_mark_node + || decl == error_mark_node + || TREE_TYPE (arg) == error_mark_node + || decl_type == error_mark_node) + /* Something already went wrong. There's no need to check + further. */ + return error_mark_node; + + /* [dcl.fct.default] + + A default argument expression is implicitly converted to the + parameter type. */ + if (!TREE_TYPE (arg) + || !can_convert_arg (decl_type, TREE_TYPE (arg), arg)) + { + if (decl) + cp_error ("default argument for `%#D' has type `%T'", + decl, TREE_TYPE (arg)); + else + cp_error ("default argument for paramter of type `%T' has type `%T'", + decl_type, TREE_TYPE (arg)); + + return error_mark_node; + } + + /* [dcl.fct.default] + + Local variables shall not be used in default argument + expressions. + + The keyword `this' shall not be used in a default argument of a + member function. */ + var = search_tree (arg, local_variable_p); + if (var) + { + cp_error ("default argument `%E' uses local variable `%D'", + arg, var); + return error_mark_node; + } + + /* All is well. */ + return arg; +} + /* Decode the list of parameter types for a function type. Given the list of things declared inside the parens, return a list of types. @@ -11437,51 +11535,10 @@ grokparms (first_parm, funcdef_flag) && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) DECL_ARG_TYPE (decl) = integer_type_node; #endif - if (!any_error) + if (!any_error && init) { - if (init) - { - any_init++; - if (TREE_CODE (init) == SAVE_EXPR) - PARM_DECL_EXPR (init) = 1; - else if (processing_template_decl) - ; - /* Unparsed default arg from in-class decl. */ - else if (TREE_CODE (init) == DEFAULT_ARG) - ; - else if (TREE_CODE (init) == PARM_DECL - || TREE_CODE (init) == VAR_DECL) - { - if (TREE_CODE (init) == VAR_DECL - && (IDENTIFIER_VALUE (DECL_NAME (init)) - == init) - && LOCAL_BINDING_P - (IDENTIFIER_BINDING (DECL_NAME - (init)))) - { - /* ``Local variables may not be used in - default argument expressions.'' - dpANSI C++ 8.2.6 */ - - cp_error ("local variable `%D' may not be used as a default argument", init); - any_error = 1; - } - else if (TREE_READONLY_DECL_P (init)) - init = decl_constant_value (init); - } - else if (TREE_TYPE (init) == NULL_TREE) - { - error ("argument list may not have an initializer list"); - init = error_mark_node; - } - - if (! processing_template_decl - && init != error_mark_node - && TREE_CODE (init) != DEFAULT_ARG - && ! can_convert_arg (type, TREE_TYPE (init), init)) - cp_pedwarn ("invalid type `%T' for default argument to `%#D'", - TREE_TYPE (init), decl); - } + any_init++; + init = check_default_argument (decl, init); } else init = NULL_TREE; diff --git a/gcc/cp/error.c b/gcc/cp/error.c index fd3f5f5..ec3bf71 100644 --- a/gcc/cp/error.c +++ b/gcc/cp/error.c @@ -1344,7 +1344,6 @@ dump_expr (t, nop) { OB_PUTS ("new "); dump_type (TREE_TYPE (TREE_TYPE (t)), 0); - PARM_DECL_EXPR (t) = 1; } else { diff --git a/gcc/cp/pt.c b/gcc/cp/pt.c index 0a67535..9bd73c2 100644 --- a/gcc/cp/pt.c +++ b/gcc/cp/pt.c @@ -136,6 +136,7 @@ static void check_specialization_scope PROTO((void)); static tree process_partial_specialization PROTO((tree)); static void set_current_access_from_decl PROTO((tree)); static void check_default_tmpl_args PROTO((tree, tree, int, int)); +static tree tsubst_call_declarator_parms PROTO((tree, tree, tree)); /* We use TREE_VECs to hold template arguments. If there is only one level of template arguments, then the TREE_VEC contains the @@ -3809,6 +3810,10 @@ for_each_template_parm (t, fn, data) COMPONENT_REF uses template parms. */ return for_each_template_parm (TREE_TYPE (t), fn, data); + case ARRAY_REF: + return (for_each_template_parm (TREE_OPERAND (t, 0), fn, data) + || for_each_template_parm (TREE_OPERAND (t, 1), fn, data)); + case IDENTIFIER_NODE: if (!IDENTIFIER_TEMPLATE (t)) return 0; @@ -3917,7 +3922,9 @@ for_each_template_parm (t, fn, data) return 0; case CALL_EXPR: - return for_each_template_parm (TREE_TYPE (t), fn, data); + return (for_each_template_parm (TREE_OPERAND (t, 0), fn, data) + || for_each_template_parm (TREE_OPERAND (t, 1), fn, data)); + case ADDR_EXPR: return for_each_template_parm (TREE_OPERAND (t, 0), fn, data); @@ -5628,6 +5635,43 @@ tsubst_arg_types (arg_types, args, in_decl) } +/* Substitute into the PARMS of a call-declarator. */ + +tree +tsubst_call_declarator_parms (parms, args, in_decl) + tree parms; + tree args; + tree in_decl; +{ + tree new_parms; + tree type; + tree defarg; + + if (!parms || parms == void_list_node) + return parms; + + new_parms = tsubst_call_declarator_parms (TREE_CHAIN (parms), + args, in_decl); + + /* Figure out the type of this parameter. */ + type = tsubst (TREE_VALUE (parms), args, in_decl); + + /* Figure out the default argument as well. Note that we use + tsubst_copy since the default argument is really an + expression. */ + defarg = tsubst_expr (TREE_PURPOSE (parms), args, in_decl); + + /* Chain this parameter on to the front of those we have already + processed. We don't use hash_tree_cons because that function + doesn't check TREE_PARMLIST. */ + new_parms = tree_cons (defarg, type, new_parms); + + /* And note that these are parameters. */ + TREE_PARMLIST (new_parms) = 1; + + return new_parms; +} + /* Take the tree structure T and replace template parameters used therein with the argument vector ARGS. IN_DECL is an associated decl for diagnostics. @@ -6061,7 +6105,7 @@ tsubst (t, args, in_decl) case CALL_EXPR: return make_call_declarator (tsubst (TREE_OPERAND (t, 0), args, in_decl), - tsubst (TREE_OPERAND (t, 1), args, in_decl), + tsubst_call_declarator_parms (TREE_OPERAND (t, 1), args, in_decl), TREE_OPERAND (t, 2), tsubst (TREE_TYPE (t), args, in_decl)); diff --git a/gcc/cp/tree.c b/gcc/cp/tree.c index 85cd968..65ae47a 100644 --- a/gcc/cp/tree.c +++ b/gcc/cp/tree.c @@ -1545,7 +1545,7 @@ copy_template_template_parm (t) /* Walk through the tree structure T, applying func. If func ever returns non-null, return that value. */ -static tree +tree search_tree (t, func) tree t; tree (*func) PROTO((tree)); diff --git a/gcc/cp/typeck.c b/gcc/cp/typeck.c index 9882f76..82ce514 100644 --- a/gcc/cp/typeck.c +++ b/gcc/cp/typeck.c @@ -3088,9 +3088,10 @@ convert_arguments (typelist, values, fndecl, flags) { for (; typetail != void_list_node; ++i) { - tree type = TREE_VALUE (typetail); - tree val = TREE_PURPOSE (typetail); - tree parmval = convert_default_arg (type, val); + tree parmval + = convert_default_arg (TREE_VALUE (typetail), + TREE_PURPOSE (typetail), + fndecl); if (parmval == error_mark_node) return error_mark_node; diff --git a/gcc/testsuite/g++.old-deja/g++.other/defarg1.C b/gcc/testsuite/g++.old-deja/g++.other/defarg1.C new file mode 100644 index 0000000..68b07a5 --- /dev/null +++ b/gcc/testsuite/g++.old-deja/g++.other/defarg1.C @@ -0,0 +1,28 @@ +// Build don't link: + +int f (int x) +{ + extern void g (int i = f (x)); // ERROR - default argument uses local + + g(); + + return 0; +} + +int f (void); + +int h1 (int (*)(int) = f); +int h2 (int (*)(double) = f); // ERROR - no matching f + +template <class T> +int j (T t) +{ + extern void k (int i = j (t)); // ERROR - default argument uses local + + k (); + + return 0; +} + +template int j (double); // ERROR - instantiated from here + |