From patchwork Tue Nov 17 11:01:07 2015 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "H.J. Lu" X-Patchwork-Id: 545508 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by ozlabs.org (Postfix) with ESMTPS id 41AE0141420 for ; Tue, 17 Nov 2015 22:01:25 +1100 (AEDT) Authentication-Results: ozlabs.org; dkim=pass (1024-bit key; unprotected) header.d=gcc.gnu.org header.i=@gcc.gnu.org header.b=NIr46GTu; dkim-atps=neutral DomainKey-Signature: a=rsa-sha1; c=nofws; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id; q=dns; s=default; b=OqVj0PZnHyCeQa0 rchxn2QhrXTbEdvy5D4quPjmxJ1TEoJW98VqNQGAaYMw+ZGPSj6I+zelyXFJi1d1 Dfr/prt5pL+TWEaYFC6MxXPKhQWpNrs/az+0s9+LOXb7rkdQvILiyNAbg9dNvu1k pVYfppKiyoUW1Lj2Rf2eK8dOvpIc= DKIM-Signature: v=1; a=rsa-sha1; c=relaxed; d=gcc.gnu.org; h=list-id :list-unsubscribe:list-archive:list-post:list-help:sender:from :to:subject:date:message-id; s=default; bh=Jf0CUvsqtJ5ONS46zU8MF n+OdKg=; b=NIr46GTudymfbuvD0pCIBLAg7Gc3kSeEZYksjt51K74Y8sn849Ndf x77gkKemYBMxm+Egc8xTpsK8A6fJdjW7JqDSFgKPJY5d5+CduvhR9JwkQH1mU3If 6W2mJNsJd4hpyaOit5VPfOJbr3NTEtoh5VNJ8dp03vl8mcxbVl4VAU= Received: (qmail 52525 invoked by alias); 17 Nov 2015 11:01:14 -0000 Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org Received: (qmail 52491 invoked by uid 89); 17 Nov 2015 11:01:13 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-0.5 required=5.0 tests=AWL, BAYES_00, FREEMAIL_FROM, SPF_SOFTFAIL autolearn=no version=3.3.2 X-HELO: mga03.intel.com Received: from mga03.intel.com (HELO mga03.intel.com) (134.134.136.65) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 17 Nov 2015 11:01:10 +0000 Received: from orsmga003.jf.intel.com ([10.7.209.27]) by orsmga103.jf.intel.com with ESMTP; 17 Nov 2015 03:01:07 -0800 X-ExtLoop1: 1 Received: from gnu-6.sc.intel.com ([172.25.70.52]) by orsmga003.jf.intel.com with ESMTP; 17 Nov 2015 03:01:07 -0800 From: "H.J. Lu" To: gcc-patches@gcc.gnu.org Subject: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class Date: Tue, 17 Nov 2015 03:01:07 -0800 Message-Id: <1447758067-4440-1-git-send-email-hjl.tools@gmail.com> X-IsSubscribed: yes Empty record should be returned and passed the same way in C and C++. This patch adds LANG_HOOKS_EMPTY_RECORD_P for C++ empty class, which defaults to return false. For C++, LANG_HOOKS_EMPTY_RECORD_P is defined to is_really_empty_class, which returns true for C++ empty classes. For LTO, we stream out a bit to indicate if a record is empty and we store it in TYPE_LANG_FLAG_0 when streaming in. get_ref_base_and_extent is changed to set bitsize to 0 for empty records. Middle-end and x86 backend are updated to ignore empty records for parameter passing and function value return. Other targets may need similar changes. gcc/ PR c++/60336 PR middle-end/67239 PR target/68355 * calls.c (store_one_arg): Use 0 for empty record size. Don't push 0 size argument onto stack. (must_pass_in_stack_var_size_or_pad): Return false for empty record. * function.c (locate_and_pad_parm): Use 0 for empty record size. * tree-dfa.c (get_ref_base_and_extent): Likewise. * langhooks-def.h (LANG_HOOKS_EMPTY_RECORD_P): New. (LANG_HOOKS_DECLS): Add LANG_HOOKS_EMPTY_RECORD_P. * langhooks.h (lang_hooks_for_decls): Add empty_record_p. * lto-streamer.h (LTO_major_version): Increase by 1 to 6. * targhooks.c: Include "langhooks.h". (std_gimplify_va_arg_expr): Use 0 for empty record size. * tree-streamer-in.c (unpack_ts_base_value_fields): Stream in TYPE_LANG_FLAG_0. * tree-streamer-out.c: Include "langhooks.h". (pack_ts_base_value_fields): Stream out a bit to indicate if a record is empty. * config/i386/i386.c (classify_argument): Return 0 for empty record. (construct_container): Return NULL for empty record. (ix86_function_arg): Likewise. (ix86_function_arg_advance): Skip empty record. (ix86_return_in_memory): Return false for empty record. (ix86_gimplify_va_arg): Use 0 for empty record size. gcc/cp/ PR c++/60336 PR middle-end/67239 PR target/68355 * class.c (is_empty_class): Changed to return bool and take const_tree. (is_really_empty_class): Changed to take const_tree. Check if TYPE_BINFO is zero. * cp-tree.h (is_empty_class): Updated. (is_really_empty_class): Likewise. * cp-lang.c (LANG_HOOKS_EMPTY_RECORD_P): New. gcc/lto/ PR c++/60336 PR middle-end/67239 PR target/68355 * lto-lang.c (lto_empty_record_p): New. (LANG_HOOKS_EMPTY_RECORD_P): Likewise. gcc/testsuite/ PR c++/60336 PR middle-end/67239 PR target/68355 * g++.dg/abi/empty12.C: New test. * g++.dg/abi/empty12.h: Likewise. * g++.dg/abi/empty12a.c: Likewise. * g++.dg/pr60336-1.C: Likewise. * g++.dg/pr60336-2.C: Likewise. * g++.dg/pr68355.C: Likewise. --- gcc/calls.c | 41 +++++++++++++++++++++++++++---------- gcc/config/i386/i386.c | 18 +++++++++++++++- gcc/cp/class.c | 17 ++++++++------- gcc/cp/cp-lang.c | 2 ++ gcc/cp/cp-tree.h | 4 ++-- gcc/function.c | 7 +++++-- gcc/langhooks-def.h | 2 ++ gcc/langhooks.h | 3 +++ gcc/lto-streamer.h | 2 +- gcc/lto/lto-lang.c | 13 ++++++++++++ gcc/targhooks.c | 6 +++++- gcc/testsuite/g++.dg/abi/empty12.C | 17 +++++++++++++++ gcc/testsuite/g++.dg/abi/empty12.h | 9 ++++++++ gcc/testsuite/g++.dg/abi/empty12a.c | 6 ++++++ gcc/testsuite/g++.dg/pr60336-1.C | 17 +++++++++++++++ gcc/testsuite/g++.dg/pr60336-2.C | 28 +++++++++++++++++++++++++ gcc/testsuite/g++.dg/pr68355.C | 24 ++++++++++++++++++++++ gcc/tree-dfa.c | 2 ++ gcc/tree-streamer-in.c | 5 +++++ gcc/tree-streamer-out.c | 6 ++++++ 20 files changed, 204 insertions(+), 25 deletions(-) create mode 100644 gcc/testsuite/g++.dg/abi/empty12.C create mode 100644 gcc/testsuite/g++.dg/abi/empty12.h create mode 100644 gcc/testsuite/g++.dg/abi/empty12a.c create mode 100644 gcc/testsuite/g++.dg/pr60336-1.C create mode 100644 gcc/testsuite/g++.dg/pr60336-2.C create mode 100644 gcc/testsuite/g++.dg/pr68355.C diff --git a/gcc/calls.c b/gcc/calls.c index b56556a..ecc9b7a 100644 --- a/gcc/calls.c +++ b/gcc/calls.c @@ -4835,7 +4835,10 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, Note that in C the default argument promotions will prevent such mismatches. */ - size = GET_MODE_SIZE (arg->mode); + if (lang_hooks.decls.empty_record_p (TREE_TYPE (pval))) + size = 0; + else + size = GET_MODE_SIZE (arg->mode); /* Compute how much space the push instruction will push. On many machines, pushing a byte will advance the stack pointer by a halfword. */ @@ -4865,10 +4868,14 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, /* This isn't already where we want it on the stack, so put it there. This can either be done with push or copy insns. */ - if (!emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), NULL_RTX, - parm_align, partial, reg, used - size, argblock, - ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space, - ARGS_SIZE_RTX (arg->locate.alignment_pad), true)) + if (used + && !emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), + NULL_RTX, parm_align, partial, reg, + used - size, argblock, + ARGS_SIZE_RTX (arg->locate.offset), + reg_parm_stack_space, + ARGS_SIZE_RTX (arg->locate.alignment_pad), + true)) sibcall_failure = 1; /* Unless this is a partially-in-register argument, the argument is now @@ -4900,10 +4907,16 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, { /* PUSH_ROUNDING has no effect on us, because emit_push_insn for BLKmode is careful to avoid it. */ + bool empty_record + = lang_hooks.decls.empty_record_p (TREE_TYPE (pval)); excess = (arg->locate.size.constant - - int_size_in_bytes (TREE_TYPE (pval)) + - (empty_record + ? 0 + : int_size_in_bytes (TREE_TYPE (pval))) + partial); - size_rtx = expand_expr (size_in_bytes (TREE_TYPE (pval)), + size_rtx = expand_expr ((empty_record + ? size_zero_node + : size_in_bytes (TREE_TYPE (pval))), NULL_RTX, TYPE_MODE (sizetype), EXPAND_NORMAL); } @@ -4971,10 +4984,13 @@ store_one_arg (struct arg_data *arg, rtx argblock, int flags, } } - emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), size_rtx, - parm_align, partial, reg, excess, argblock, - ARGS_SIZE_RTX (arg->locate.offset), reg_parm_stack_space, - ARGS_SIZE_RTX (arg->locate.alignment_pad), false); + if (!CONST_INT_P (size_rtx) || INTVAL (size_rtx) != 0) + emit_push_insn (arg->value, arg->mode, TREE_TYPE (pval), + size_rtx, parm_align, partial, reg, excess, + argblock, ARGS_SIZE_RTX (arg->locate.offset), + reg_parm_stack_space, + ARGS_SIZE_RTX (arg->locate.alignment_pad), + false); /* Unless this is a partially-in-register argument, the argument is now in the stack. @@ -5052,6 +5068,9 @@ must_pass_in_stack_var_size_or_pad (machine_mode mode, const_tree type) if (TREE_ADDRESSABLE (type)) return true; + if (lang_hooks.decls.empty_record_p (type)) + return false; + /* If the padding and mode of the type is such that a copy into a register would put it into the wrong part of the register. */ if (mode == BLKmode diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c index 6173dae..8bd6198 100644 --- a/gcc/config/i386/i386.c +++ b/gcc/config/i386/i386.c @@ -7920,6 +7920,9 @@ static int classify_argument (machine_mode mode, const_tree type, enum x86_64_reg_class classes[MAX_CLASSES], int bit_offset) { + if (type && lang_hooks.decls.empty_record_p (type)) + return 0; + HOST_WIDE_INT bytes = (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode); int words = CEIL (bytes + (bit_offset % 64) / 8, UNITS_PER_WORD); @@ -8371,6 +8374,9 @@ construct_container (machine_mode mode, machine_mode orig_mode, static bool issued_sse_ret_error; static bool issued_x87_ret_error; + if (type && lang_hooks.decls.empty_record_p (type)) + return NULL; + machine_mode tmpmode; int bytes = (mode == BLKmode) ? int_size_in_bytes (type) : (int) GET_MODE_SIZE (mode); @@ -8783,6 +8789,9 @@ ix86_function_arg_advance (cumulative_args_t cum_v, machine_mode mode, HOST_WIDE_INT bytes, words; int nregs; + if (type && lang_hooks.decls.empty_record_p (type)) + return; + if (mode == BLKmode) bytes = int_size_in_bytes (type); else @@ -9099,6 +9108,9 @@ ix86_function_arg (cumulative_args_t cum_v, machine_mode omode, HOST_WIDE_INT bytes, words; rtx arg; + if (type && lang_hooks.decls.empty_record_p (type)) + return NULL; + /* All pointer bounds arguments are handled separately here. */ if ((type && POINTER_BOUNDS_TYPE_P (type)) || POINTER_BOUNDS_MODE_P (mode)) @@ -9708,6 +9720,9 @@ ix86_return_in_memory (const_tree type, const_tree fntype ATTRIBUTE_UNUSED) if (POINTER_BOUNDS_TYPE_P (type)) return false; + if (type && lang_hooks.decls.empty_record_p (type)) + return false; + if (TARGET_64BIT) { if (ix86_function_type_abi (fntype) == MS_ABI) @@ -10266,7 +10281,8 @@ ix86_gimplify_va_arg (tree valist, tree type, gimple_seq *pre_p, indirect_p = pass_by_reference (NULL, TYPE_MODE (type), type, false); if (indirect_p) type = build_pointer_type (type); - size = int_size_in_bytes (type); + bool empty_record = type && lang_hooks.decls.empty_record_p (type); + size = empty_record ? 0 : int_size_in_bytes (type); rsize = CEIL (size, UNITS_PER_WORD); nat_mode = type_natural_mode (type, NULL, false); diff --git a/gcc/cp/class.c b/gcc/cp/class.c index 216a301..c380734 100644 --- a/gcc/cp/class.c +++ b/gcc/cp/class.c @@ -8068,8 +8068,8 @@ build_self_reference (void) /* Returns 1 if TYPE contains only padding bytes. */ -int -is_empty_class (tree type) +bool +is_empty_class (const_tree type) { if (type == error_mark_node) return 0; @@ -8084,7 +8084,7 @@ is_empty_class (tree type) possible combinations of empty classes and possibly a vptr. */ bool -is_really_empty_class (tree type) +is_really_empty_class (const_tree type) { if (CLASS_TYPE_P (type)) { @@ -8098,10 +8098,13 @@ is_really_empty_class (tree type) if (COMPLETE_TYPE_P (type) && is_empty_class (type)) return true; - for (binfo = TYPE_BINFO (type), i = 0; - BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i) - if (!is_really_empty_class (BINFO_TYPE (base_binfo))) - return false; + /* TYPE_BINFO may be zeron when is_really_empty_class is called + from LANG_HOOKS_EMPTY_RECORD_P. */ + binfo = TYPE_BINFO (type); + if (binfo) + for (i = 0; BINFO_BASE_ITERATE (binfo, i, base_binfo); ++i) + if (!is_really_empty_class (BINFO_TYPE (base_binfo))) + return false; for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field)) if (TREE_CODE (field) == FIELD_DECL && !DECL_ARTIFICIAL (field) diff --git a/gcc/cp/cp-lang.c b/gcc/cp/cp-lang.c index 048108d..80174cb 100644 --- a/gcc/cp/cp-lang.c +++ b/gcc/cp/cp-lang.c @@ -78,6 +78,8 @@ static tree cxx_enum_underlying_base_type (const_tree); #define LANG_HOOKS_EH_RUNTIME_TYPE build_eh_type_type #undef LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE #define LANG_HOOKS_ENUM_UNDERLYING_BASE_TYPE cxx_enum_underlying_base_type +#undef LANG_HOOKS_EMPTY_RECORD_P +#define LANG_HOOKS_EMPTY_RECORD_P is_really_empty_class /* Each front end provides its own lang hook initializer. */ struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h index 84437b4..dc79979 100644 --- a/gcc/cp/cp-tree.h +++ b/gcc/cp/cp-tree.h @@ -5578,8 +5578,8 @@ extern tree finish_struct (tree, tree); extern void finish_struct_1 (tree); extern int resolves_to_fixed_type_p (tree, int *); extern void init_class_processing (void); -extern int is_empty_class (tree); -extern bool is_really_empty_class (tree); +extern bool is_empty_class (const_tree); +extern bool is_really_empty_class (const_tree); extern void pushclass (tree); extern void popclass (void); extern void push_nested_class (tree); diff --git a/gcc/function.c b/gcc/function.c index afc2c87..b59157d 100644 --- a/gcc/function.c +++ b/gcc/function.c @@ -4093,8 +4093,11 @@ locate_and_pad_parm (machine_mode passed_mode, tree type, int in_regs, part_size_in_regs = (reg_parm_stack_space == 0 ? partial : 0); - sizetree - = type ? size_in_bytes (type) : size_int (GET_MODE_SIZE (passed_mode)); + if (type) + sizetree = (lang_hooks.decls.empty_record_p (type) + ? size_zero_node : size_in_bytes (type)); + else + sizetree = size_int (GET_MODE_SIZE (passed_mode)); where_pad = FUNCTION_ARG_PADDING (passed_mode, type); boundary = targetm.calls.function_arg_boundary (passed_mode, type); round_boundary = targetm.calls.function_arg_round_boundary (passed_mode, diff --git a/gcc/langhooks-def.h b/gcc/langhooks-def.h index 18ac84d..df4cbf8 100644 --- a/gcc/langhooks-def.h +++ b/gcc/langhooks-def.h @@ -163,6 +163,7 @@ extern tree lhd_make_node (enum tree_code); #define LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P hook_bool_const_tree_false #define LANG_HOOKS_FUNCTION_PARM_EXPANDED_FROM_PACK_P \ hook_bool_tree_tree_false +#define LANG_HOOKS_EMPTY_RECORD_P hook_bool_const_tree_false #define LANG_HOOKS_GET_GENERIC_FUNCTION_DECL hook_tree_const_tree_null #define LANG_HOOKS_TYPE_PROMOTES_TO lhd_type_promotes_to #define LANG_HOOKS_REGISTER_BUILTIN_TYPE lhd_register_builtin_type @@ -228,6 +229,7 @@ extern tree lhd_make_node (enum tree_code); LANG_HOOKS_FUNCTION_DECL_DELETED_P, \ LANG_HOOKS_GENERIC_GENERIC_PARAMETER_DECL_P, \ LANG_HOOKS_FUNCTION_PARM_EXPANDED_FROM_PACK_P, \ + LANG_HOOKS_EMPTY_RECORD_P, \ LANG_HOOKS_GET_GENERIC_FUNCTION_DECL, \ LANG_HOOKS_WARN_UNUSED_GLOBAL_DECL, \ LANG_HOOKS_POST_COMPILATION_PARSING_CLEANUPS, \ diff --git a/gcc/langhooks.h b/gcc/langhooks.h index d8d01fa..450bdee 100644 --- a/gcc/langhooks.h +++ b/gcc/langhooks.h @@ -177,6 +177,9 @@ struct lang_hooks_for_decls function parameter pack. */ bool (*function_parm_expanded_from_pack_p) (tree, tree); + /* Determine if a type is an empty record. */ + bool (*empty_record_p) (const_tree type); + /* Returns the generic declaration of a generic function instantiations. */ tree (*get_generic_function_decl) (const_tree); diff --git a/gcc/lto-streamer.h b/gcc/lto-streamer.h index 5aae9e9..cc4cede 100644 --- a/gcc/lto-streamer.h +++ b/gcc/lto-streamer.h @@ -128,7 +128,7 @@ along with GCC; see the file COPYING3. If not see String are represented in the table as pairs, a length in ULEB128 form followed by the data for the string. */ -#define LTO_major_version 5 +#define LTO_major_version 6 #define LTO_minor_version 0 typedef unsigned char lto_decl_flags_t; diff --git a/gcc/lto/lto-lang.c b/gcc/lto/lto-lang.c index 53dd8f6..dc849a4 100644 --- a/gcc/lto/lto-lang.c +++ b/gcc/lto/lto-lang.c @@ -1306,6 +1306,16 @@ static void lto_init_ts (void) tree_contains_struct[NAMESPACE_DECL][TS_DECL_MINIMAL] = 1; } +/* Return true if TYPE contains no actual data, just various possible + combinations of empty records. */ + +static bool +lto_empty_record_p (const_tree type) +{ + /* Set if a record is empty. */ + return TYPE_LANG_FLAG_0 (type); +} + #undef LANG_HOOKS_NAME #define LANG_HOOKS_NAME "GNU GIMPLE" #undef LANG_HOOKS_OPTION_LANG_MASK @@ -1363,6 +1373,9 @@ static void lto_init_ts (void) #undef LANG_HOOKS_INIT_TS #define LANG_HOOKS_INIT_TS lto_init_ts +#undef LANG_HOOKS_EMPTY_RECORD_P +#define LANG_HOOKS_EMPTY_RECORD_P lto_empty_record_p + struct lang_hooks lang_hooks = LANG_HOOKS_INITIALIZER; /* Language hooks that are not part of lang_hooks. */ diff --git a/gcc/targhooks.c b/gcc/targhooks.c index c34b4e9..5e74dd9 100644 --- a/gcc/targhooks.c +++ b/gcc/targhooks.c @@ -74,6 +74,7 @@ along with GCC; see the file COPYING3. If not see #include "intl.h" #include "opts.h" #include "gimplify.h" +#include "langhooks.h" bool @@ -1823,9 +1824,12 @@ std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, /* Hoist the valist value into a temporary for the moment. */ valist_tmp = get_initialized_tmp_var (valist, pre_p, NULL); + bool empty_record = lang_hooks.decls.empty_record_p (type); + /* va_list pointer is aligned to PARM_BOUNDARY. If argument actually requires greater alignment, we must perform dynamic alignment. */ if (boundary > align + && !empty_record && !integer_zerop (TYPE_SIZE (type))) { t = build2 (MODIFY_EXPR, TREE_TYPE (valist), valist_tmp, @@ -1852,7 +1856,7 @@ std_gimplify_va_arg_expr (tree valist, tree type, gimple_seq *pre_p, } /* Compute the rounded size of the type. */ - type_size = size_in_bytes (type); + type_size = empty_record ? size_zero_node : size_in_bytes (type); rounded_size = round_up (type_size, align); /* Reduce rounded_size so it's sharable with the postqueue. */ diff --git a/gcc/testsuite/g++.dg/abi/empty12.C b/gcc/testsuite/g++.dg/abi/empty12.C new file mode 100644 index 0000000..430d57d --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/empty12.C @@ -0,0 +1,17 @@ +// PR c++/60336 +// { dg-do run } +// { dg-options "-x c" } +// { dg-additional-sources "empty12a.c" } +// { dg-prune-output "command line option" } + +#include "empty12.h" +extern "C" void fun(struct dummy, struct foo); + +int main() +{ + struct dummy d; + struct foo f = { -1, -2, -3, -4, -5 }; + + fun(d, f); + return 0; +} diff --git a/gcc/testsuite/g++.dg/abi/empty12.h b/gcc/testsuite/g++.dg/abi/empty12.h new file mode 100644 index 0000000..c61afcd --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/empty12.h @@ -0,0 +1,9 @@ +struct dummy { }; +struct foo +{ + int i1; + int i2; + int i3; + int i4; + int i5; +}; diff --git a/gcc/testsuite/g++.dg/abi/empty12a.c b/gcc/testsuite/g++.dg/abi/empty12a.c new file mode 100644 index 0000000..34a25ba --- /dev/null +++ b/gcc/testsuite/g++.dg/abi/empty12a.c @@ -0,0 +1,6 @@ +#include "empty12.h" +void fun(struct dummy d, struct foo f) +{ + if (f.i1 != -1) + __builtin_abort(); +} diff --git a/gcc/testsuite/g++.dg/pr60336-1.C b/gcc/testsuite/g++.dg/pr60336-1.C new file mode 100644 index 0000000..af08638 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr60336-1.C @@ -0,0 +1,17 @@ +// { dg-do compile } +// { dg-options "-O2 -std=c++11 -fno-pic" } +// { dg-require-effective-target fpic } + +struct dummy { }; +struct true_type { struct dummy i; }; + +extern true_type y; +extern void xxx (true_type c); + +void +yyy (void) +{ + xxx (y); +} + +// { dg-final { scan-assembler "jmp\[\t \]+\[^\$\]*?_Z3xxx9true_type" { target i?86-*-* x86_64-*-* } } } diff --git a/gcc/testsuite/g++.dg/pr60336-2.C b/gcc/testsuite/g++.dg/pr60336-2.C new file mode 100644 index 0000000..7b902e8 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr60336-2.C @@ -0,0 +1,28 @@ +// { dg-do run } +// { dg-options "-O2" } + +#include + +struct dummy { struct{}__attribute__((aligned (4))) a[7]; }; + +void +test (struct dummy a, ...) +{ + va_list va_arglist; + int i; + + va_start (va_arglist, a); + i = va_arg (va_arglist, int); + if (i != 0x10) + __builtin_abort (); + va_end (va_arglist); +} + +struct dummy a0; + +int +main () +{ + test (a0, 0x10); + return 0; +} diff --git a/gcc/testsuite/g++.dg/pr68355.C b/gcc/testsuite/g++.dg/pr68355.C new file mode 100644 index 0000000..1354fc4 --- /dev/null +++ b/gcc/testsuite/g++.dg/pr68355.C @@ -0,0 +1,24 @@ +// { dg-do compile } +// { dg-options "-O2 -std=c++11 -fno-pic" } +// { dg-require-effective-target fpic } + +template +struct integral_constant +{ + static constexpr _Tp value = __v; + typedef _Tp value_type; + typedef integral_constant<_Tp, __v> type; + constexpr operator value_type() const { return value; } +}; + +typedef integral_constant true_type; +extern void xxx (true_type c); + +void +yyy (void) +{ + true_type y; + xxx (y); +} + +// { dg-final { scan-assembler "jmp\[\t \]+\[^\$\]*?_Z3xxx17integral_constantIbLb1EE" { target i?86-*-* x86_64-*-* } } } diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c index bb5cd49..6b1e25d 100644 --- a/gcc/tree-dfa.c +++ b/gcc/tree-dfa.c @@ -394,6 +394,8 @@ get_ref_base_and_extent (tree exp, HOST_WIDE_INT *poffset, machine_mode mode = TYPE_MODE (TREE_TYPE (exp)); if (mode == BLKmode) size_tree = TYPE_SIZE (TREE_TYPE (exp)); + else if (lang_hooks.decls.empty_record_p (TREE_TYPE (exp))) + bitsize = 0; else bitsize = int (GET_MODE_PRECISION (mode)); } diff --git a/gcc/tree-streamer-in.c b/gcc/tree-streamer-in.c index 65a1ce3..1c32d81 100644 --- a/gcc/tree-streamer-in.c +++ b/gcc/tree-streamer-in.c @@ -154,6 +154,11 @@ unpack_ts_base_value_fields (struct bitpack_d *bp, tree expr) } else bp_unpack_value (bp, 9); + if (TYPE_P (expr)) + /* Set if a record is empty. */ + TYPE_LANG_FLAG_0 (expr) = (unsigned) bp_unpack_value (bp, 1); + else + bp_unpack_value (bp, 1); } diff --git a/gcc/tree-streamer-out.c b/gcc/tree-streamer-out.c index d0b7f6d..a1bf962 100644 --- a/gcc/tree-streamer-out.c +++ b/gcc/tree-streamer-out.c @@ -31,6 +31,7 @@ along with GCC; see the file COPYING3. If not see #include "alias.h" #include "stor-layout.h" #include "gomp-constants.h" +#include "langhooks.h" /* Output the STRING constant to the string @@ -128,6 +129,11 @@ pack_ts_base_value_fields (struct bitpack_d *bp, tree expr) } else bp_pack_value (bp, 0, 9); + if (TYPE_P (expr)) + /* Stream out a bit to indicate if a record is empty. */ + bp_pack_value (bp, lang_hooks.decls.empty_record_p (expr), 1); + else + bp_pack_value (bp, 0, 1); }