From d8472c75e8f6cdeabb60e2d743e58fb7ab46fef6 Mon Sep 17 00:00:00 2001 From: Jason Merrill Date: Sun, 18 Jul 2004 01:44:18 -0400 Subject: [PATCH] re PR tree-optimization/16115 (double-destruction problem with argument passing via temporary (breaks auto_ptr)) PR c++/16115 * stor-layout.c (relayout_decl): New fn. * tree.h: Declare it. (DECL_BY_REFERENCE): New macro. * cp/call.c (type_passed_as): Make the invisible reference type __restrict. * cp/cp-gimplify.c (gimplify_cleanup_stmt): Rename to cp_genericize_r. Handle invisible reference lowering. (is_invisiref_parm): New fn. (cp_genericize): Adjust the types of invisible reference parms. Don't repeat the walk for clones. * cp/decl.c (store_parm_decls): Don't generate any code for clones. From-SVN: r84887 --- gcc/ChangeLog | 7 ++++ gcc/cp/ChangeLog | 12 +++++++ gcc/cp/call.c | 6 +++- gcc/cp/cp-gimplify.c | 77 ++++++++++++++++++++++++++++++++++++++------ gcc/cp/decl.c | 15 ++++++--- gcc/stor-layout.c | 14 ++++++++ gcc/tree.h | 17 ++++++++-- 7 files changed, 130 insertions(+), 18 deletions(-) diff --git a/gcc/ChangeLog b/gcc/ChangeLog index afea2890af8..e279ea24f10 100644 --- a/gcc/ChangeLog +++ b/gcc/ChangeLog @@ -1,3 +1,10 @@ +2004-07-17 Jason Merrill + + PR c++/16115 + * stor-layout.c (relayout_decl): New fn. + * tree.h: Declare it. + (DECL_BY_REFERENCE): New macro. + 2004-07-17 Eric Botcazou * libgcc2.c (__enable_execute_stack): New symbol. diff --git a/gcc/cp/ChangeLog b/gcc/cp/ChangeLog index 1e0bec12ccb..0108c295494 100644 --- a/gcc/cp/ChangeLog +++ b/gcc/cp/ChangeLog @@ -1,3 +1,15 @@ +2004-07-17 Jason Merrill + + PR c++/16115 + * call.c (type_passed_as): Make the invisible reference type + __restrict. + * cp-gimplify.c (gimplify_cleanup_stmt): Rename to + cp_genericize_r. Handle invisible reference lowering. + (is_invisiref_parm): New fn. + (cp_genericize): Adjust the types of invisible reference parms. + Don't repeat the walk for clones. + * decl.c (store_parm_decls): Don't generate any code for clones. + 2004-07-17 Joseph S. Myers * cp-tree.h (builtin_function): Declare. diff --git a/gcc/cp/call.c b/gcc/cp/call.c index d2a17d9a7ed..0e734b80179 100644 --- a/gcc/cp/call.c +++ b/gcc/cp/call.c @@ -4503,7 +4503,11 @@ type_passed_as (tree type) { /* Pass classes with copy ctors by invisible reference. */ if (TREE_ADDRESSABLE (type)) - type = build_reference_type (type); + { + type = build_reference_type (type); + /* There are no other pointers to this temporary. */ + type = build_qualified_type (type, TYPE_QUAL_RESTRICT); + } else if (targetm.calls.promote_prototypes (type) && INTEGRAL_TYPE_P (type) && COMPLETE_TYPE_P (type) diff --git a/gcc/cp/cp-gimplify.c b/gcc/cp/cp-gimplify.c index db88e052b4d..ed0a6a19d41 100644 --- a/gcc/cp/cp-gimplify.c +++ b/gcc/cp/cp-gimplify.c @@ -29,7 +29,7 @@ Software Foundation, 59 Temple Place - Suite 330, Boston, MA #include "c-common.h" #include "toplev.h" #include "tree-gimple.h" - +#include "hashtab.h" /* Genericize a TRY_BLOCK. */ @@ -264,31 +264,88 @@ cp_gimplify_expr (tree *expr_p, tree *pre_p, tree *post_p) return ret; } -/* Genericize a CLEANUP_STMT. This just turns into a TRY_FINALLY or - TRY_CATCH depending on whether it's EH-only. */ +static inline bool +is_invisiref_parm (tree t) +{ + return (TREE_CODE (t) == PARM_DECL + && DECL_BY_REFERENCE (t)); +} + +/* Perform any pre-gimplification lowering of C++ front end trees to + GENERIC. */ static tree -gimplify_cleanup_stmt (tree *stmt_p, int *walk_subtrees, - void *data ATTRIBUTE_UNUSED) +cp_genericize_r (tree *stmt_p, int *walk_subtrees, void *data) { tree stmt = *stmt_p; + htab_t htab = (htab_t) data; + void **slot; - if (DECL_P (stmt) || TYPE_P (stmt)) + if (is_invisiref_parm (stmt)) + { + *stmt_p = build_fold_indirect_ref (stmt); + *walk_subtrees = 0; + return NULL; + } + + /* Other than invisiref parms, don't walk the same tree twice. */ + slot = htab_find_slot (htab, stmt, INSERT); + if (*slot) + { + *walk_subtrees = 0; + return NULL_TREE; + } + + if (TREE_CODE (stmt) == ADDR_EXPR + && is_invisiref_parm (TREE_OPERAND (stmt, 0))) + { + *stmt_p = convert (TREE_TYPE (stmt), TREE_OPERAND (stmt, 0)); + *walk_subtrees = 0; + } + else if (DECL_P (stmt) || TYPE_P (stmt)) *walk_subtrees = 0; + + /* Due to the way voidify_wrapper_expr is written, we don't get a chance + to lower this construct before scanning it, so we need to lower these + before doing anything else. */ else if (TREE_CODE (stmt) == CLEANUP_STMT) *stmt_p = build (CLEANUP_EH_ONLY (stmt) ? TRY_CATCH_EXPR : TRY_FINALLY_EXPR, void_type_node, CLEANUP_BODY (stmt), CLEANUP_EXPR (stmt)); + *slot = *stmt_p; return NULL; } void cp_genericize (tree fndecl) { - /* Due to the way voidify_wrapper_expr is written, we don't get a chance - to lower this construct before scanning it. So we need to lower these - before doing anything else. */ - walk_tree (&DECL_SAVED_TREE (fndecl), gimplify_cleanup_stmt, NULL, NULL); + tree t; + htab_t htab; + + /* Fix up the types of parms passed by invisible reference. */ + for (t = DECL_ARGUMENTS (fndecl); t; t = TREE_CHAIN (t)) + { + if (DECL_BY_REFERENCE (t)) + abort (); + if (TREE_ADDRESSABLE (TREE_TYPE (t))) + { + if (DECL_ARG_TYPE (t) == TREE_TYPE (t)) + abort (); + DECL_BY_REFERENCE (t) = 1; + TREE_TYPE (t) = DECL_ARG_TYPE (t); + relayout_decl (t); + } + } + + /* If we're a clone, the body is already GIMPLE. */ + if (DECL_CLONED_FUNCTION_P (fndecl)) + return; + + /* We do want to see every occurrence of the parms, so we can't just use + walk_tree's hash functionality. */ + htab = htab_create (37, htab_hash_pointer, htab_eq_pointer, NULL); + walk_tree (&DECL_SAVED_TREE (fndecl), cp_genericize_r, htab, NULL); + htab_delete (htab); /* Do everything else. */ c_genericize (fndecl); diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c index 6279eb5d9b7..874cfcba150 100644 --- a/gcc/cp/decl.c +++ b/gcc/cp/decl.c @@ -9991,11 +9991,16 @@ store_parm_decls (tree current_function_parms) DECL_ARGUMENTS is not modified. */ current_binding_level->names = chainon (nonparms, DECL_ARGUMENTS (fndecl)); - /* Do the starting of the exception specifications, if we have any. */ - if (flag_exceptions && !processing_template_decl - && flag_enforce_eh_specs - && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))) - current_eh_spec_block = begin_eh_spec_block (); + /* For a cloned function, we've already got all the code we need; + there's no need to add any extra bits. */ + if (!DECL_CLONED_FUNCTION_P (fndecl)) + { + /* Do the starting of the exception specifications, if we have any. */ + if (flag_exceptions && !processing_template_decl + && flag_enforce_eh_specs + && TYPE_RAISES_EXCEPTIONS (TREE_TYPE (current_function_decl))) + current_eh_spec_block = begin_eh_spec_block (); + } } diff --git a/gcc/stor-layout.c b/gcc/stor-layout.c index 689768536af..0ca26c238f7 100644 --- a/gcc/stor-layout.c +++ b/gcc/stor-layout.c @@ -524,6 +524,20 @@ layout_decl (tree decl, unsigned int known_align) SET_DECL_RTL (decl, rtl); } } + +/* Given a VAR_DECL, PARM_DECL or RESULT_DECL, clears the results of + a previous call to layout_decl and calls it again. */ + +void +relayout_decl (tree decl) +{ + DECL_SIZE (decl) = DECL_SIZE_UNIT (decl) = 0; + DECL_MODE (decl) = VOIDmode; + DECL_ALIGN (decl) = 0; + SET_DECL_RTL (decl, 0); + + layout_decl (decl, 0); +} /* Hook for a front-end function that can modify the record layout as needed immediately before it is finalized. */ diff --git a/gcc/tree.h b/gcc/tree.h index 31e117312fa..9871387c7e3 100644 --- a/gcc/tree.h +++ b/gcc/tree.h @@ -234,6 +234,8 @@ struct tree_common GTY(()) ..._DECL CALL_EXPR_HAS_RETURN_SLOT_ADDR in CALL_EXPR + DECL_BY_REFERENCE in + PARM_DECL, RESULT_DECL protected_flag: @@ -855,6 +857,10 @@ extern void tree_operand_check_failed (int, enum tree_code, argument list. */ #define CALL_EXPR_HAS_RETURN_SLOT_ADDR(NODE) ((NODE)->common.private_flag) +/* In a RESULT_DECL or PARM_DECL, means that it is passed by invisible + reference (and the TREE_TYPE is a pointer to the true type). */ +#define DECL_BY_REFERENCE(NODE) (DECL_CHECK (NODE)->common.private_flag) + /* In a CALL_EXPR, means that the call is the jump from a thunk to the thunked-to function. */ #define CALL_FROM_THUNK_P(NODE) ((NODE)->common.protected_flag) @@ -2976,6 +2982,11 @@ extern tree type_hash_canon (unsigned int, tree); extern void layout_decl (tree, unsigned); +/* Given a VAR_DECL, PARM_DECL or RESULT_DECL, clears the results of + a previous call to layout_decl and calls it again. */ + +extern void relayout_decl (tree); + /* Return the mode for data of a given size SIZE and mode class CLASS. If LIMIT is nonzero, then don't use modes bigger than MAX_FIXED_MODE_SIZE. The value is BLKmode if no other mode is found. This is like @@ -3659,11 +3670,13 @@ extern void dwarf2out_return_save (const char *, HOST_WIDE_INT); extern void dwarf2out_return_reg (const char *, unsigned); +/* In tree-inline.c */ + /* The type of a callback function for walking over tree structure. */ typedef tree (*walk_tree_fn) (tree *, int *, void *); -tree walk_tree (tree*, walk_tree_fn, void*, void*); -tree walk_tree_without_duplicates (tree*, walk_tree_fn, void*); +extern tree walk_tree (tree*, walk_tree_fn, void*, void*); +extern tree walk_tree_without_duplicates (tree*, walk_tree_fn, void*); /* In tree-dump.c */ -- 2.30.2