aboutsummaryrefslogtreecommitdiff
path: root/gcc
diff options
context:
space:
mode:
authorMark Mitchell <mark@markmitchell.com>1999-01-21 14:29:33 +0000
committerMark Mitchell <mmitchel@gcc.gnu.org>1999-01-21 14:29:33 +0000
commit297e73d807cc311d7a49f5b96729f03fde333da5 (patch)
treebaf338e3c55393da72e8f2f9e50fa81ec5ca6a34 /gcc
parent939b4a73dbf5ef563c9567c68c6d8e56708f964d (diff)
downloadgcc-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/ChangeLog22
-rw-r--r--gcc/cp/call.c70
-rw-r--r--gcc/cp/cp-tree.h8
-rw-r--r--gcc/cp/decl.c145
-rw-r--r--gcc/cp/error.c1
-rw-r--r--gcc/cp/pt.c48
-rw-r--r--gcc/cp/tree.c2
-rw-r--r--gcc/cp/typeck.c7
-rw-r--r--gcc/testsuite/g++.old-deja/g++.other/defarg1.C28
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
+