Patchwork [Ada] Fix ICE on constant with tagged type

login
register
mail settings
Submitter Eric Botcazou
Date Nov. 9, 2010, 11:59 a.m.
Message ID <201011091259.38623.ebotcazou@adacore.com>
Download mbox | patch
Permalink /patch/70535/
State New
Headers show

Comments

Eric Botcazou - Nov. 9, 2010, 11:59 a.m.
This is an ICE raised when compiling Adasockets 1.8.8, a regression present on 
the mainline.  The gimplifier is trying to create a temporary with a type for 
which it isn't allowed to do so; such a temporary must always be created by 
gigi for this kind of type.

It turns out that no temporary is needed if the trees are fully simplified.
But they aren't because the constant folder doesn't fold constructors with 
type_contains_placeholder_p types.  However, the problematic type doesn't 
contain PLACEHOLDER_EXPRs in its structure, it only contains a component 
whose type is a pointer type to a type_contains_placeholder_p type.

This appears to be an old thinko in type_contains_placeholder_1: it reads

/* Return true if any part of the computation of TYPE involves a
   PLACEHOLDER_EXPR.  This includes size, bounds, qualifiers
   (for QUAL_UNION_TYPE) and field positions.  */

static bool
type_contains_placeholder_1 (const_tree type)
{
  /* If the size contains a placeholder or the parent type (component type in
     the case of arrays) type involves a placeholder, this type does.  */
  if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (type))
      || CONTAINS_PLACEHOLDER_P (TYPE_SIZE_UNIT (type))
      || (TREE_TYPE (type) != 0
	  && type_contains_placeholder_p (TREE_TYPE (type))))
    return true;

but TREE_TYPE (type) is the pointed-to type for POINTER_TYPE_P types.

The attached patch makes it so that type_contains_placeholder_p returns false 
for POINTER_TYPE_P types.  This works fine, except for what we call "fat 
pointer types" in Ada, which are not only used to represent pointers but also 
unconstrained arrays types themselves; the latters do contain PLACEHOLDERs.
So the patch forces type_contains_placeholder_p to return true for them.

Tested on i586-suse-linux, applied on the mainline.  This only affects Ada.


2010-11-09  Eric Botcazou  <ebotcazou@adacore.com>

	* tree.h (contains_placeholder_p): Fix comment.
	(type_contains_placeholder_p): Adjust comment.
	* tree.c (contains_placeholder_p): Fix comment.
	(type_contains_placeholder_1): Do not recurse on pointed-to types and
	adjust comment.
	(type_contains_placeholder_p): Add comment.
ada/
	* gcc-interface/decl.c (finish_fat_pointer_type): New function.
	(gnat_to_gnu_entity) <E_Array_Type>: Use it to build the fat pointer
	type.
	<E_Access_Type>: Likewise.


2010-11-09  Eric Botcazou  <ebotcazou@adacore.com>

	* gnat.dg/specs/static_initializer5.ads: New test.
	* gnat.dg/specs/static_initializer5_pkg.ads: New helper.

Patch

Index: tree.c
===================================================================
--- tree.c	(revision 166445)
+++ tree.c	(working copy)
@@ -2795,8 +2795,8 @@  process_call_operands (tree t)
   TREE_READONLY (t) = read_only;
 }
 
-/* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size
-   or offset that depends on a field within a record.  */
+/* Return true if EXP contains a PLACEHOLDER_EXPR, i.e. if it represents a
+   size or offset that depends on a field within a record.  */
 
 bool
 contains_placeholder_p (const_tree exp)
@@ -2882,9 +2882,9 @@  contains_placeholder_p (const_tree exp)
   return 0;
 }
 
-/* Return true if any part of the computation of TYPE involves a
-   PLACEHOLDER_EXPR.  This includes size, bounds, qualifiers
-   (for QUAL_UNION_TYPE) and field positions.  */
+/* Return true if any part of the structure of TYPE involves a PLACEHOLDER_EXPR
+   directly.  This includes size, bounds, qualifiers (for QUAL_UNION_TYPE) and
+   field positions.  */
 
 static bool
 type_contains_placeholder_1 (const_tree type)
@@ -2893,7 +2893,8 @@  type_contains_placeholder_1 (const_tree
      the case of arrays) type involves a placeholder, this type does.  */
   if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (type))
       || CONTAINS_PLACEHOLDER_P (TYPE_SIZE_UNIT (type))
-      || (TREE_TYPE (type) != 0
+      || (!POINTER_TYPE_P (type)
+	  && TREE_TYPE (type)
 	  && type_contains_placeholder_p (TREE_TYPE (type))))
     return true;
 
@@ -2921,8 +2922,8 @@  type_contains_placeholder_1 (const_tree
 	      || CONTAINS_PLACEHOLDER_P (TYPE_MAX_VALUE (type)));
 
     case ARRAY_TYPE:
-      /* We're already checked the component type (TREE_TYPE), so just check
-	 the index type.  */
+      /* We have already checked the component type above, so just check the
+	 domain type.  */
       return type_contains_placeholder_p (TYPE_DOMAIN (type));
 
     case RECORD_TYPE:
@@ -2947,6 +2948,8 @@  type_contains_placeholder_1 (const_tree
     }
 }
 
+/* Wrapper around above function used to cache its result.  */
+
 bool
 type_contains_placeholder_p (tree type)
 {
Index: tree.h
===================================================================
--- tree.h	(revision 166445)
+++ tree.h	(working copy)
@@ -4588,11 +4588,8 @@  extern tree skip_simple_arithmetic (tree
 
 enum tree_node_structure_enum tree_node_structure (const_tree);
 
-/* Return 1 if EXP contains a PLACEHOLDER_EXPR; i.e., if it represents a size
-   or offset that depends on a field within a record.
-
-   Note that we only allow such expressions within simple arithmetic
-   or a COND_EXPR.  */
+/* Return true if EXP contains a PLACEHOLDER_EXPR, i.e. if it represents a
+   size or offset that depends on a field within a record.  */
 
 extern bool contains_placeholder_p (const_tree);
 
@@ -4602,9 +4599,9 @@  extern bool contains_placeholder_p (cons
 #define CONTAINS_PLACEHOLDER_P(EXP) \
   ((EXP) != 0 && ! TREE_CONSTANT (EXP) && contains_placeholder_p (EXP))
 
-/* Return 1 if any part of the computation of TYPE involves a PLACEHOLDER_EXPR.
-   This includes size, bounds, qualifiers (for QUAL_UNION_TYPE) and field
-   positions.  */
+/* Return true if any part of the structure of TYPE involves a PLACEHOLDER_EXPR
+   directly.  This includes size, bounds, qualifiers (for QUAL_UNION_TYPE) and
+   field positions.  */
 
 extern bool type_contains_placeholder_p (tree);
 
Index: ada/gcc-interface/decl.c
===================================================================
--- ada/gcc-interface/decl.c	(revision 166445)
+++ ada/gcc-interface/decl.c	(working copy)
@@ -177,6 +177,7 @@  static tree create_variant_part_from (tr
 				      tree, VEC(subst_pair,heap) *);
 static void copy_and_substitute_in_size (tree, tree, VEC(subst_pair,heap) *);
 static void rest_of_type_decl_compilation_no_defer (tree);
+static void finish_fat_pointer_type (tree, tree);
 
 /* The relevant constituents of a subprogram binding to a GCC builtin.  Used
    to pass around calls performing profile compatibilty checks.  */
@@ -188,7 +189,6 @@  typedef struct {
 } intrin_binding_t;
 
 static bool intrin_profiles_compatible_p (intrin_binding_t *);
-
 
 /* Given GNAT_ENTITY, a GNAT defining identifier node, which denotes some Ada
    entity, return the equivalent GCC tree for that entity (a ..._DECL node)
@@ -1915,23 +1915,13 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 	/* Build the fat pointer type.  Use a "void *" object instead of
 	   a pointer to the array type since we don't have the array type
 	   yet (it will reference the fat pointer via the bounds).  */
-	tem = chainon (chainon (NULL_TREE,
-				create_field_decl (get_identifier ("P_ARRAY"),
-						   ptr_void_type_node,
-						   gnu_fat_type, NULL_TREE,
-						   NULL_TREE, 0, 0)),
-		       create_field_decl (get_identifier ("P_BOUNDS"),
-					  gnu_ptr_template,
-					  gnu_fat_type, NULL_TREE,
-					  NULL_TREE, 0, 0));
-
-	/* Make sure we can put this into a register.  */
-	TYPE_ALIGN (gnu_fat_type) = MIN (BIGGEST_ALIGNMENT, 2 * POINTER_SIZE);
-
-	/* Do not emit debug info for this record type since the types of its
-	   fields are still incomplete at this point.  */
-	finish_record_type (gnu_fat_type, tem, 0, false);
-	TYPE_FAT_POINTER_P (gnu_fat_type) = 1;
+	tem
+	  = create_field_decl (get_identifier ("P_ARRAY"), ptr_void_type_node,
+			       gnu_fat_type, NULL_TREE, NULL_TREE, 0, 0);
+	TREE_CHAIN (tem)
+	  = create_field_decl (get_identifier ("P_BOUNDS"), gnu_ptr_template,
+			       gnu_fat_type, NULL_TREE, NULL_TREE, 0, 0);
+	finish_fat_pointer_type (gnu_fat_type, tem);
 
 	/* Build a reference to the template from a PLACEHOLDER_EXPR that
 	   is the fat pointer.  This will be used to access the individual
@@ -3587,15 +3577,7 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 		  = create_field_decl (get_identifier ("P_BOUNDS"),
 				       gnu_ptr_template, gnu_type,
 				       NULL_TREE, NULL_TREE, 0, 0);
-
-		/* Make sure we can place this into a register.  */
-		TYPE_ALIGN (gnu_type)
-		  = MIN (BIGGEST_ALIGNMENT, 2 * POINTER_SIZE);
-		TYPE_FAT_POINTER_P (gnu_type) = 1;
-
-		/* Do not emit debug info for this record type since the types
-		   of its fields are incomplete.  */
-		finish_record_type (gnu_type, fields, 0, false);
+		finish_fat_pointer_type (gnu_type, fields);
 
 		TYPE_OBJECT_RECORD_TYPE (gnu_desig_type)
 		  = make_node (RECORD_TYPE);
@@ -5125,6 +5107,28 @@  rest_of_type_decl_compilation_no_defer (
     }
 }
 
+/* Given a record type RECORD_TYPE and a list of FIELD_DECL nodes FIELD_LIST,
+   finish constructing the record type as a fat pointer type.  */
+
+static void
+finish_fat_pointer_type (tree record_type, tree field_list)
+{
+  /* Make sure we can put it into a register.  */
+  TYPE_ALIGN (record_type) = MIN (BIGGEST_ALIGNMENT, 2 * POINTER_SIZE);
+
+  /* Show what it really is.  */
+  TYPE_FAT_POINTER_P (record_type) = 1;
+
+  /* Do not emit debug info for it since the types of its fields may still be
+     incomplete at this point.  */
+  finish_record_type (record_type, field_list, 0, false);
+
+  /* Force type_contains_placeholder_p to return true on it.  Although the
+     PLACEHOLDER_EXPRs are referenced only indirectly, this isn't a pointer
+     type but the representation of the unconstrained array.  */
+  TYPE_CONTAINS_PLACEHOLDER_INTERNAL (record_type) = 2;
+}
+
 /* Finalize any From_With_Type incomplete types.  We do this after processing
    our compilation unit and after processing its spec, if this is a body.  */