This is the mail archive of the gcc-patches@gcc.gnu.org mailing list for the GCC project.


Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]
Other format: [Raw text]

Re: PING^1: [PATCH] Add TYPE_EMPTY_RECORD for C++ empty class


I'm concerned about how this patch changes both target-independent code and target-specific code, with a passing remark that other targets might need to make similar changes. I'm also concerned about the effect of this on other languages that might not want the same change. So, here's an alternative patch that implements the change in the front end (and includes your testcases, thanks!).

Thoughts?
commit 96d0f7ffec807b5a6b71dd2fc2f6745f441fabe0
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Mar 11 13:39:52 2016 -0500

    	* class.c (is_really_empty_class): An unnamed bit-field doesn't
    	make a class non-empty.

diff --git a/gcc/cp/class.c b/gcc/cp/class.c
index f6ad696..1027dad 100644
--- a/gcc/cp/class.c
+++ b/gcc/cp/class.c
@@ -8361,6 +8361,8 @@ is_really_empty_class (tree type)
       for (field = TYPE_FIELDS (type); field; field = DECL_CHAIN (field))
 	if (TREE_CODE (field) == FIELD_DECL
 	    && !DECL_ARTIFICIAL (field)
+	    /* An unnamed bit-field is not a data member.  */
+	    && (DECL_NAME (field) || !DECL_C_BIT_FIELD (field))
 	    && !is_really_empty_class (TREE_TYPE (field)))
 	  return false;
       return true;

commit 4a683e9e5e3b3ee824dbf86dd2ad7508ea4fdc3f
Author: Jason Merrill <jason@redhat.com>
Date:   Fri Mar 11 13:40:02 2016 -0500

    	Pass empty class parameters like C.
    
    	* call.c (pass_as_empty_struct, empty_class_arg)
    	(warn_empty_class_abi): New.
    	(type_passed_as, build_x_va_arg): Use pass_as_empty_struct.
    	(build_call_a): Use empty_class_arg, warn_empty_class_abi.
    	* cp-tree.h (CPTI_EMPTY_STRUCT, empty_struct_type): New.
    	* decl.c (cxx_init_decl_processing): Create empty_struct_type.
    	(store_parm_decls): Use warn_empty_class_abi.

diff --git a/gcc/cp/call.c b/gcc/cp/call.c
index 3ad3bd5..d7cfb99 100644
--- a/gcc/cp/call.c
+++ b/gcc/cp/call.c
@@ -214,6 +214,8 @@ static void add_candidates (tree, tree, const vec<tree, va_gc> *, tree, tree,
 			    tsubst_flags_t);
 static conversion *merge_conversion_sequences (conversion *, conversion *);
 static tree build_temp (tree, tree, int, diagnostic_t *, tsubst_flags_t);
+static bool pass_as_empty_struct (tree type);
+static tree empty_class_arg (tree);
 
 /* Returns nonzero iff the destructor name specified in NAME matches BASETYPE.
    NAME can take many forms...  */
@@ -341,7 +343,6 @@ build_call_a (tree function, int n, tree *argarray)
   tree decl;
   tree result_type;
   tree fntype;
-  int i;
 
   function = build_addr_func (function, tf_warning_or_error);
 
@@ -379,16 +380,24 @@ build_call_a (tree function, int n, tree *argarray)
   /* Don't pass empty class objects by value.  This is useful
      for tags in STL, which are used to control overload resolution.
      We don't need to handle other cases of copying empty classes.  */
+  bool warned = false;
+  if (decl && !TREE_PUBLIC (decl))
+    /* Don't warn about the ABI of a function local to this TU.  */
+    warned = true;
   if (! decl || ! DECL_BUILT_IN (decl))
-    for (i = 0; i < n; i++)
+    for (int i = 0; i < n; i++)
       {
 	tree arg = CALL_EXPR_ARG (function, i);
-	if (is_empty_class (TREE_TYPE (arg))
-	    && ! TREE_ADDRESSABLE (TREE_TYPE (arg)))
+	tree type = TREE_TYPE (arg);
+	if (is_really_empty_class (type)
+	    && ! TREE_ADDRESSABLE (type))
 	  {
-	    tree t = build0 (EMPTY_CLASS_EXPR, TREE_TYPE (arg));
-	    arg = build2 (COMPOUND_EXPR, TREE_TYPE (t), arg, t);
-	    CALL_EXPR_ARG (function, i) = arg;
+	    location_t loc = EXPR_LOC_OR_LOC (arg, input_location);
+	    CALL_EXPR_ARG (function, i) = empty_class_arg (arg);
+	    /* Warn about ABI changes for a non-final argument.  */
+	    if (!warned && i < n-1
+		&& warn_empty_class_abi (arg, loc))
+	      warned = true;
 	  }
       }
 
@@ -6871,6 +6880,14 @@ build_x_va_arg (source_location loc, tree expr, tree type)
       expr = build_va_arg (loc, expr, ref);
       return convert_from_reference (expr);
     }
+  else if (is_really_empty_class (type) && !TREE_ADDRESSABLE (type))
+    {
+      /* Do the reverse of empty_class_arg.  */
+      tree etype = pass_as_empty_struct (type) ? empty_struct_type : type;
+      expr = build_va_arg (loc, expr, etype);
+      tree ec = build0 (EMPTY_CLASS_EXPR, type);
+      return build2 (COMPOUND_EXPR, type, expr, ec);
+    }
 
   return build_va_arg (loc, expr, type);
 }
@@ -6967,6 +6984,65 @@ convert_default_arg (tree type, tree arg, tree fn, int parmnum,
   return arg;
 }
 
+/* Return true iff TYPE should be passed and returned as a size 0 type rather
+   than its normal size, for compatibility with C.  */
+
+static bool
+pass_as_empty_struct (tree type)
+{
+  return (abi_version_at_least (10)
+	  && type != error_mark_node
+	  && COMPLETE_TYPE_P (type)
+	  && !TREE_ADDRESSABLE (type)
+	  && is_really_empty_class (type));
+}
+
+/* Adjust the value VAL of empty class type TYPE for argument passing.
+   Keep this synced with build_x_va_arg.  */
+
+static tree
+empty_class_arg (tree val)
+{
+  /* Don't pass empty class objects by value.  This is useful
+     for tags in STL, which are used to control overload resolution.
+     We don't need to handle other cases of copying empty classes.  */
+  tree type = TREE_TYPE (val);
+  tree etype = pass_as_empty_struct (type) ? empty_struct_type : type;
+  tree empty = build0 (EMPTY_CLASS_EXPR, etype);
+  return build2 (COMPOUND_EXPR, etype, val, empty);
+}
+
+/* Warn about the change in empty class parameter passing ABI.  Returns true
+   if we warned.  */
+
+bool
+warn_empty_class_abi (tree arg, location_t loc)
+{
+  if (!warn_abi || !abi_version_crosses (10))
+    return false;
+
+  tree type;
+  if (TYPE_P (arg))
+    type = arg;
+  else
+    {
+      if (TREE_TYPE (arg) == empty_struct_type
+	  && TREE_CODE (arg) == COMPOUND_EXPR)
+	arg = TREE_OPERAND (arg, 0);
+      type = TREE_TYPE (arg);
+    }
+
+  if (!dependent_type_p (type)
+      && !TREE_ADDRESSABLE (type)
+      && is_really_empty_class (type))
+    {
+      warning_at (loc, OPT_Wabi, "empty class %qT parameter passing ABI "
+	       "changes in -fabi-version=10 (GCC 6)", type);
+      return true;
+    }
+  return false;
+}
+
 /* Returns the type which will really be used for passing an argument of
    type TYPE.  */
 
@@ -6985,6 +7061,8 @@ type_passed_as (tree type)
 	   && COMPLETE_TYPE_P (type)
 	   && tree_int_cst_lt (TYPE_SIZE (type), TYPE_SIZE (integer_type_node)))
     type = integer_type_node;
+  else if (pass_as_empty_struct (type))
+    type = empty_struct_type;
 
   return type;
 }
diff --git a/gcc/cp/cp-tree.h b/gcc/cp/cp-tree.h
index a08c59b..3f24f7d 100644
--- a/gcc/cp/cp-tree.h
+++ b/gcc/cp/cp-tree.h
@@ -1150,6 +1150,8 @@ enum cp_tree_index
     CPTI_NULLPTR,
     CPTI_NULLPTR_TYPE,
 
+    CPTI_EMPTY_STRUCT,
+
     CPTI_MAX
 };
 
@@ -1185,6 +1187,7 @@ extern GTY(()) tree cp_global_trees[CPTI_MAX];
 #define current_aggr			cp_global_trees[CPTI_AGGR_TAG]
 #define nullptr_node			cp_global_trees[CPTI_NULLPTR]
 #define nullptr_type_node		cp_global_trees[CPTI_NULLPTR_TYPE]
+#define empty_struct_type		cp_global_trees[CPTI_EMPTY_STRUCT]
 
 /* We cache these tree nodes so as to call get_identifier less
    frequently.  */
@@ -5571,6 +5574,7 @@ extern tree build_addr_func			(tree, tsubst_flags_t);
 extern void set_flags_from_callee		(tree);
 extern tree build_call_a			(tree, int, tree*);
 extern tree build_call_n			(tree, int, ...);
+extern bool warn_empty_class_abi		(tree, location_t);
 extern bool null_ptr_cst_p			(tree);
 extern bool null_member_pointer_value_p		(tree);
 extern bool sufficient_parms_p			(const_tree);
diff --git a/gcc/cp/decl.c b/gcc/cp/decl.c
index 27c3597..4ee4ccc 100644
--- a/gcc/cp/decl.c
+++ b/gcc/cp/decl.c
@@ -4145,6 +4145,10 @@ cxx_init_decl_processing (void)
     nullptr_node = build_int_cst (nullptr_type_node, 0);
   }
 
+  empty_struct_type = make_node (RECORD_TYPE);
+  finish_builtin_struct (empty_struct_type, "__empty_struct",
+			 NULL_TREE, NULL_TREE);
+
   abort_fndecl
     = build_library_fn_ptr ("__cxa_pure_virtual", void_ftype,
 			    ECF_NORETURN | ECF_NOTHROW);
@@ -14243,6 +14247,9 @@ store_parm_decls (tree current_function_parms)
 	     they end in the correct forward order.  */
       specparms = nreverse (specparms);
 
+      /* Don't warn about the ABI of a function local to this TU.  */
+      bool warned = (processing_template_decl
+		     || !TREE_PUBLIC (current_function_decl));
       for (parm = specparms; parm; parm = next)
 	{
 	  next = DECL_CHAIN (parm);
@@ -14253,6 +14260,13 @@ store_parm_decls (tree current_function_parms)
 		pushdecl (parm);
 	      else
 		error ("parameter %qD declared void", parm);
+	      /* If this isn't the last parameter, maybe warn about ABI change
+		 in passing empty classes.  */
+	      if (!warned
+		  && (parm != specparms
+		      || varargs_function_p (current_function_decl))
+		  && warn_empty_class_abi (parm, DECL_SOURCE_LOCATION (parm)))
+		warned = true;
 	    }
 	  else
 	    {
diff --git a/gcc/testsuite/g++.dg/abi/empty12.C b/gcc/testsuite/g++.dg/abi/empty12.C
new file mode 100644
index 0000000..ce1f6f2
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty12.C
@@ -0,0 +1,17 @@
+// PR c++/60336
+// { dg-do run }
+// { dg-options "-Wabi=9 -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-warning "empty" }
+  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/abi/empty13.C b/gcc/testsuite/g++.dg/abi/empty13.C
new file mode 100644
index 0000000..d1e0946
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty13.C
@@ -0,0 +1,17 @@
+// PR c++/60336
+// { dg-do run }
+// { dg-options "-x c -fabi-version=9" }
+// { dg-additional-sources "empty13a.c" }
+// { dg-prune-output "command line option" }
+
+#include "empty13.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/empty13.h b/gcc/testsuite/g++.dg/abi/empty13.h
new file mode 100644
index 0000000..c61afcd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty13.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/empty13a.c b/gcc/testsuite/g++.dg/abi/empty13a.c
new file mode 100644
index 0000000..b4303a6
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty13a.c
@@ -0,0 +1,6 @@
+#include "empty13.h"
+void fun(struct dummy d, struct foo f)
+{
+  if (f.i1 == -1)
+    __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/abi/empty14.C b/gcc/testsuite/g++.dg/abi/empty14.C
new file mode 100644
index 0000000..1b9c397
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty14.C
@@ -0,0 +1,17 @@
+// PR c++/60336
+// { dg-do run }
+// { dg-options "-Wabi=9 -x c" }
+// { dg-additional-sources "empty14a.c" }
+// { dg-prune-output "command line option" }
+
+#include "empty14.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-warning "empty" }
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/abi/empty14.h b/gcc/testsuite/g++.dg/abi/empty14.h
new file mode 100644
index 0000000..5842279
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty14.h
@@ -0,0 +1,10 @@
+struct dummy0 { };
+struct dummy { struct dummy0 d[140]; };
+struct foo
+{
+  int i1;
+  int i2;
+  int i3;
+  int i4;
+  int i5;
+};
diff --git a/gcc/testsuite/g++.dg/abi/empty14a.c b/gcc/testsuite/g++.dg/abi/empty14a.c
new file mode 100644
index 0000000..8b3d780
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty14a.c
@@ -0,0 +1,6 @@
+#include "empty14.h"
+void fun(struct dummy d, struct foo f)
+{
+  if (f.i1 != -1)
+    __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/abi/empty15.C b/gcc/testsuite/g++.dg/abi/empty15.C
new file mode 100644
index 0000000..ac0a868
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty15.C
@@ -0,0 +1,17 @@
+// PR c++/60336
+// { dg-do run }
+// { dg-options "-Wabi=9 -x c" }
+// { dg-additional-sources "empty15a.c" }
+// { dg-prune-output "command line option" }
+
+#include "empty15.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-warning "empty" }
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/abi/empty15.h b/gcc/testsuite/g++.dg/abi/empty15.h
new file mode 100644
index 0000000..1c6f26f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty15.h
@@ -0,0 +1,30 @@
+struct A1 {};
+struct A2 {};
+struct B1 { struct A1 a; struct A2 b; };
+struct B2 { struct A1 a; struct A2 b; };
+struct C1 { struct B1 a; struct B2 b; };
+struct C2 { struct B1 a; struct B2 b; };
+struct D1 { struct C1 a; struct C2 b; };
+struct D2 { struct C1 a; struct C2 b; };
+struct E1 { struct D1 a; struct D2 b; };
+struct E2 { struct D1 a; struct D2 b; };
+struct F1 { struct E1 a; struct E2 b; };
+struct F2 { struct E1 a; struct E2 b; };
+struct G1 { struct F1 a; struct F2 b; };
+struct G2 { struct F1 a; struct F2 b; };
+struct H1 { struct G1 a; struct G2 b; };
+struct H2 { struct G1 a; struct G2 b; };
+struct I1 { struct H1 a; struct H2 b; };
+struct I2 { struct H1 a; struct H2 b; };
+struct J1 { struct I1 a; struct I2 b; };
+struct J2 { struct I1 a; struct I2 b; };
+struct dummy { struct J1 a; struct J2 b; };
+
+struct foo
+{
+  int i1;
+  int i2;
+  int i3;
+  int i4;
+  int i5;
+};
diff --git a/gcc/testsuite/g++.dg/abi/empty15a.c b/gcc/testsuite/g++.dg/abi/empty15a.c
new file mode 100644
index 0000000..325b2c5
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty15a.c
@@ -0,0 +1,6 @@
+#include "empty15.h"
+void fun(struct dummy d, struct foo f)
+{
+  if (f.i1 != -1)
+    __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/abi/empty16.C b/gcc/testsuite/g++.dg/abi/empty16.C
new file mode 100644
index 0000000..de2bf5c
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty16.C
@@ -0,0 +1,17 @@
+// PR c++/60336
+// { dg-do run }
+// { dg-options "-Wabi=9 -x c" }
+// { dg-additional-sources "empty16a.c" }
+// { dg-prune-output "command line option" }
+
+#include "empty16.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-warning "empty" }
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/abi/empty16.h b/gcc/testsuite/g++.dg/abi/empty16.h
new file mode 100644
index 0000000..7552ae0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty16.h
@@ -0,0 +1,16 @@
+#ifdef __cplusplus
+struct A1 {};
+struct A2 {};
+struct dummy : A1, A2 {} ;
+#else
+struct dummy {};
+#endif
+
+struct foo
+{
+  int i1;
+  int i2;
+  int i3;
+  int i4;
+  int i5;
+};
diff --git a/gcc/testsuite/g++.dg/abi/empty16a.c b/gcc/testsuite/g++.dg/abi/empty16a.c
new file mode 100644
index 0000000..6cb7fbc
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty16a.c
@@ -0,0 +1,6 @@
+#include "empty16.h"
+void fun(struct dummy d, struct foo f)
+{
+  if (f.i1 != -1)
+    __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/abi/empty17.C b/gcc/testsuite/g++.dg/abi/empty17.C
new file mode 100644
index 0000000..c7a37c0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty17.C
@@ -0,0 +1,17 @@
+// PR c++/60336
+// { dg-do run }
+// { dg-options "-Wabi=9 -x c" }
+// { dg-additional-sources "empty17a.c" }
+// { dg-prune-output "command line option" }
+
+#include "empty17.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-warning "empty" }
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/abi/empty17.h b/gcc/testsuite/g++.dg/abi/empty17.h
new file mode 100644
index 0000000..9cf72ba
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty17.h
@@ -0,0 +1,27 @@
+#ifdef __cplusplus
+struct A1
+{
+  void foo (void);
+  unsigned int : 15;
+};
+struct A2
+{
+  void bar (void);
+  unsigned int : 15;
+};
+struct dummy : A1, A2
+{
+  unsigned int : 15;
+};
+#else
+struct dummy {};
+#endif
+
+struct foo
+{
+  int i1;
+  int i2;
+  int i3;
+  int i4;
+  int i5;
+};
diff --git a/gcc/testsuite/g++.dg/abi/empty17a.c b/gcc/testsuite/g++.dg/abi/empty17a.c
new file mode 100644
index 0000000..24408fd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/empty17a.c
@@ -0,0 +1,6 @@
+#include "empty17.h"
+void fun(struct dummy d, struct foo f)
+{
+  if (f.i1 != -1)
+    __builtin_abort();
+}
diff --git a/gcc/testsuite/g++.dg/abi/pr60336-1.C b/gcc/testsuite/g++.dg/abi/pr60336-1.C
new file mode 100644
index 0000000..af08638
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/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/abi/pr60336-10.C b/gcc/testsuite/g++.dg/abi/pr60336-10.C
new file mode 100644
index 0000000..6c9c990
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/pr60336-10.C
@@ -0,0 +1,50 @@
+// { dg-do run }
+// { dg-options "-O2" }
+
+#include <stdarg.h>
+
+struct dummy0 { };
+struct dummy1 { };
+struct dummy : dummy0, dummy1 { };
+
+void
+test (struct dummy a, int m, ...)
+{
+  va_list va_arglist;
+  int i;
+  int count = 0;
+
+  if (m == 0)
+    count++;
+  va_start (va_arglist, m);
+  i = va_arg (va_arglist, int);
+  if (i == 1)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 2)
+  i = va_arg (va_arglist, int);
+    count++;
+  if (i == 3)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 4)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 5)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 6)
+    count++;
+  va_end (va_arglist);
+  if (count != 7)
+    __builtin_abort ();
+}
+
+struct dummy a0;
+
+int
+main ()
+{
+  test (a0, 0, 1, 2, 3, 4, 5, 6);
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/abi/pr60336-11.C b/gcc/testsuite/g++.dg/abi/pr60336-11.C
new file mode 100644
index 0000000..c92f3d4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/pr60336-11.C
@@ -0,0 +1,56 @@
+// { dg-do run }
+// { dg-options "-O2" }
+
+#include <stdarg.h>
+
+struct dummy0
+{
+  void bar (void);
+};
+struct dummy1
+{
+  void foo (void);
+};
+struct dummy : dummy0, dummy1 { };
+
+void
+test (struct dummy a, int m, ...)
+{
+  va_list va_arglist;
+  int i;
+  int count = 0;
+
+  if (m == 0)
+    count++;
+  va_start (va_arglist, m);
+  i = va_arg (va_arglist, int);
+  if (i == 1)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 2)
+  i = va_arg (va_arglist, int);
+    count++;
+  if (i == 3)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 4)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 5)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 6)
+    count++;
+  va_end (va_arglist);
+  if (count != 7)
+    __builtin_abort ();
+}
+
+struct dummy a0;
+
+int
+main ()
+{
+  test (a0, 0, 1, 2, 3, 4, 5, 6);
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/abi/pr60336-12.C b/gcc/testsuite/g++.dg/abi/pr60336-12.C
new file mode 100644
index 0000000..83a7bb0
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/pr60336-12.C
@@ -0,0 +1,57 @@
+// { dg-do run }
+// { dg-options "-O2" }
+
+#include <stdarg.h>
+
+struct dummy0
+{
+};
+struct dummy1
+{
+  unsigned : 15;
+};
+struct dummy : dummy0, dummy1
+{
+};
+
+void
+test (struct dummy a, int m, ...)
+{
+  va_list va_arglist;
+  int i;
+  int count = 0;
+
+  if (m == 0)
+    count++;
+  va_start (va_arglist, m);
+  i = va_arg (va_arglist, int);
+  if (i == 1)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 2)
+  i = va_arg (va_arglist, int);
+    count++;
+  if (i == 3)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 4)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 5)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 6)
+    count++;
+  va_end (va_arglist);
+  if (count != 7)
+    __builtin_abort ();
+}
+
+struct dummy a0;
+
+int
+main ()
+{
+  test (a0, 0, 1, 2, 3, 4, 5, 6);
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/abi/pr60336-2.C b/gcc/testsuite/g++.dg/abi/pr60336-2.C
new file mode 100644
index 0000000..32eecb3
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/pr60336-2.C
@@ -0,0 +1,48 @@
+// { dg-do run }
+// { dg-options "-O2 -Wabi=9" }
+
+#include <stdarg.h>
+
+struct dummy { };
+
+void
+test (struct dummy a, int m, ...) // { dg-message "empty" }
+{
+  va_list va_arglist;
+  int i;
+  int count = 0;
+
+  if (m == 0)
+    count++;
+  va_start (va_arglist, m);
+  i = va_arg (va_arglist, int);
+  if (i == 1)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 2)
+  i = va_arg (va_arglist, int);
+    count++;
+  if (i == 3)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 4)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 5)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 6)
+    count++;
+  va_end (va_arglist);
+  if (count != 7)
+    __builtin_abort ();
+}
+
+struct dummy a0;
+
+int
+main ()
+{
+  test (a0, 0, 1, 2, 3, 4, 5, 6); // { dg-message "empty" }
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/abi/pr60336-3.C b/gcc/testsuite/g++.dg/abi/pr60336-3.C
new file mode 100644
index 0000000..8ebd4dd
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/pr60336-3.C
@@ -0,0 +1,15 @@
+// { dg-do compile }
+// { dg-options "-O2 -Wabi=9" }
+
+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, 42); // { dg-message "empty" }
+  test2 (a0, 42); // { dg-message "empty" }
+}
diff --git a/gcc/testsuite/g++.dg/abi/pr60336-4.C b/gcc/testsuite/g++.dg/abi/pr60336-4.C
new file mode 100644
index 0000000..8790a66
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/pr60336-4.C
@@ -0,0 +1,48 @@
+// { dg-do run { target { { i?86-*-* x86_64-*-* } && { ! { ia32 } } } } }
+// { dg-options "-O2 -fabi-version=9" }
+
+#include <stdarg.h>
+
+struct dummy { };
+
+void
+test (struct dummy a, int m, ...)
+{
+  va_list va_arglist;
+  int i;
+  int count = 0;
+
+  if (m == 0)
+    count++;
+  va_start (va_arglist, m);
+  i = va_arg (va_arglist, int);
+  if (i == 1)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 2)
+  i = va_arg (va_arglist, int);
+    count++;
+  if (i == 3)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 4)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 5)
+    count++;
+  i = va_arg (va_arglist, int);
+  if (i == 6)
+    count++;
+  va_end (va_arglist);
+  if (count == 7)
+    __builtin_abort ();
+}
+
+struct dummy a0;
+
+int
+main ()
+{
+  test (a0, 0, 1, 2, 3, 4, 5, 6);
+  return 0;
+}
diff --git a/gcc/testsuite/g++.dg/abi/pr60336-5.C b/gcc/testsuite/g++.dg/abi/pr60336-5.C
new file mode 100644
index 0000000..b0c76ad
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/pr60336-5.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; struct dummy j; };
+
+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/abi/pr60336-6.C b/gcc/testsuite/g++.dg/abi/pr60336-6.C
new file mode 100644
index 0000000..5879651
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/pr60336-6.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 i1; struct dummy i2; };
+
+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/abi/pr60336-7.C b/gcc/testsuite/g++.dg/abi/pr60336-7.C
new file mode 100644
index 0000000..0e5d2ef
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/pr60336-7.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[120]; };
+
+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/abi/pr60336-8.C b/gcc/testsuite/g++.dg/abi/pr60336-8.C
new file mode 100644
index 0000000..fdfc924
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/pr60336-8.C
@@ -0,0 +1,15 @@
+// { dg-do compile }
+// { dg-options "-O2 -Wabi=9" }
+
+struct dummy { struct{} a[7][3]; };
+
+extern void test1 (struct dummy, ...);
+extern void (*test2) (struct dummy, ...);
+
+void
+foo ()
+{
+  struct dummy a0;
+  test1 (a0, 42); // { dg-message "empty" }
+  test2 (a0, 42); // { dg-message "empty" }
+}
diff --git a/gcc/testsuite/g++.dg/abi/pr60336-9.C b/gcc/testsuite/g++.dg/abi/pr60336-9.C
new file mode 100644
index 0000000..4ad333f
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/pr60336-9.C
@@ -0,0 +1,28 @@
+// { dg-do compile }
+// { dg-options "-O2 -std=c++11 -fno-pic" }
+// { dg-require-effective-target fpic }
+
+struct A1 {}; struct A2 {};
+struct B1 { A1 a; A2 b; }; struct B2 { A1 a; A2 b; };
+struct C1 { B1 a; B2 b; }; struct C2 { B1 a; B2 b; };
+struct D1 { C1 a; C2 b; }; struct D2 { C1 a; C2 b; };
+struct E1 { D1 a; D2 b; }; struct E2 { D1 a; D2 b; };
+struct F1 { E1 a; E2 b; }; struct F2 { E1 a; E2 b; };
+struct G1 { F1 a; F2 b; }; struct G2 { F1 a; F2 b; };
+struct H1 { G1 a; G2 b; }; struct H2 { G1 a; G2 b; };
+struct I1 { H1 a; H2 b; }; struct I2 { H1 a; H2 b; };
+struct J1 { I1 a; I2 b; }; struct J2 { I1 a; I2 b; };
+struct dummy { J1 a; J2 b; };
+
+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/abi/pr68355.C b/gcc/testsuite/g++.dg/abi/pr68355.C
new file mode 100644
index 0000000..1354fc4
--- /dev/null
+++ b/gcc/testsuite/g++.dg/abi/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-*-* } } }

commit b3d57318c2372703cf725d4cfd3752bc1f2a65fa
Author: Jason Merrill <jason@redhat.com>
Date:   Thu Mar 10 13:56:16 2016 -0500

    wabi

diff --git a/libstdc++-v3/acinclude.m4 b/libstdc++-v3/acinclude.m4
index 95df24a..94fde7e 100644
--- a/libstdc++-v3/acinclude.m4
+++ b/libstdc++-v3/acinclude.m4
@@ -765,7 +765,7 @@ AC_DEFUN([GLIBCXX_EXPORT_FLAGS], [
   # OPTIMIZE_CXXFLAGS = -O3 -fstrict-aliasing -fvtable-gc
   AC_SUBST(OPTIMIZE_CXXFLAGS)
 
-  WARN_FLAGS='-Wall -Wextra -Wwrite-strings -Wcast-qual -Wabi'
+  WARN_FLAGS='-Wall -Wextra -Wwrite-strings -Wcast-qual -Werror=abi -Wabi=9'
   AC_SUBST(WARN_FLAGS)
 ])
 
diff --git a/libstdc++-v3/configure b/libstdc++-v3/configure
index acbc6a6..4913211 100755
--- a/libstdc++-v3/configure
+++ b/libstdc++-v3/configure
@@ -81354,7 +81354,7 @@ $as_echo "$gxx_include_dir" >&6; }
   # OPTIMIZE_CXXFLAGS = -O3 -fstrict-aliasing -fvtable-gc
 
 
-  WARN_FLAGS='-Wall -Wextra -Wwrite-strings -Wcast-qual -Wabi'
+  WARN_FLAGS='-Wall -Wextra -Wwrite-strings -Wcast-qual -Werror=abi -Wabi=9'
 
 
 

Index Nav: [Date Index] [Subject Index] [Author Index] [Thread Index]
Message Nav: [Date Prev] [Date Next] [Thread Prev] [Thread Next]