Patchwork fix c++/46862, ICE with non-standard def for decimal class

login
register
mail settings
Submitter Janis Johnson
Date Dec. 16, 2010, 1:11 a.m.
Message ID <AANLkTi=vfJAAVJV6N=mKch4M0GSD2RQyGJUGapP6rAZF@mail.gmail.com>
Download mbox | patch
Permalink /patch/75711/
State New
Headers show

Comments

Janis Johnson - Dec. 16, 2010, 1:11 a.m.
This patch fixes PR c++/46862.

The C++ ABI requires that classes decimal32, decimal64, and decimal128
from namespace std::decimal be passed the same as the corresponding
scalar types in C. The classes are defined in the libstdc++ header
files, but the C++ compiler needs to know about them in order to pass
decimal class arguments as scalars. To do that it uses a tree flag
TYPE_TRANSPARENT_AGGR.

Currently the decimal classes are recognized and the flag is set in
begin_class_definition, before the contents of the class are known.
This patch moves the code to recognize them to layout_class_type, when
the compiler can also verify that the class has a first non-static data
member and that the field is a decimal float scalar. If it isn't then a
warning is issued with -Wabi and the TYPE_TRANSPARENT_AGGR flag is not
set, avoiding an ICE if, as in the testcase from the PR, there is no
member to dereference.

Tested on i686-pc-linux-gnu with c,c++ bootstrap and testsuite.
OK for trunk?

Janis
2010-12-15  Janis Johnson  <janis.marie.johnson@gmail.com>

gcc/cp/
	PR c++/46862
	* semantics.c (begin_class_definition): Move code to recognize
	a standard decimal class and mark it to be passed as the
	associated decimal scalar from here ...
	* class.c (layout_class_type): ... to here, and warn if it cannot
	be passed as required by the C++ ABI.

gcc/testsuite/
	PR c++/46862
	* g++.dg/abi/pr46862.C: New test.

Patch

Index: gcc/cp/semantics.c
===================================================================
--- gcc/cp/semantics.c	(revision 167809)
+++ gcc/cp/semantics.c	(working copy)
@@ -2382,25 +2382,6 @@  begin_class_definition (tree t, tree att
       return error_mark_node;
     }
 
-  /* According to the C++ ABI, decimal classes defined in ISO/IEC TR 24733
-     are passed the same as decimal scalar types.  */
-  if (TREE_CODE (t) == RECORD_TYPE
-      && !processing_template_decl)
-    {
-      tree ns = TYPE_CONTEXT (t);
-      if (ns && TREE_CODE (ns) == NAMESPACE_DECL
-	  && DECL_CONTEXT (ns) == std_node
-	  && DECL_NAME (ns)
-	  && !strcmp (IDENTIFIER_POINTER (DECL_NAME (ns)), "decimal"))
-	{
-	  const char *n = TYPE_NAME_STRING (t);
-	  if ((strcmp (n, "decimal32") == 0)
-	      || (strcmp (n, "decimal64") == 0)
-	      || (strcmp (n, "decimal128") == 0))
-	    TYPE_TRANSPARENT_AGGR (t) = 1;
-	}
-    }
-
   /* A non-implicit typename comes from code like:
 
        template <typename T> struct A {
Index: gcc/cp/class.c
===================================================================
--- gcc/cp/class.c	(revision 167809)
+++ gcc/cp/class.c	(working copy)
@@ -5322,6 +5322,44 @@  layout_class_type (tree t, tree *virtual
       last_field_was_bitfield = DECL_C_BIT_FIELD (field);
     }
 
+  /* The C++ ABI requires that the decimal classes in std::decimal, as
+     defined in ISO/IEC TR 24733, be passed the same as the corresponding
+     decimal float scalar types.  */
+  if (!processing_template_decl)
+    {
+      tree ns = TYPE_CONTEXT (t);
+      if (ns && TREE_CODE (ns) == NAMESPACE_DECL
+	  && DECL_CONTEXT (ns) == std_node
+	  && DECL_NAME (ns)
+	  && !strcmp (IDENTIFIER_POINTER (DECL_NAME (ns)), "decimal"))
+	{
+	  const char *n = TYPE_NAME_STRING (t);
+	  if ((strcmp (n, "decimal64") == 0)
+	      || (strcmp (n, "decimal32") == 0)
+	      || (strcmp (n, "decimal128") == 0))
+            {
+	      tree first_field = NULL;
+
+	      /* Find the first non-static data member, if there is one.  */
+	      field = non_static_data_members;
+	      while (field && first_field == NULL)
+		{
+		  if (TREE_CODE (field) == FIELD_DECL)
+		    first_field = field;
+		  field = DECL_CHAIN (field);
+		}
+	
+	      if (first_field && (DECIMAL_FLOAT_MODE_P (TYPE_MODE (
+				    TREE_TYPE (first_field)))))
+		 TYPE_TRANSPARENT_AGGR (t) = 1;
+	      else
+		 warning (OPT_Wabi,
+			  "class %qT cannot be passed as corresponding "
+		          "scalar and is not ABI-compliant", t);
+	    }
+	}
+     }
+
   if (abi_version_at_least (2) && !integer_zerop (rli->bitpos))
     {
       /* Make sure that we are on a byte boundary so that the size of
Index: gcc/testsuite/g++.dg/abi/pr46862.C
===================================================================
--- gcc/testsuite/g++.dg/abi/pr46862.C	(revision 0)
+++ gcc/testsuite/g++.dg/abi/pr46862.C	(revision 0)
@@ -0,0 +1,32 @@ 
+// { dg-do compile }
+// { dg-options "-Wabi" }
+
+// This test does NOT depend on support for decimal float types.
+
+int foo ();
+static __typeof (foo) bar __attribute__ ((__weakref__ ("foo")));
+namespace std
+{
+  namespace decimal
+  {
+    class decimal32;
+    template <class> struct S { };
+    template <> struct S <decimal32> { static const bool value = true; };
+    template <class> class T { };
+    class decimal32 : public T <decimal32> { };	// { dg-warning "corresponding scalar" }
+  }
+}
+
+namespace std
+{
+  namespace decimal
+  {
+    class decimal64 {	// { dg-warning "corresponding scalar" }
+    private:
+      double x;
+    };
+
+    class decimal128 {	// { dg-warning "corresponding scalar" }
+    };
+  }
+}