This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
Re: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
- From: Richard Biener <richard dot guenther at gmail dot com>
- To: "H.J. Lu" <hjl dot tools at gmail dot com>
- Cc: GCC Patches <gcc-patches at gcc dot gnu dot org>
- Date: Tue, 17 Nov 2015 13:22:06 +0100
- Subject: Re: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
- Authentication-results: sourceware.org; auth=none
- References: <1447758067-4440-1-git-send-email-hjl dot tools at gmail dot com>
On Tue, Nov 17, 2015 at 12:01 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
> 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.
Please avoid a new langhook for this and instead claim a bit in tree_type_common
like for example restrict_flag (double-check it is unused for non-pointers).
I don't like that you need to modify targets - those checks should be done
in the caller (which may just use a new wrapper with the logic and then
dispatching to the actual hook).
Why do you need do adjust get_ref_base_and_extent?
Thanks,
Richard.
> 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 <stdarg.h>
> +
> +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<typename _Tp, _Tp __v>
> +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<bool, true> 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);
> }
>
>
> --
> 2.4.3
>