This is the mail archive of the
gcc-patches@gcc.gnu.org
mailing list for the GCC project.
[PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
- From: "H.J. Lu" <hjl dot tools at gmail dot com>
- To: gcc-patches at gcc dot gnu dot org
- Date: Tue, 17 Nov 2015 03:01:07 -0800
- Subject: [PATCH] Add LANG_HOOKS_EMPTY_RECORD_P for C++ empty class
- Authentication-results: sourceware.org; auth=none
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 <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