From: "H.J. Lu" <hjl.tools@gmail.com>
To: Richard Biener <richard.guenther@gmail.com>
Cc: Jason Merrill <jason@redhat.com>, GCC Patches <gcc-patches@gcc.gnu.org>
Subject: Re: PING^1: [PATCH] Add TYPE_EMPTY_RECORD for C++ empty class
Date: Wed, 09 Dec 2015 18:53:00 -0000 [thread overview]
Message-ID: <CAMe9rOrMC4XjhFW-a1TdGD2SJo7=yhtGX8r=KxLEyit1WLwpog@mail.gmail.com> (raw)
In-Reply-To: <CAFiYyc2Qx3DfTraZjUCR0Ha17++SNU-4d5SjGMSWn1hZWKK4uA@mail.gmail.com>
[-- Attachment #1: Type: text/plain, Size: 6815 bytes --]
On Wed, Dec 9, 2015 at 6:05 AM, Richard Biener
<richard.guenther@gmail.com> wrote:
> On Tue, Dec 8, 2015 at 5:22 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>> On Mon, Nov 23, 2015 at 12:53 PM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>> On Mon, Nov 23, 2015 at 1:57 AM, Richard Biener
>>> <richard.guenther@gmail.com> wrote:
>>>> On Sat, Nov 21, 2015 at 12:46 AM, H.J. Lu <hjl.tools@gmail.com> wrote:
>>>>> On Fri, Nov 20, 2015 at 2:17 PM, Jason Merrill <jason@redhat.com> wrote:
>>>>>> On 11/20/2015 01:52 PM, H.J. Lu wrote:
>>>>>>>
>>>>>>> On Tue, Nov 17, 2015 at 4:22 AM, Richard Biener
>>>>>>> <richard.guenther@gmail.com> wrote:
>>>>>>>>
>>>>>>>> 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).
>>>>>>>
>>>>>>>
>>>>>>> There is no bit in tree_type_common I can overload. restrict_flag is
>>>>>>> checked for non-pointers to issue an error when it is used on
>>>>>>> non-pointers:
>>>>>>>
>>>>>>>
>>>>>>> /export/gnu/import/git/sources/gcc/gcc/testsuite/g++.dg/template/qualttp20.C:19:38:
>>>>>>> error: ‘__restrict__’ qualifiers cannot be applied to ‘AS::L’
>>>>>>> typedef typename T::L __restrict__ r;// { dg-error "'__restrict__'
>>>>>>> qualifiers cannot" "" }
>>>>>>
>>>>>>
>>>>>> The C++ front end only needs to check TYPE_RESTRICT for this purpose on
>>>>>> front-end-specific type codes like TEMPLATE_TYPE_PARM; cp_type_quals could
>>>>>> handle that specifically if you change TYPE_RESTRICT to only apply to
>>>>>> pointers.
>>>>>>
>>>>>
>>>>> restrict_flag is also checked in this case:
>>>>>
>>>>> [hjl@gnu-6 gcc]$ cat x.i
>>>>> struct dummy { };
>>>>>
>>>>> struct dummy
>>>>> foo (struct dummy __restrict__ i)
>>>>> {
>>>>> return i;
>>>>> }
>>>>> [hjl@gnu-6 gcc]$ gcc -S x.i -Wall
>>>>> x.i:4:13: error: invalid use of ‘restrict’
>>>>> foo (struct dummy __restrict__ i)
>>>>> ^
>>>>> x.i:4:13: error: invalid use of ‘restrict’
>>>>> [hjl@gnu-6 gcc]$
>>>>>
>>>>> restrict_flag can't also be used to indicate `i' is an empty record.
>>>>
>>>> I'm sure this error can be done during parsing w/o relying on TYPE_RESTRICT.
>>>>
>>>> But well, use any other free bit (but do not enlarge
>>>> tree_type_common). Eventually
>>>> you can free up a bit by putting sth into type_lang_specific currently
>>>> using bits
>>>> in tree_type_common.
>>>
>>> There are no bits in tree_type_common I can move. Instead,
>>> this patch overloads side_effects_flag in tree_base. Tested on
>>> Linux/x86-64. OK for trunk?
>
> I'm fine with using side_effects_flag for this.
>
> I miss an explanation of where this detail of the ABI is documented and wonder
> if the term "empty record" is also used in that document and how it is
> documented.
>
> Thus
>
> +/* Nonzero in a type considered an empty record. */
> +#define TYPE_EMPTY_RECORD(NODE) \
> + (TYPE_CHECK (NODE)->base.side_effects_flag)
>
> should refer to the ABI where is defined what an "empty record" is and how
> it is handled by the backend(s).
Empty C++ class is a corner case which isn't covered in psABI nor C++ ABI.
There is no mention of "empty record" in GCC documentation. But there are
plenty of "empty class" in gcc/cp. This change affects all targets. C++ ABI
should specify how it should be passed.
> +/* Return true if type T is an empty record. */
> +
> +static inline bool
> +type_is_empty_record_p (const_tree t)
> +{
> + return TYPE_EMPTY_RECORD (TYPE_MAIN_VARIANT (t));
>
> the type checker should probably check the bit is consistent across
> variants so it can be tested on any of them.
TYPE_EMPTY_RECORD is only relevant for parameter passing. For
struct foo;
typedef foo bar;
TYPE_EMPTY_RECORD has no impact. Since call only uses
the main variant type, checking TYPE_MAIN_VARIANT is sufficient.
> You fail to adjust other targets gimplification hooks which suggests
> this is a detail of the x86 psABI and not the C++ ABI? If so I miss
> a -Wpsabi warning for this change.
My change is generic. The only x86 specific change is
diff --git a/gcc/config/i386/i386.c b/gcc/config/i386/i386.c
index d30fbff..308d9a4e 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -10292,7 +10292,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 && type_is_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);
which is for 64-bit variadic functions. I added a testcase,
g++.dg/pr60336-2.C, for it. There are also other variadic tests
in g++.dg/compat. If a target doesn't use std_gimplify_va_arg_expr,
it needs similar change. I see that TARGET_GIMPLIFY_VA_ARG_EXPR
is also defined in
aarch64/aarch64.c
alpha/alpha.c
arm/arm.c
epiphany/epiphany.c
ia64/ia64.c
mep/mep.c
mips/mips.c
msp430/msp430.c
pa/pa.c
rs6000/rs6000.c
s390/s390.c
sh/sh.c
sparc/sparc.c
spu/spu.c
stormy16/stormy16.c
tilegx/tilegx.c
tilepro/tilepro.c
visium/visium.c
xtensa/xtensa.c
I will prepare a separate patch for those targets to try.
> Did you investigate the effect of this patch on a larger code base?
I use it to bootstrap GCC.
> More specifically does it only affect variadic functions?
See above.
> An entry for changes.html is warranted as well.
>
>
I will prepare a patch for changes.html.
Here is the updated patch with -Wpsabi warning:
/export/gnu/import/git/sources/gcc/gcc/testsuite/g++.dg/abi/empty12.C:15:12:
note: the ABI of passing empty record has changed in GCC 6
Thanks.
--
H.J.
[-- Attachment #2: 0001-Add-TYPE_EMPTY_RECORD-for-C-empty-class.patch --]
[-- Type: text/x-patch, Size: 32635 bytes --]
From 3cb893e2c9c096ebea82fd7f72d52926a12d77e4 Mon Sep 17 00:00:00 2001
From: "H.J. Lu" <hjl.tools@gmail.com>
Date: Sun, 15 Nov 2015 13:19:05 -0800
Subject: [PATCH] Add TYPE_EMPTY_RECORD for C++ empty class
Empty record should be returned and passed the same way in C and C++.
This patch overloads a bit, side_effects_flag, in tree_base for C++
empty class. Middle-end and x86 backend are updated to ignore empty
records for parameter passing and function value return. Other targets
may need similar changes.
get_ref_base_and_extent is changed to set bitsize to 0 for empty records
so that when ref_maybe_used_by_call_p_1 calls get_ref_base_and_extent to
get 0 as the maximum size on empty record. Otherwise, find_tail_calls
won't perform tail call optimization for functions with empty record
parameters, as shown in g++.dg/pr60336-1.C and g++.dg/pr60336-2.C.
gcc/
PR c++/60336
PR middle-end/67239
PR target/68355
* calls.c (initialize_argument_information): Replace
targetm.calls.function_arg, targetm.calls.function_incoming_arg
and targetm.calls.function_arg_advance with function_arg,
function_incoming_arg and function_arg_advance.
(expand_call): Likewise.
(emit_library_call_value_1): Likewise.
(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.
* dse.c (get_call_args): Replace targetm.calls.function_arg
and targetm.calls.function_arg_advance with function_arg and
function_arg_advance.
* expr.c (block_move_libcall_safe_for_call_parm): Likewise.
* function.c (aggregate_value_p): Replace
targetm.calls.return_in_memory with return_in_memory.
(assign_parm_find_entry_rtl): Replace
targetm.calls.function_incoming_arg with function_incoming_arg.
(assign_parms): Replace targetm.calls.function_arg_advance with
function_arg_advance.
(gimplify_parameters): Replace targetm.calls.function_arg_advance
with function_arg_advance.
(locate_and_pad_parm): Use 0 for empty record size.
(warn_empty_record): New function.
(function_arg_advance): New wrapper function.
(function_arg): Likewise.
(function_incoming_arg): Likewise.
(return_in_memory): Likewise.
* lto-streamer-out.c (hash_tree): Call hstate.add_flag with
TYPE_EMPTY_RECORD for types.
* print-tree.c (print_node): Also handle TYPE_EMPTY_RECORD.
* ubsan.c (ubsan_type_descriptor): Likewise.
* target.h (function_arg_advance): New prototype.
(function_arg): Likewise.
(function_incoming_arg): Likewise.
(return_in_memory): Likewise.
* targhooks.c (std_gimplify_va_arg_expr): Use 0 for empty record
size.
* tree-dfa.c (get_ref_base_and_extent): Likewise.
* tree-core.h (tree_base): Mention TYPE_EMPTY_RECORD in comments
for side_effects_flag.
* tree-streamer-in.c (unpack_ts_base_value_fields): Stream in
TYPE_EMPTY_RECORD for types.
* tree-streamer-out.c (pack_ts_base_value_fields): Stream out
TYPE_EMPTY_RECORD for types.
* tree.h (TYPE_EMPTY_RECORD): New.
(type_is_empty_record_p): New static inline function.
* var-tracking.c (prepare_call_arguments): Replace
targetm.calls.function_arg and targetm.calls.function_arg_advance
with function_arg and function_arg_advance.
* config/i386/i386.c (ix86_gimplify_va_arg): Use 0 for empty
record size.
gcc/c
PR c++/60336
PR middle-end/67239
PR target/68355
* c-aux-info.c (gen_type): Add TYPE_EMPTY_RECORD check.
gcc/cp/
PR c++/60336
PR middle-end/67239
PR target/68355
* class.c (finish_struct_1): Set TYPE_EMPTY_RECORD with return
value from is_really_empty_class ().
gcc/lto/
PR c++/60336
PR middle-end/67239
PR target/68355
* lto.c (compare_tree_sccs_1): Call compare_values with
TYPE_EMPTY_RECORD for types.
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/c/c-aux-info.c | 2 +
gcc/calls.c | 76 ++++++++++++++++------------
gcc/config/i386/i386.c | 3 +-
gcc/cp/class.c | 2 +
gcc/dse.c | 4 +-
gcc/expr.c | 5 +-
gcc/function.c | 98 +++++++++++++++++++++++++++++++------
gcc/lto-streamer-out.c | 2 +
gcc/lto/lto.c | 2 +
gcc/print-tree.c | 3 ++
gcc/target.h | 8 +++
gcc/targhooks.c | 5 +-
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-core.h | 3 ++
gcc/tree-dfa.c | 2 +
gcc/tree-streamer-in.c | 5 +-
gcc/tree-streamer-out.c | 5 +-
gcc/tree.h | 12 +++++
gcc/ubsan.c | 3 +-
gcc/var-tracking.c | 18 +++----
25 files changed, 294 insertions(+), 65 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/c/c-aux-info.c b/gcc/c/c-aux-info.c
index 79d9851..93b001b 100644
--- a/gcc/c/c-aux-info.c
+++ b/gcc/c/c-aux-info.c
@@ -433,6 +433,8 @@ gen_type (const char *ret_val, tree t, formals_style style)
ret_val = concat ("volatile ", ret_val, NULL);
if (TYPE_RESTRICT (t))
ret_val = concat ("restrict ", ret_val, NULL);
+ if (TYPE_EMPTY_RECORD (t))
+ ret_val = concat ("empty-record ", ret_val, NULL);
return ret_val;
}
diff --git a/gcc/calls.c b/gcc/calls.c
index 1eb4ec7..557c51e 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -1399,8 +1399,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
args[i].unsignedp = unsignedp;
args[i].mode = mode;
- args[i].reg = targetm.calls.function_arg (args_so_far, mode, type,
- argpos < n_named_args);
+ args[i].reg = function_arg (args_so_far, mode, type,
+ argpos < n_named_args);
if (args[i].reg && CONST_INT_P (args[i].reg))
{
@@ -1413,8 +1413,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
arguments have to go into the incoming registers. */
if (targetm.calls.function_incoming_arg != targetm.calls.function_arg)
args[i].tail_call_reg
- = targetm.calls.function_incoming_arg (args_so_far, mode, type,
- argpos < n_named_args);
+ = function_incoming_arg (args_so_far, mode, type,
+ argpos < n_named_args);
else
args[i].tail_call_reg = args[i].reg;
@@ -1475,8 +1475,8 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
/* Increment ARGS_SO_FAR, which has info about which arg-registers
have been used, etc. */
- targetm.calls.function_arg_advance (args_so_far, TYPE_MODE (type),
- type, argpos < n_named_args);
+ function_arg_advance (args_so_far, TYPE_MODE (type), type,
+ argpos < n_named_args);
}
}
@@ -3328,14 +3328,11 @@ expand_call (tree exp, rtx target, int ignore)
/* Set up next argument register. For sibling calls on machines
with register windows this should be the incoming register. */
if (pass == 0)
- next_arg_reg = targetm.calls.function_incoming_arg (args_so_far,
- VOIDmode,
- void_type_node,
- true);
+ next_arg_reg = function_incoming_arg (args_so_far, VOIDmode,
+ void_type_node, true);
else
- next_arg_reg = targetm.calls.function_arg (args_so_far,
- VOIDmode, void_type_node,
- true);
+ next_arg_reg = function_arg (args_so_far, VOIDmode,
+ void_type_node, true);
if (pass == 1 && (return_flags & ERF_RETURNS_ARG))
{
@@ -3947,8 +3944,8 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
argvec[count].mode = Pmode;
argvec[count].partial = 0;
- argvec[count].reg = targetm.calls.function_arg (args_so_far,
- Pmode, NULL_TREE, true);
+ argvec[count].reg = function_arg (args_so_far, Pmode, NULL_TREE,
+ true);
gcc_assert (targetm.calls.arg_partial_bytes (args_so_far, Pmode,
NULL_TREE, 1) == 0);
@@ -3965,7 +3962,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
|| reg_parm_stack_space > 0)
args_size.constant += argvec[count].locate.size.constant;
- targetm.calls.function_arg_advance (args_so_far, Pmode, (tree) 0, true);
+ function_arg_advance (args_so_far, Pmode, (tree) 0, true);
count++;
}
@@ -4030,7 +4027,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
mode = promote_function_mode (NULL_TREE, mode, &unsigned_p, NULL_TREE, 0);
argvec[count].mode = mode;
argvec[count].value = convert_modes (mode, GET_MODE (val), val, unsigned_p);
- argvec[count].reg = targetm.calls.function_arg (args_so_far, mode,
+ argvec[count].reg = function_arg (args_so_far, mode,
NULL_TREE, true);
argvec[count].partial
@@ -4060,7 +4057,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
GET_MODE_SIZE (mode) <= UNITS_PER_WORD);
#endif
- targetm.calls.function_arg_advance (args_so_far, mode, (tree) 0, true);
+ function_arg_advance (args_so_far, mode, (tree) 0, true);
}
/* If this machine requires an external definition for library
@@ -4407,8 +4404,7 @@ emit_library_call_value_1 (int retval, rtx orgfun, rtx value,
build_function_type (tfom, NULL_TREE),
original_args_size.constant, args_size.constant,
struct_value_size,
- targetm.calls.function_arg (args_so_far,
- VOIDmode, void_type_node, true),
+ function_arg (args_so_far, VOIDmode, void_type_node, true),
valreg,
old_inhibit_defer_pop + 1, call_fusage, flags, args_so_far);
@@ -4843,7 +4839,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 (type_is_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. */
@@ -4873,10 +4872,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
@@ -4908,10 +4911,15 @@ 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 = type_is_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);
}
@@ -4986,10 +4994,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.
@@ -5067,6 +5078,9 @@ must_pass_in_stack_var_size_or_pad (machine_mode mode, const_tree type)
if (TREE_ADDRESSABLE (type))
return true;
+ if (type_is_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 d30fbff..308d9a4e 100644
--- a/gcc/config/i386/i386.c
+++ b/gcc/config/i386/i386.c
@@ -10292,7 +10292,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 && type_is_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..d97aae6 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -6802,6 +6802,8 @@ finish_struct_1 (tree t)
TYPE_TRANSPARENT_AGGR (t) = 0;
}
}
+
+ TYPE_EMPTY_RECORD (t) = is_really_empty_class (t);
}
/* Insert FIELDS into T for the sorted case if the FIELDS count is
diff --git a/gcc/dse.c b/gcc/dse.c
index 35eef71..594106f 100644
--- a/gcc/dse.c
+++ b/gcc/dse.c
@@ -2366,7 +2366,7 @@ get_call_args (rtx call_insn, tree fn, rtx *args, int nargs)
{
machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
rtx reg, link, tmp;
- reg = targetm.calls.function_arg (args_so_far, mode, NULL_TREE, true);
+ reg = function_arg (args_so_far, mode, NULL_TREE, true);
if (!reg || !REG_P (reg) || GET_MODE (reg) != mode
|| GET_MODE_CLASS (mode) != MODE_INT)
return false;
@@ -2400,7 +2400,7 @@ get_call_args (rtx call_insn, tree fn, rtx *args, int nargs)
if (tmp)
args[idx] = tmp;
- targetm.calls.function_arg_advance (args_so_far, mode, NULL_TREE, true);
+ function_arg_advance (args_so_far, mode, NULL_TREE, true);
}
if (arg != void_list_node || idx != nargs)
return false;
diff --git a/gcc/expr.c b/gcc/expr.c
index bd43dc4..384581a 100644
--- a/gcc/expr.c
+++ b/gcc/expr.c
@@ -1198,13 +1198,12 @@ block_move_libcall_safe_for_call_parm (void)
for ( ; arg != void_list_node ; arg = TREE_CHAIN (arg))
{
machine_mode mode = TYPE_MODE (TREE_VALUE (arg));
- rtx tmp = targetm.calls.function_arg (args_so_far, mode,
- NULL_TREE, true);
+ rtx tmp = function_arg (args_so_far, mode, NULL_TREE, true);
if (!tmp || !REG_P (tmp))
return false;
if (targetm.calls.arg_partial_bytes (args_so_far, mode, NULL, 1))
return false;
- targetm.calls.function_arg_advance (args_so_far, mode,
+ function_arg_advance (args_so_far, mode,
NULL_TREE, true);
}
}
diff --git a/gcc/function.c b/gcc/function.c
index b513ead..eccd968 100644
--- a/gcc/function.c
+++ b/gcc/function.c
@@ -2074,7 +2074,7 @@ aggregate_value_p (const_tree exp, const_tree fntype)
if (flag_pcc_struct_return && AGGREGATE_TYPE_P (type))
return 1;
- if (targetm.calls.return_in_memory (type, fntype))
+ if (return_in_memory (type, fntype))
return 1;
/* Make sure we have suitable call-clobbered regs to return
@@ -2524,10 +2524,10 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all,
return;
}
- entry_parm = targetm.calls.function_incoming_arg (all->args_so_far,
- data->promoted_mode,
- data->passed_type,
- data->named_arg);
+ entry_parm = function_incoming_arg (all->args_so_far,
+ data->promoted_mode,
+ data->passed_type,
+ data->named_arg);
if (entry_parm == 0)
data->promoted_mode = data->passed_mode;
@@ -2551,9 +2551,9 @@ assign_parm_find_entry_rtl (struct assign_parm_data_all *all,
if (targetm.calls.pretend_outgoing_varargs_named (all->args_so_far))
{
rtx tem;
- tem = targetm.calls.function_incoming_arg (all->args_so_far,
- data->promoted_mode,
- data->passed_type, true);
+ tem = function_incoming_arg (all->args_so_far,
+ data->promoted_mode,
+ data->passed_type, true);
in_regs = tem != NULL;
}
}
@@ -3791,8 +3791,8 @@ assign_parms (tree fndecl)
}
/* Update info on where next arg arrives in registers. */
- targetm.calls.function_arg_advance (all.args_so_far, data.promoted_mode,
- data.passed_type, data.named_arg);
+ function_arg_advance (all.args_so_far, data.promoted_mode,
+ data.passed_type, data.named_arg);
if (POINTER_BOUNDS_TYPE_P (data.passed_type))
bound_no++;
@@ -3988,8 +3988,8 @@ gimplify_parameters (void)
continue;
/* Update info on where next arg arrives in registers. */
- targetm.calls.function_arg_advance (all.args_so_far, data.promoted_mode,
- data.passed_type, data.named_arg);
+ function_arg_advance (all.args_so_far, data.promoted_mode,
+ data.passed_type, data.named_arg);
/* ??? Once upon a time variable_size stuffed parameter list
SAVE_EXPRs (amongst others) onto a pending sizes list. This
@@ -4132,8 +4132,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 = (type_is_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,
@@ -6862,5 +6865,72 @@ make_pass_match_asm_constraints (gcc::context *ctxt)
return new pass_match_asm_constraints (ctxt);
}
+static void
+warn_empty_record (void)
+{
+ if (warn_psabi)
+ inform (input_location, "the ABI of passing empty record has"
+ " changed in GCC 6");
+}
+
+/* Wrapper for targetm.calls.function_arg_advance. */
+
+void
+function_arg_advance (cumulative_args_t ca, machine_mode mode,
+ const_tree type, bool named)
+{
+ if (type && type_is_empty_record_p (type))
+ {
+ warn_empty_record ();
+ return;
+ }
+
+ targetm.calls.function_arg_advance (ca, mode, type, named);
+}
+
+/* Wrapper for targetm.calls.function_arg. */
+
+rtx
+function_arg (cumulative_args_t ca, machine_mode mode, const_tree type,
+ bool named)
+{
+ if (type && type_is_empty_record_p (type))
+ {
+ warn_empty_record ();
+ return NULL;
+ }
+
+ return targetm.calls.function_arg (ca, mode, type, named);
+}
+
+/* Wrapper for targetm.calls.function_incoming_arg. */
+
+rtx
+function_incoming_arg (cumulative_args_t ca, machine_mode mode,
+ const_tree type, bool named)
+{
+ if (type && type_is_empty_record_p (type))
+ {
+ warn_empty_record ();
+ return NULL;
+ }
+
+ return targetm.calls.function_incoming_arg (ca, mode, type, named);
+}
+
+/* Wrapper for targetm.calls.return_in_memory. */
+
+bool
+return_in_memory (const_tree type, const_tree fntype)
+{
+ if (type && type_is_empty_record_p (type))
+ {
+ warn_empty_record ();
+ return false;
+ }
+
+ return targetm.calls.return_in_memory (type, fntype);
+}
+
#include "gt-function.h"
diff --git a/gcc/lto-streamer-out.c b/gcc/lto-streamer-out.c
index a874846..509f0b3 100644
--- a/gcc/lto-streamer-out.c
+++ b/gcc/lto-streamer-out.c
@@ -944,6 +944,8 @@ hash_tree (struct streamer_tree_cache_d *cache, hash_map<tree, hashval_t> *map,
hstate.add_flag (TREE_READONLY (t));
hstate.add_flag (TREE_PUBLIC (t));
}
+ else
+ hstate.add_flag (TYPE_EMPTY_RECORD (t));
hstate.add_flag (TREE_ADDRESSABLE (t));
hstate.add_flag (TREE_THIS_VOLATILE (t));
if (DECL_P (t))
diff --git a/gcc/lto/lto.c b/gcc/lto/lto.c
index 90712b4..6755132 100644
--- a/gcc/lto/lto.c
+++ b/gcc/lto/lto.c
@@ -1002,6 +1002,8 @@ compare_tree_sccs_1 (tree t1, tree t2, tree **map)
compare_values (TREE_READONLY);
compare_values (TREE_PUBLIC);
}
+ else
+ compare_values (TYPE_EMPTY_RECORD);
compare_values (TREE_ADDRESSABLE);
compare_values (TREE_THIS_VOLATILE);
if (DECL_P (t1))
diff --git a/gcc/print-tree.c b/gcc/print-tree.c
index cb0f1fd..bb489ff 100644
--- a/gcc/print-tree.c
+++ b/gcc/print-tree.c
@@ -587,6 +587,9 @@ print_node (FILE *file, const char *prefix, tree node, int indent)
if (TYPE_RESTRICT (node))
fputs (" restrict", file);
+ if (TYPE_EMPTY_RECORD (node))
+ fputs (" empty-record", file);
+
if (TYPE_LANG_FLAG_0 (node))
fputs (" type_0", file);
if (TYPE_LANG_FLAG_1 (node))
diff --git a/gcc/target.h b/gcc/target.h
index ffc4d6a..eb01a76 100644
--- a/gcc/target.h
+++ b/gcc/target.h
@@ -104,6 +104,14 @@ extern bool target_default_pointer_address_modes_p (void);
behaviour. */
extern unsigned int get_move_ratio (bool);
+extern void function_arg_advance (cumulative_args_t, machine_mode,
+ const_tree, bool);
+extern rtx function_arg (cumulative_args_t, machine_mode, const_tree,
+ bool);
+extern rtx function_incoming_arg (cumulative_args_t, machine_mode,
+ const_tree, bool);
+extern bool return_in_memory (const_tree, const_tree);
+
struct stdarg_info;
struct spec_info_def;
struct hard_reg_set_container;
diff --git a/gcc/targhooks.c b/gcc/targhooks.c
index dcf0863..7a8d1e8 100644
--- a/gcc/targhooks.c
+++ b/gcc/targhooks.c
@@ -1827,9 +1827,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 = type_is_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,
@@ -1856,7 +1859,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..db2fd24
--- /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); // { dg-message "note: the ABI of passing empty record has changed in GCC 6" }
+ 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..2136f48
--- /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-message "note: the ABI of passing empty record has changed in GCC 6" }
+}
+
+// { 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..7ab7d23
--- /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, ...) // { dg-message "note: the ABI of passing empty record has changed in GCC 6" }
+{
+ 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); // { dg-message "note: the ABI of passing empty record has changed in GCC 6" }
+ return 0;
+}
diff --git a/gcc/testsuite/g++.dg/pr68355.C b/gcc/testsuite/g++.dg/pr68355.C
new file mode 100644
index 0000000..90584d0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr68355.C
@@ -0,0 +1,24 @@
+// { dg-do compile }
+// { dg-options "-Wno-psabi -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-core.h b/gcc/tree-core.h
index 9cc64d9..67bffa4 100644
--- a/gcc/tree-core.h
+++ b/gcc/tree-core.h
@@ -1086,6 +1086,9 @@ struct GTY(()) tree_base {
FORCED_LABEL in
LABEL_DECL
+ TYPE_EMPTY_RECORD in
+ all types
+
volatile_flag:
TREE_THIS_VOLATILE in
diff --git a/gcc/tree-dfa.c b/gcc/tree-dfa.c
index bb5cd49..1634ed6 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 (type_is_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 3162d1a..2aee7ad 100644
--- a/gcc/tree-streamer-in.c
+++ b/gcc/tree-streamer-in.c
@@ -112,7 +112,10 @@ unpack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
TREE_PUBLIC (expr) = (unsigned) bp_unpack_value (bp, 1);
}
else
- bp_unpack_value (bp, 4);
+ {
+ TYPE_EMPTY_RECORD (expr) = (unsigned) bp_unpack_value (bp, 1);
+ bp_unpack_value (bp, 3);
+ }
TREE_ADDRESSABLE (expr) = (unsigned) bp_unpack_value (bp, 1);
TREE_THIS_VOLATILE (expr) = (unsigned) bp_unpack_value (bp, 1);
if (DECL_P (expr))
diff --git a/gcc/tree-streamer-out.c b/gcc/tree-streamer-out.c
index bfd0644..4306fcc 100644
--- a/gcc/tree-streamer-out.c
+++ b/gcc/tree-streamer-out.c
@@ -83,7 +83,10 @@ pack_ts_base_value_fields (struct bitpack_d *bp, tree expr)
bp_pack_value (bp, TREE_PUBLIC (expr), 1);
}
else
- bp_pack_value (bp, 0, 4);
+ {
+ bp_pack_value (bp, TYPE_EMPTY_RECORD (expr), 1);
+ bp_pack_value (bp, 0, 3);
+ }
bp_pack_value (bp, TREE_ADDRESSABLE (expr), 1);
bp_pack_value (bp, TREE_THIS_VOLATILE (expr), 1);
if (DECL_P (expr))
diff --git a/gcc/tree.h b/gcc/tree.h
index aef825d..9b13d5c 100644
--- a/gcc/tree.h
+++ b/gcc/tree.h
@@ -766,6 +766,10 @@ extern void omp_clause_range_check_failed (const_tree, const char *, int,
computed gotos. */
#define FORCED_LABEL(NODE) (LABEL_DECL_CHECK (NODE)->base.side_effects_flag)
+/* Nonzero in a type considered an empty record. */
+#define TYPE_EMPTY_RECORD(NODE) \
+ (TYPE_CHECK (NODE)->base.side_effects_flag)
+
/* Nonzero means this expression is volatile in the C sense:
its address should be of type `volatile WHATEVER *'.
In other words, the declared item is volatile qualified.
@@ -5379,6 +5383,14 @@ get_finish (location_t loc)
return get_range_from_loc (line_table, loc).m_finish;
}
+/* Return true if type T is an empty record. */
+
+static inline bool
+type_is_empty_record_p (const_tree t)
+{
+ return TYPE_EMPTY_RECORD (TYPE_MAIN_VARIANT (t));
+}
+
extern location_t set_block (location_t loc, tree block);
extern void gt_ggc_mx (tree &);
diff --git a/gcc/ubsan.c b/gcc/ubsan.c
index 6fc6233..6dafc90 100644
--- a/gcc/ubsan.c
+++ b/gcc/ubsan.c
@@ -379,10 +379,11 @@ ubsan_type_descriptor (tree type, enum ubsan_print_style pstyle)
if (pstyle == UBSAN_PRINT_POINTER)
{
- pp_printf (&pretty_name, "'%s%s%s%s%s%s%s",
+ pp_printf (&pretty_name, "'%s%s%s%s%s%s%s%s",
TYPE_VOLATILE (type2) ? "volatile " : "",
TYPE_READONLY (type2) ? "const " : "",
TYPE_RESTRICT (type2) ? "restrict " : "",
+ TYPE_EMPTY_RECORD (type2) ? "empty-record " : "",
TYPE_ATOMIC (type2) ? "_Atomic " : "",
TREE_CODE (type2) == RECORD_TYPE
? "struct "
diff --git a/gcc/var-tracking.c b/gcc/var-tracking.c
index 9185bfd..e9fdbe9 100644
--- a/gcc/var-tracking.c
+++ b/gcc/var-tracking.c
@@ -6140,10 +6140,10 @@ prepare_call_arguments (basic_block bb, rtx_insn *insn)
rtx reg;
INIT_CUMULATIVE_ARGS (args_so_far_v, type, NULL_RTX, fndecl,
nargs + 1);
- reg = targetm.calls.function_arg (args_so_far, mode,
- struct_addr, true);
- targetm.calls.function_arg_advance (args_so_far, mode,
- struct_addr, true);
+ reg = function_arg (args_so_far, mode, struct_addr,
+ true);
+ function_arg_advance (args_so_far, mode, struct_addr,
+ true);
if (reg == NULL_RTX)
{
for (; link; link = XEXP (link, 1))
@@ -6164,8 +6164,8 @@ prepare_call_arguments (basic_block bb, rtx_insn *insn)
machine_mode mode;
t = TYPE_ARG_TYPES (type);
mode = TYPE_MODE (TREE_VALUE (t));
- this_arg = targetm.calls.function_arg (args_so_far, mode,
- TREE_VALUE (t), true);
+ this_arg = function_arg (args_so_far, mode,
+ TREE_VALUE (t), true);
if (this_arg && !REG_P (this_arg))
this_arg = NULL_RTX;
else if (this_arg == NULL_RTX)
@@ -6280,8 +6280,7 @@ prepare_call_arguments (basic_block bb, rtx_insn *insn)
argtype = build_pointer_type (argtype);
mode = TYPE_MODE (argtype);
}
- reg = targetm.calls.function_arg (args_so_far, mode,
- argtype, true);
+ reg = function_arg (args_so_far, mode, argtype, true);
if (TREE_CODE (argtype) == REFERENCE_TYPE
&& INTEGRAL_TYPE_P (TREE_TYPE (argtype))
&& reg
@@ -6335,8 +6334,7 @@ prepare_call_arguments (basic_block bb, rtx_insn *insn)
}
}
}
- targetm.calls.function_arg_advance (args_so_far, mode,
- argtype, true);
+ function_arg_advance (args_so_far, mode, argtype, true);
t = TREE_CHAIN (t);
}
}
--
2.5.0
next prev parent reply other threads:[~2015-12-09 18:53 UTC|newest]
Thread overview: 52+ messages / expand[flat|nested] mbox.gz Atom feed top
2015-12-08 16:22 H.J. Lu
2015-12-09 14:05 ` Richard Biener
2015-12-09 18:53 ` H.J. Lu [this message]
2015-12-09 21:14 ` H.J. Lu
2015-12-09 21:31 ` Markus Trippelsdorf
2015-12-10 11:24 ` Richard Biener
2015-12-11 23:52 ` H.J. Lu
2015-12-12 14:51 ` Jason Merrill
2015-12-12 15:27 ` Jakub Jelinek
2015-12-12 16:45 ` H.J. Lu
2015-12-12 18:43 ` Marc Glisse
2015-12-14 20:16 ` Jason Merrill
2015-12-14 20:39 ` H.J. Lu
2015-12-14 20:44 ` Jason Merrill
2015-12-14 22:08 ` H.J. Lu
2016-01-26 19:27 ` Jason Merrill
2016-01-26 19:52 ` H.J. Lu
2016-01-26 20:23 ` Marc Glisse
2016-01-26 20:26 ` H.J. Lu
2016-01-26 20:44 ` Marc Glisse
2016-01-26 21:21 ` H.J. Lu
2016-01-26 21:40 ` Jakub Jelinek
2016-01-26 22:21 ` H.J. Lu
2016-01-27 8:10 ` Marc Glisse
2016-01-27 8:21 ` Jakub Jelinek
2016-01-27 9:03 ` Marc Glisse
2016-01-27 13:46 ` H.J. Lu
2016-01-27 15:39 ` H.J. Lu
2016-03-01 1:02 ` Jason Merrill
2016-03-01 22:44 ` H.J. Lu
2016-03-02 16:25 ` Ulrich Weigand
2016-03-02 17:34 ` H.J. Lu
2016-03-15 15:35 ` Jason Merrill
2016-03-15 16:00 ` H.J. Lu
2016-03-15 19:32 ` Jason Merrill
2016-03-16 12:38 ` H.J. Lu
2016-03-16 16:58 ` Jason Merrill
2016-03-16 17:02 ` H.J. Lu
2016-03-16 19:39 ` H.J. Lu
2016-03-16 19:43 ` Jason Merrill
2016-03-15 21:40 ` Joseph Myers
2016-03-15 22:31 ` H.J. Lu
2016-03-15 22:35 ` Joseph Myers
2016-03-16 0:23 ` H.J. Lu
2016-03-16 0:25 ` Joseph Myers
2016-03-16 2:17 ` H.J. Lu
2016-03-16 9:46 ` Bernhard Reutner-Fischer
2016-03-16 11:53 ` H.J. Lu
2016-03-16 2:51 ` Jason Merrill
2016-03-16 11:55 ` H.J. Lu
2016-03-16 14:33 ` Jason Merrill
2016-03-16 14:48 ` H.J. Lu
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to='CAMe9rOrMC4XjhFW-a1TdGD2SJo7=yhtGX8r=KxLEyit1WLwpog@mail.gmail.com' \
--to=hjl.tools@gmail.com \
--cc=gcc-patches@gcc.gnu.org \
--cc=jason@redhat.com \
--cc=richard.guenther@gmail.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).