Patchwork [Ada] Fix ICE during inlining

login
register
mail settings
Submitter Eric Botcazou
Date Nov. 18, 2010, 6:48 p.m.
Message ID <201011181948.07973.ebotcazou@adacore.com>
Download mbox | patch
Permalink /patch/72134/
State New
Headers show

Comments

Eric Botcazou - Nov. 18, 2010, 6:48 p.m.
This is a regression present on the mainline.  The attached testcase triggers 
an ICE in the inliner because the function being inlined uses the target's 
return-by-reference mechanism without having the DECL_BY_REFERENCE flag set on 
its RESULT_DECL.

Tested on i586-suse-linux, applied on the mainline


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

	* gcc-interface/decl.c (gnat_to_gnu_entity) <E_Subprogram_Type>: Also
	use return-by-invisible-reference if the return type is By_Reference.
	Tidy up and skip the processing of the return type if it is void.


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

	* gnat.dg/atomic4.ad[sb]: New test.
	* gnat.dg/volatile4.adb: Likewise.

Patch

Index: gcc-interface/decl.c
===================================================================
--- gcc-interface/decl.c	(revision 166899)
+++ gcc-interface/decl.c	(working copy)
@@ -3827,9 +3827,9 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 
     /* Subprogram Entities
 
-       The following access functions are defined for subprograms (functions
-       or procedures):
+       The following access functions are defined for subprograms:
 
+		Etype       	Return type or Standard_Void_Type.
 		First_Formal	The first formal parameter.
 		Is_Imported     Indicates that the subprogram has appeared in
 				an INTERFACE or IMPORT pragma.  For now we
@@ -3837,10 +3837,6 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 		Is_Exported     Likewise but for an EXPORT pragma.
 		Is_Inlined      True if the subprogram is to be inlined.
 
-       In addition for function subprograms we have:
-
-		Etype       	Return type of the function.
-
        Each parameter is first checked by calling must_pass_by_ref on its
        type to determine if it is passed by reference.  For parameters which
        are copied in, if they are Ada In Out or Out parameters, their return
@@ -3873,18 +3869,16 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
     case E_Function:
     case E_Procedure:
       {
+	/* The type returned by a function or else Standard_Void_Type for a
+	   procedure.  */
+	Entity_Id gnat_return_type = Etype (gnat_entity);
+	tree gnu_return_type;
 	/* The first GCC parameter declaration (a PARM_DECL node).  The
 	   PARM_DECL nodes are chained through the TREE_CHAIN field, so this
 	   actually is the head of this parameter list.  */
 	tree gnu_param_list = NULL_TREE;
 	/* Likewise for the stub associated with an exported procedure.  */
 	tree gnu_stub_param_list = NULL_TREE;
-	/* The type returned by a function.  If the subprogram is a procedure
-	   this type should be void_type_node.  */
-	tree gnu_return_type = void_type_node;
-	/* List of fields in return type of procedure with copy-in copy-out
-	   parameters.  */
-	tree gnu_field_list = NULL_TREE;
 	/* Non-null for subprograms containing parameters passed by copy-in
 	   copy-out (Ada In Out or Out parameters not passed by reference),
 	   in which case it is the list of nodes used to specify the values
@@ -3894,6 +3888,9 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 	   corresponding to that field.  This list will be saved in the
 	   TYPE_CI_CO_LIST field of the FUNCTION_TYPE node we create.  */
 	tree gnu_cico_list = NULL_TREE;
+	/* List of fields in return type of procedure with copy-in copy-out
+	   parameters.  */
+	tree gnu_field_list = NULL_TREE;
 	/* If an import pragma asks to map this subprogram to a GCC builtin,
 	   this is the builtin DECL node.  */
 	tree gnu_builtin_decl = NULL_TREE;
@@ -3905,7 +3902,6 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 	bool public_flag = Is_Public (gnat_entity) || imported_p;
 	bool extern_flag
 	  = (Is_Public (gnat_entity) && !definition) || imported_p;
-
        /* The semantics of "pure" in Ada essentially matches that of "const"
           in the back-end.  In particular, both properties are orthogonal to
           the "nothrow" property if the EH circuitry is explicit in the
@@ -3917,7 +3913,6 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 	bool const_flag
 	  = (Exception_Mechanism == Back_End_Exceptions
 	     && Is_Pure (gnat_entity));
-
 	bool volatile_flag = No_Return (gnat_entity);
 	bool return_by_direct_ref_p = false;
 	bool return_by_invisi_ref_p = false;
@@ -3942,8 +3937,7 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 	    if (Ekind (Alias (gnat_entity)) == E_Enumeration_Literal)
 	      gnat_to_gnu_entity (Etype (Alias (gnat_entity)), NULL_TREE, 0);
 
-	    gnu_decl = gnat_to_gnu_entity (Alias (gnat_entity),
-					   gnu_expr, 0);
+	    gnu_decl = gnat_to_gnu_entity (Alias (gnat_entity), gnu_expr, 0);
 
 	    /* Elaborate any Itypes in the parameters of this entity.  */
 	    for (gnat_temp = First_Formal_With_Extras (gnat_entity);
@@ -3978,97 +3972,92 @@  gnat_to_gnu_entity (Entity_Id gnat_entit
 	   In the current state we neither warn nor err, and calls will just
 	   be handled as for regular subprograms.  */
 
-	if (kind == E_Function || kind == E_Subprogram_Type)
-	  gnu_return_type = gnat_to_gnu_type (Etype (gnat_entity));
-
-	/* If this function returns by reference, make the actual return
-	   type of this function the pointer and mark the decl.  */
-	if (Returns_By_Ref (gnat_entity))
-	  {
-	    gnu_return_type = build_pointer_type (gnu_return_type);
-	    return_by_direct_ref_p = true;
+	/* Look into the return type and get its associated GCC tree.  If it
+	   is not void, compute various flags for the subprogram type.  */
+	if (Ekind (gnat_return_type) == E_Void)
+	  gnu_return_type = void_type_node;
+	else
+	  {
+	    gnu_return_type = gnat_to_gnu_type (gnat_return_type);
+
+	    /* If this function returns by reference, make the actual return
+	       type the pointer type and make a note of that.  */
+	    if (Returns_By_Ref (gnat_entity))
+	      {
+		gnu_return_type = build_pointer_type (gnu_return_type);
+		return_by_direct_ref_p = true;
+	      }
+
+	    /* If we are supposed to return an unconstrained array type, make
+	       the actual return type the fat pointer type.  */
+	    else if (TREE_CODE (gnu_return_type) == UNCONSTRAINED_ARRAY_TYPE)
+	      {
+		gnu_return_type = TREE_TYPE (gnu_return_type);
+		return_unconstrained_p = true;
+	      }
+
+	    /* Likewise, if the return type requires a transient scope, the
+	       return value will be allocated on the secondary stack so the
+	       actual return type is the pointer type.  */
+	    else if (Requires_Transient_Scope (gnat_return_type))
+	      {
+		gnu_return_type = build_pointer_type (gnu_return_type);
+		return_unconstrained_p = true;
+	      }
+
+	    /* If the Mechanism is By_Reference, ensure this function uses the
+	       target's by-invisible-reference mechanism, which may not be the
+	       same as above (e.g. it might be passing an extra parameter).  */
+	    else if (kind == E_Function
+		     && Mechanism (gnat_entity) == By_Reference)
+	      return_by_invisi_ref_p = true;
+
+	    /* Likewise, if the return type is itself By_Reference.  */
+	    else if (TREE_ADDRESSABLE (gnu_return_type))
+	      return_by_invisi_ref_p = true;
+
+	    /* If the type is a padded type and the underlying type would not
+	       be passed by reference or the function has a foreign convention,
+	       return the underlying type.  */
+	    else if (TYPE_IS_PADDING_P (gnu_return_type)
+		     && (!default_pass_by_ref
+			  (TREE_TYPE (TYPE_FIELDS (gnu_return_type)))
+			 || Has_Foreign_Convention (gnat_entity)))
+	      gnu_return_type = TREE_TYPE (TYPE_FIELDS (gnu_return_type));
+
+	    /* If the return type is unconstrained, that means it must have a
+	       maximum size.  Use the padded type as the effective return type.
+	       And ensure the function uses the target's by-invisible-reference
+	       mechanism to avoid copying too much data when it returns.  */
+	    if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_return_type)))
+	      {
+		gnu_return_type
+		  = maybe_pad_type (gnu_return_type,
+				    max_size (TYPE_SIZE (gnu_return_type),
+					      true),
+				    0, gnat_entity, false, false, false, true);
+		return_by_invisi_ref_p = true;
+	      }
+
+	    /* If the return type has a size that overflows, we cannot have
+	       a function that returns that type.  This usage doesn't make
+	       sense anyway, so give an error here.  */
+	    if (TYPE_SIZE_UNIT (gnu_return_type)
+		&& TREE_CONSTANT (TYPE_SIZE_UNIT (gnu_return_type))
+		&& TREE_OVERFLOW (TYPE_SIZE_UNIT (gnu_return_type)))
+	      {
+		post_error ("cannot return type whose size overflows",
+			    gnat_entity);
+		gnu_return_type = copy_node (gnu_return_type);
+		TYPE_SIZE (gnu_return_type) = bitsize_zero_node;
+		TYPE_SIZE_UNIT (gnu_return_type) = size_zero_node;
+		TYPE_MAIN_VARIANT (gnu_return_type) = gnu_return_type;
+		TYPE_NEXT_VARIANT (gnu_return_type) = NULL_TREE;
+	      }
 	  }
 
-	/* If the Mechanism is By_Reference, ensure this function uses the
-	   target's by-invisible-reference mechanism, which may not be the
-	   same as above (e.g. it might be passing an extra parameter).
-
-	   Prior to GCC 4, this was handled by just setting TREE_ADDRESSABLE
-	   on the result type.  Everything required to pass by invisible
-	   reference using the target's mechanism (e.g. an extra parameter)
-	   was handled at RTL expansion time.
-
-	   This doesn't work with GCC 4 any more for several reasons.  First,
-	   the gimplification process might need to create temporaries of this
-	   type and the gimplifier ICEs on such attempts; that's why the flag
-	   is now set on the function type instead.  Second, the middle-end
-	   now also relies on a different attribute, DECL_BY_REFERENCE on the
-	   RESULT_DECL, and expects the by-invisible-reference-ness to be made
-	   explicit in the function body.  */
-	else if (kind == E_Function && Mechanism (gnat_entity) == By_Reference)
-	  return_by_invisi_ref_p = true;
-
-	/* If we are supposed to return an unconstrained array, actually return
-	   a fat pointer and make a note of that.  */
-	else if (TREE_CODE (gnu_return_type) == UNCONSTRAINED_ARRAY_TYPE)
-	  {
-	    gnu_return_type = TREE_TYPE (gnu_return_type);
-	    return_unconstrained_p = true;
-	  }
-
-	/* If the type requires a transient scope, the result is allocated
-	   on the secondary stack, so the result type of the function is
-	   just a pointer.  */
-	else if (Requires_Transient_Scope (Etype (gnat_entity)))
-	  {
-	    gnu_return_type = build_pointer_type (gnu_return_type);
-	    return_unconstrained_p = true;
-	  }
-
-	/* If the type is a padded type and the underlying type would not
-	   be passed by reference or this function has a foreign convention,
-	   return the underlying type.  */
-	else if (TYPE_IS_PADDING_P (gnu_return_type)
-		 && (!default_pass_by_ref (TREE_TYPE
-					   (TYPE_FIELDS (gnu_return_type)))
-		     || Has_Foreign_Convention (gnat_entity)))
-	  gnu_return_type = TREE_TYPE (TYPE_FIELDS (gnu_return_type));
-
-	/* If the return type is unconstrained, that means it must have a
-	   maximum size.  Use the padded type as the effective return type.
-	   And ensure the function uses the target's by-invisible-reference
-	   mechanism to avoid copying too much data when it returns.  */
-	if (CONTAINS_PLACEHOLDER_P (TYPE_SIZE (gnu_return_type)))
-	  {
-	    gnu_return_type
-	      = maybe_pad_type (gnu_return_type,
-				max_size (TYPE_SIZE (gnu_return_type), true),
-				0, gnat_entity, false, false, false, true);
-	    return_by_invisi_ref_p = true;
-	  }
-
-	/* If the return type has a size that overflows, we cannot have
-	   a function that returns that type.  This usage doesn't make
-	   sense anyway, so give an error here.  */
-	if (TYPE_SIZE_UNIT (gnu_return_type)
-	    && TREE_CONSTANT (TYPE_SIZE_UNIT (gnu_return_type))
-	    && TREE_OVERFLOW (TYPE_SIZE_UNIT (gnu_return_type)))
-	  {
-	    post_error ("cannot return type whose size overflows",
-			gnat_entity);
-	    gnu_return_type = copy_node (gnu_return_type);
-	    TYPE_SIZE (gnu_return_type) = bitsize_zero_node;
-	    TYPE_SIZE_UNIT (gnu_return_type) = size_zero_node;
-	    TYPE_MAIN_VARIANT (gnu_return_type) = gnu_return_type;
-	    TYPE_NEXT_VARIANT (gnu_return_type) = NULL_TREE;
-	  }
-
-	/* Look at all our parameters and get the type of
-	   each.  While doing this, build a copy-out structure if
-	   we need one.  */
-
-	/* Loop over the parameters and get their associated GCC tree.
-	   While doing this, build a copy-out structure if we need one.  */
+	/* Loop over the parameters and get their associated GCC tree.  While
+	   doing this, build a copy-in copy-out structure if we need one.  */
 	for (gnat_param = First_Formal_With_Extras (gnat_entity), parmnum = 0;
 	     Present (gnat_param);
 	     gnat_param = Next_Formal_With_Extras (gnat_param), parmnum++)