diff options
Diffstat (limited to 'gcc')
-rw-r--r-- | gcc/ChangeLog | 9 | ||||
-rw-r--r-- | gcc/cp/ChangeLog | 12 | ||||
-rw-r--r-- | gcc/cp/call.c | 31 | ||||
-rw-r--r-- | gcc/cp/cp-lang.c | 3 | ||||
-rw-r--r-- | gcc/cp/cp-tree.h | 5 | ||||
-rw-r--r-- | gcc/cp/except.c | 26 | ||||
-rw-r--r-- | gcc/integrate.c | 32 | ||||
-rw-r--r-- | gcc/testsuite/g++.dg/init/elide2.C | 30 | ||||
-rw-r--r-- | gcc/tree-inline.c | 14 | ||||
-rw-r--r-- | gcc/tree.c | 3 |
10 files changed, 106 insertions, 59 deletions
diff --git a/gcc/ChangeLog b/gcc/ChangeLog index 579d884..76609c3 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,12 @@ +2002-12-04 Jason Merrill <jason@redhat.com> + + PR c++/8461, c++/8625 + * integrate.c (copy_decl_for_inlining): Handle explicit invisible + references. + * tree-inline.c (initialize_inlined_parameters): Likewise. + + * tree.c (variably_modified_type_p): Just return an error_mark_node. + 2002-12-04 Chris Demetriou <cgd@broadcom.com> * config/mips/mips.md (get_fnaddr): Avoid placing an "la" diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 5da6ebc..60789ee 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -6,6 +6,18 @@ 2002-12-03 Jason Merrill <jason@redhat.com> + PR c++/8674 + * call.c (build_over_call): Check specifically for TARGET_EXPR + when eliding. + + PR c++/8461, c++/8625 + * call.c (convert_for_arg_passing): Don't mess with error_mark_node. + (cp_convert_parm_for_inlining): Remove. + * cp-lang.c (LANG_HOOKS_TREE_INLINING_CONVERT_PARM_FOR_INLINING): + Remove. + * cp-tree.h (ADDR_IS_INVISIREF): Remove. + * except.c (stabilize_throw_expr): Remove ADDR_IS_INVISIREF code. + * call.c (build_user_type_conversion_1): Don't set ICS_BAD_FLAG on an ambiguous conversion. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index 1678ed2..072fbe6 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4276,12 +4276,11 @@ tree convert_for_arg_passing (type, val) tree type, val; { + if (val == error_mark_node) + ; /* Pass classes with copy ctors by invisible reference. */ - if (TREE_ADDRESSABLE (type)) - { - val = build1 (ADDR_EXPR, build_reference_type (type), val); - ADDR_IS_INVISIREF (val) = 1; - } + else if (TREE_ADDRESSABLE (type)) + val = build1 (ADDR_EXPR, build_reference_type (type), val); else if (PROMOTE_PROTOTYPES && INTEGRAL_TYPE_P (type) && TYPE_PRECISION (type) < TYPE_PRECISION (integer_type_node)) @@ -4289,24 +4288,6 @@ convert_for_arg_passing (type, val) return val; } -/* Convert VALUE for assignment into inlined parameter PARM. */ - -tree -cp_convert_parm_for_inlining (parm, value, fn) - tree parm, value; - tree fn ATTRIBUTE_UNUSED; -{ - /* When inlining, we don't need to mess with invisible references, so - undo the ADDR_EXPR. */ - if (TREE_ADDRESSABLE (TREE_TYPE (parm))) - { - value = TREE_OPERAND (value, 0); - if (TREE_CODE (value) != TARGET_EXPR) - abort (); - } - return value; -} - /* Subroutine of the various build_*_call functions. Overload resolution has chosen a winning candidate CAND; build up a CALL_EXPR accordingly. ARGS is a TREE_LIST of the unconverted arguments to the call. FLAGS is a @@ -4477,12 +4458,12 @@ build_over_call (cand, args, flags) temp or an INIT_EXPR otherwise. */ if (integer_zerop (TREE_VALUE (args))) { - if (! real_lvalue_p (arg)) + if (TREE_CODE (arg) == TARGET_EXPR) return arg; else if (TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn))) return build_target_expr_with_type (arg, DECL_CONTEXT (fn)); } - else if (!real_lvalue_p (arg) + else if (TREE_CODE (arg) == TARGET_EXPR || TYPE_HAS_TRIVIAL_INIT_REF (DECL_CONTEXT (fn))) { tree address; diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c index d89fb63..a7f2d85 100644 --- a/gcc/cp/cp-lang.c +++ b/gcc/cp/cp-lang.c @@ -122,9 +122,6 @@ static bool cp_var_mod_type_p PARAMS ((tree)); #undef LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING #define LANG_HOOKS_TREE_INLINING_COPY_RES_DECL_FOR_INLINING \ cp_copy_res_decl_for_inlining -#undef LANG_HOOKS_TREE_INLINING_CONVERT_PARM_FOR_INLINING -#define LANG_HOOKS_TREE_INLINING_CONVERT_PARM_FOR_INLINING \ - cp_convert_parm_for_inlining #undef LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P #define LANG_HOOKS_TREE_INLINING_ANON_AGGR_TYPE_P anon_aggr_type_p #undef LANG_HOOKS_TREE_INLINING_VAR_MOD_TYPE_P diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 0c8c37a..4c0efd2 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -65,7 +65,6 @@ struct diagnostic_context; BINDING_HAS_LEVEL_P (in CPLUS_BINDING) BINFO_LOST_PRIMARY_P (in BINFO) TREE_PARMLIST (in TREE_LIST) - ADDR_IS_INVISIREF (in ADDR_EXPR) 3: TYPE_USES_VIRTUAL_BASECLASSES (in a class TYPE). BINFO_VTABLE_PATH_MARKED. BINFO_PUSHDECLS_MARKED. @@ -1687,10 +1686,6 @@ struct lang_type GTY(()) /* Nonzero for a parmlist means that this parmlist ended in ... */ #define PARMLIST_ELLIPSIS_P(NODE) TREE_LANG_FLAG_0 (NODE) -/* Nonzero if this ADDR_EXPR is used to implement the pass by invisible - reference calling convention. */ -#define ADDR_IS_INVISIREF(NODE) TREE_LANG_FLAG_2 (NODE) - /* For FUNCTION_TYPE or METHOD_TYPE, a list of the exceptions that this type can raise. Each TREE_VALUE is a _TYPE. The TREE_VALUE will be NULL_TREE to indicate a throw specification of `()', or diff --git a/gcc/cp/except.c b/gcc/cp/except.c index 848ef51..747cc1a 100644 --- a/gcc/cp/except.c +++ b/gcc/cp/except.c @@ -601,28 +601,12 @@ stabilize_throw_expr (exp, initp) { tree arg = TREE_VALUE (args); tree arg_init_expr; - if (TREE_CODE (arg) == ADDR_EXPR - && ADDR_IS_INVISIREF (arg)) - { - /* A sub-TARGET_EXPR. Recurse; we can't wrap the actual call - without introducing an extra copy. */ - tree sub = TREE_OPERAND (arg, 0); - if (TREE_CODE (sub) != TARGET_EXPR) - abort (); - sub = stabilize_throw_expr (sub, &arg_init_expr); - TREE_OPERAND (arg, 0) = sub; - if (TREE_SIDE_EFFECTS (arg_init_expr)) - init_expr = build (COMPOUND_EXPR, void_type_node, init_expr, - arg_init_expr); - } - else - { - arg = stabilize_expr (arg, &arg_init_expr); - if (TREE_SIDE_EFFECTS (arg_init_expr)) - init_expr = build (COMPOUND_EXPR, void_type_node, init_expr, - arg_init_expr); - } + arg = stabilize_expr (arg, &arg_init_expr); + + if (TREE_SIDE_EFFECTS (arg_init_expr)) + init_expr = build (COMPOUND_EXPR, void_type_node, init_expr, + arg_init_expr); *p = tree_cons (NULL_TREE, arg, NULL_TREE); p = &TREE_CHAIN (*p); } diff --git a/gcc/integrate.c b/gcc/integrate.c index 0e54e48..7752d66 100644 --- a/gcc/integrate.c +++ b/gcc/integrate.c @@ -344,12 +344,36 @@ copy_decl_for_inlining (decl, from_fn, to_fn) /* Copy the declaration. */ if (TREE_CODE (decl) == PARM_DECL || TREE_CODE (decl) == RESULT_DECL) { + tree type; + int invisiref = 0; + + /* See if the frontend wants to pass this by invisible reference. */ + if (TREE_CODE (decl) == PARM_DECL + && DECL_ARG_TYPE (decl) != TREE_TYPE (decl) + && POINTER_TYPE_P (DECL_ARG_TYPE (decl)) + && TREE_TYPE (DECL_ARG_TYPE (decl)) == TREE_TYPE (decl)) + { + invisiref = 1; + type = DECL_ARG_TYPE (decl); + } + else + type = TREE_TYPE (decl); + /* For a parameter, we must make an equivalent VAR_DECL, not a new PARM_DECL. */ - copy = build_decl (VAR_DECL, DECL_NAME (decl), TREE_TYPE (decl)); - TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl); - TREE_READONLY (copy) = TREE_READONLY (decl); - TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl); + copy = build_decl (VAR_DECL, DECL_NAME (decl), type); + if (!invisiref) + { + TREE_ADDRESSABLE (copy) = TREE_ADDRESSABLE (decl); + TREE_READONLY (copy) = TREE_READONLY (decl); + TREE_THIS_VOLATILE (copy) = TREE_THIS_VOLATILE (decl); + } + else + { + TREE_ADDRESSABLE (copy) = 0; + TREE_READONLY (copy) = 1; + TREE_THIS_VOLATILE (copy) = 0; + } } else { diff --git a/gcc/testsuite/g++.dg/init/elide2.C b/gcc/testsuite/g++.dg/init/elide2.C new file mode 100644 index 0000000..e6d3300 --- /dev/null +++ b/gcc/testsuite/g++.dg/init/elide2.C @@ -0,0 +1,30 @@ +// PR c++/8674 + +// Bug: Since B().a is an rvalue, we tried to treat it like a TARGET_EXPR +// and elide the copy. But that produces a bitwise copy, which causes us +// to abort in cp_expr_size. + +// Test that we actually run the A copy constructor when calling f(). + +// { dg-do run } + +int c; + +struct A +{ + A () { ++c; } + A (const A&) { ++c; } +}; + +struct B +{ + A a; +}; + +void f (A) { } + +int main () +{ + f (B().a); + return c < 2; +} diff --git a/gcc/tree-inline.c b/gcc/tree-inline.c index 6dea353..0f5ab59 100644 --- a/gcc/tree-inline.c +++ b/gcc/tree-inline.c @@ -632,6 +632,7 @@ initialize_inlined_parameters (id, args, fn, block) #endif /* not INLINER_FOR_JAVA */ tree var; tree value; + tree var_sub; /* Find the initializer. */ value = (*lang_hooks.tree_inlining.convert_parm_for_inlining) @@ -669,12 +670,23 @@ initialize_inlined_parameters (id, args, fn, block) /* Make an equivalent VAR_DECL. */ var = copy_decl_for_inlining (p, fn, VARRAY_TREE (id->fns, 0)); + + /* See if the frontend wants to pass this by invisible reference. If + so, our new VAR_DECL will have REFERENCE_TYPE, and we need to + replace uses of the PARM_DECL with dereferences. */ + if (TREE_TYPE (var) != TREE_TYPE (p) + && POINTER_TYPE_P (TREE_TYPE (var)) + && TREE_TYPE (TREE_TYPE (var)) == TREE_TYPE (p)) + var_sub = build1 (INDIRECT_REF, TREE_TYPE (p), var); + else + var_sub = var; + /* Register the VAR_DECL as the equivalent for the PARM_DECL; that way, when the PARM_DECL is encountered, it will be automatically replaced by the VAR_DECL. */ splay_tree_insert (id->decl_map, (splay_tree_key) p, - (splay_tree_value) var); + (splay_tree_value) var_sub); /* Declare this new variable. */ #ifndef INLINER_FOR_JAVA @@ -4118,6 +4118,9 @@ bool variably_modified_type_p (type) tree type; { + if (type == error_mark_node) + return false; + /* If TYPE itself has variable size, it is variably modified. We do not yet have a representation of the C99 '[*]' syntax. |