public inbox for gcc-patches@gcc.gnu.org
 help / color / mirror / Atom feed
From: "H.J. Lu" <hjl.tools@gmail.com>
To: Richard Biener <richard.guenther@gmail.com>
Cc: Markus Trippelsdorf <markus@trippelsdorf.de>,
	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: Fri, 11 Dec 2015 23:52:00 -0000	[thread overview]
Message-ID: <CAMe9rOrogonLyyMwY8BGs-ue52kO8jKiOH9q1KHxWiicWCFHkA@mail.gmail.com> (raw)
In-Reply-To: <CAFiYyc2jYtFdiLRdviOX3M-_BV=h_SnyTMm01jKA4ZAVnbaa6w@mail.gmail.com>

[-- Attachment #1: Type: text/plain, Size: 5760 bytes --]

On Thu, Dec 10, 2015 at 3:24 AM, Richard Biener
<richard.guenther@gmail.com> wrote:
> On Wed, Dec 9, 2015 at 10:31 PM, Markus Trippelsdorf
> <markus@trippelsdorf.de> wrote:
>> On 2015.12.09 at 10:53 -0800, H.J. Lu wrote:
>>>
>>> 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.
>>
>> There is a C++ ABI mailinglist, where you could discuss this issue:
>> http://sourcerytools.com/cgi-bin/mailman/listinfo/cxx-abi-dev
>
> Yep.  As long as the ABI doesn't state how to pass those I'd rather _not_ change
> GCCs way.

It is agreed that GCC is wrong on this:

http://sourcerytools.com/pipermail/cxx-abi-dev/2015-December/002876.html

Here is the updated patch.   I updated -WpsABI to warn empty
record which are passed in a variable argument list or aren't the last
arguments.   They are triggered in:

/export/build/gnu/gcc-x32/build-x86_64-linux/prev-x86_64-pc-linux-gnu/libstdc++-v3/include/bits/hashtable.h:1507:7:
note: the ABI of passing empty record has changed in GCC 6
/export/build/gnu/gcc-x32/build-x86_64-linux/prev-x86_64-pc-linux-gnu/libstdc++-v3/include/bits/hashtable_policy.h:901:67:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:238:4:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:266:26:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:273:4:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:289:61:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:296:11:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:304:11:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:312:11:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:320:11:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:328:11:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:341:4:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:375:19:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:375:4:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:390:19:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:390:4:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:415:16:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:425:12:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:442:29:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:449:4:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:457:4:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:500:5:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:529:5:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:547:5:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:569:5:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:617:5:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:637:5:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:657:5:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:673:5:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:686:5:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:722:5:
note: the ABI of passing empty record has changed in GCC 6
/export/gnu/import/git/sources/gcc/libstdc++-v3/src/c++11/cxx11-shim_facets.cc:753:5:
note: the ABI of passing empty record has changed in GCC 6


-- 
H.J.

[-- Attachment #2: 0001-Add-TYPE_EMPTY_RECORD-for-C-empty-class.patch --]
[-- Type: text/x-patch, Size: 36605 bytes --]

From 1a690882987e3fc940743d3368b8993acd9ec8a6 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 1/2] 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): Warn empty record
	if they are used in a variable argument list or aren't the last
	arguments.  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): 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.
	(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_data_all): Add warn_empty_record.
	(assign_parms_augmented_arg_list): Set warn_empty_record if
	empty records are used in a variable argument list or aren't
	the last arguments.
	(assign_parm_find_entry_rtl): Warn empty record if
	warn_empty_record is set.  Replace
	targetm.calls.function_incoming_arg with function_incoming_arg.
	(assign_parms): Only warn empty record once.  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/pr60336-3.C: Likewise.
	* g++.dg/pr68355.C: Likewise.
---
 gcc/c/c-aux-info.c                  |   2 +
 gcc/calls.c                         |  96 ++++++++++++++++++----------
 gcc/config/i386/i386.c              |   3 +-
 gcc/cp/class.c                      |   2 +
 gcc/dse.c                           |   4 +-
 gcc/expr.c                          |   5 +-
 gcc/function.c                      | 122 +++++++++++++++++++++++++++++++-----
 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/pr60336-3.C    |  15 +++++
 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 +++---
 26 files changed, 351 insertions(+), 67 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/pr60336-3.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..3f3ae02b 100644
--- a/gcc/calls.c
+++ b/gcc/calls.c
@@ -1152,7 +1152,10 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
   bitmap_obstack_initialize (NULL);
 
   /* In this loop, we consider args in the order they are written.
-     We fill up ARGS from the back.  */
+     We fill up ARGS from the back.  Warn empty record if they are used
+     in a variable argument list or they aren't the last arguments.  */
+  bool seen_empty_record = false;
+  bool warn_empty_record = stdarg_p (fndecl ? TREE_TYPE (fndecl) : fntype);
 
   i = num_actuals - 1;
   {
@@ -1185,6 +1188,15 @@ initialize_argument_information (int num_actuals ATTRIBUTE_UNUSED,
       {
 	tree argtype = TREE_TYPE (arg);
 
+	if (!warn_empty_record)
+	  {
+	    if (argtype != error_mark_node
+		&& type_is_empty_record_p (argtype))
+	      seen_empty_record = true;
+	    else if (seen_empty_record)
+	      warn_empty_record = true;
+	  }
+
 	/* Remember last param with pointer and associate it
 	   with following pointer bounds.  */
 	if (CALL_WITH_BOUNDS_P (exp)
@@ -1399,8 +1411,13 @@ 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,
+				  warn_empty_record);
+
+      /* Only warn empty record once.  */
+      if (type_is_empty_record_p (type))
+	warn_empty_record = false;
 
       if (args[i].reg && CONST_INT_P (args[i].reg))
 	{
@@ -1413,8 +1430,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 +1492,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 +3345,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 +3961,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 +3979,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,8 +4044,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,
-						      NULL_TREE, true);
+      argvec[count].reg = function_arg (args_so_far, mode, NULL_TREE, true);
 
       argvec[count].partial
 	= targetm.calls.arg_partial_bytes (args_so_far, mode, NULL_TREE, 1);
@@ -4060,7 +4073,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 +4420,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 +4855,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 +4888,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 +4927,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 +5010,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 +5094,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..9040a92 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
@@ -2243,6 +2243,7 @@ struct assign_parm_data_all
   HOST_WIDE_INT pretend_args_size;
   HOST_WIDE_INT extra_pretend_bytes;
   int reg_parm_stack_space;
+  bool warn_empty_record;
 };
 
 struct assign_parm_data_one
@@ -2408,6 +2409,27 @@ assign_parms_augmented_arg_list (struct assign_parm_data_all *all)
   if (targetm.calls.split_complex_arg)
     split_complex_args (&fnargs);
 
+  /* Warn empty record if they are used in a variable argument list or
+     they aren't the last arguments.  */
+  bool warn_empty_record = stdarg_p (fntype);
+  if (!warn_empty_record)
+    {
+      unsigned int i;
+      bool seen_empty_record = false;
+      FOR_EACH_VEC_ELT (fnargs, i, arg)
+	{
+	  tree type = TREE_TYPE (arg);
+	  if (type != error_mark_node && type_is_empty_record_p (type))
+	    seen_empty_record = true;
+	  else if (seen_empty_record)
+	    {
+	      warn_empty_record = true;
+	      break;
+	    }
+	}
+    }
+  all->warn_empty_record = warn_empty_record;
+
   return fnargs;
 }
 
@@ -2524,10 +2546,11 @@ 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,
+				      all->warn_empty_record);
 
   if (entry_parm == 0)
     data->promoted_mode = data->passed_mode;
@@ -2551,9 +2574,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;
 	}
     }
@@ -3715,6 +3738,10 @@ assign_parms (tree fndecl)
       /* Find out where the parameter arrives in this function.  */
       assign_parm_find_entry_rtl (&all, &data);
 
+      /* Only warn empty record once.  */
+      if (type_is_empty_record_p (data.passed_type))
+	all.warn_empty_record = false;
+
       /* Find out where stack space for this parameter might be.  */
       if (assign_parm_is_stack_parm (&all, &data))
 	{
@@ -3791,8 +3818,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 +4015,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 +4159,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 +6892,69 @@ 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))
+    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, bool warn_empty_record_p)
+{
+  if (type && type_is_empty_record_p (type))
+    {
+      if (warn_empty_record_p)
+	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,
+		       bool warn_empty_record_p)
+{
+  if (type && type_is_empty_record_p (type))
+    {
+      if (warn_empty_record_p)
+	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))
+    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..4f25a54 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, bool = false);
+extern rtx function_incoming_arg (cumulative_args_t, machine_mode,
+				  const_tree, bool, bool = false);
+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..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..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/pr60336-3.C b/gcc/testsuite/g++.dg/pr60336-3.C
new file mode 100644
index 0000000..3afdc8d
--- /dev/null
+++ b/gcc/testsuite/g++.dg/pr60336-3.C
@@ -0,0 +1,15 @@
+// { dg-do compile }
+// { dg-options "-O2" }
+
+struct dummy { struct{}__attribute__((aligned (4))) a[7]; };
+
+extern void test1 (struct dummy, ...);
+extern void (*test2) (struct dummy, ...);
+
+void
+foo ()
+{
+  struct dummy a0;
+  test1 (a0); // { dg-message "note: the ABI of passing empty record has changed in GCC 6" }
+  test2 (a0); // { dg-message "note: the ABI of passing empty record has changed in GCC 6" }
+}
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-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


  reply	other threads:[~2015-12-11 23:52 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
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 [this message]
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=CAMe9rOrogonLyyMwY8BGs-ue52kO8jKiOH9q1KHxWiicWCFHkA@mail.gmail.com \
    --to=hjl.tools@gmail.com \
    --cc=gcc-patches@gcc.gnu.org \
    --cc=jason@redhat.com \
    --cc=markus@trippelsdorf.de \
    --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).