Fix PR45586 (type confusion ICEs)

Mikael Morin mikael.morin@sfr.fr
Mon Feb 14 00:29:00 GMT 2011


On Sunday 13 February 2011 03:44:28 Michael Matz wrote:
> Hi,
> 
> so, after Tobias committed the fix for component_refs I've reworked my
> patch for this problem somewhat.  For gory details see the PR trail, but
> in short it's like this: FE generates a backend type per type definition
> it sees.  Variables can have attributes that modify their type (for
> instance make some subobjects/fields be TARGETable), unfortunately
> recursively.  So, in some circumstances we need to generate a new type
> hierarchy using an existing one by stripping off some flags.  For now we
> only need to strip restrictedness, recursively, for a type of variables
> marked in certain ways.
> 
> For that we invent gfc_nonrestricted_type, and use it in the right places.
> 
> One inconvenience is that the FE captures the notion of fields of an
> aggregate type (components in FE parlance) only per frontend-type, meaning
> the component reflecting 'a%member' is independend of attributes that the
> 'a' decl is given.  That's what we fix up in gfc_conv_component_ref, with
> a small cache to not have to repeatedly look this up.
> 
> I've included most suggestions from the prereview except the last, adding
>   TYPE_LANG_SPECIFIC (ret)->nonrestricted_type = ret;
> at the end of gfc_nonrestricted_type.  I haven't done that because it
> would require allocating the lang-specific type structure also for the
> newly generated 'ret' type, which I'd like to defer until it's really
> required.
> 
> For one suggestion I had to care for recursion in types (struct contains
> member of pointer to same struct, or variants thereof), making the
> function mildly more complicated, but I've put some extended comments in
> there.

Sorry for taking so long, I've been very doubtful about this error_mark_node 
thing, but got convinced in the end (maybe weariness helps ;-) ).

> 
> The testsuite went through already (no regressions), it fixes the testcase
> in question.  Full regstrap on x86_64-linux in progress.  Okay if that
> passes?

A few nits or overlooks below.


> 
> 
> Ciao,
> Michael.
> 
> fortran/
> 	PR fortran/45586
> 	* gfortran.h (struct gfc_component): Add norestrict_decl member.
> 	* trans.h (struct lang_type): Add nonrestricted_type member.
> 	* trans-expr.c (gfc_conv_component_ref): Search fields with correct
> 	parent type.
> 	* trans-types.c (gfc_nonrestricted_type): New.
> 	(gfc_sym_type): Use it.
> 
> testsuite/
> 	PR fortran/45586
> 	* gfortran.dg/lto/pr45586_0.f90: New test.
> 
> Index: trans-expr.c
> ===================================================================
> --- trans-expr.c	(Revision 170097)
> +++ trans-expr.c	(Arbeitskopie)
> @@ -504,6 +504,26 @@ gfc_conv_component_ref (gfc_se * se, gfc
>    field = c->backend_decl;
>    gcc_assert (TREE_CODE (field) == FIELD_DECL);
>    decl = se->expr;
> +
> +  /* Components can correspond to fields of different containing
> +     types, as components are created without context, whereas
> +     a concrete use of a component has the type of decl as context.
> +     So, if the type doesn't match, we search the corresponding
> +     FIELD_DECL in the parent type.  To not waste too much time
> +     we cache this result in norestrict_decl.  */
> +
> +  if (DECL_CONTEXT (field) != TREE_TYPE (decl))
> +    {
> +      tree f2 = c->norestrict_decl;
> +      if (!f2 || DECL_FIELD_CONTEXT (f2) != TREE_TYPE (decl))
Is there a reason to use DECL_FIELD_CONTEXT here and DECL_CONTEXT otherwise ?
How different are them ?

> +        for (f2 = TYPE_FIELDS (TREE_TYPE (decl)); f2; f2 = DECL_CHAIN
> (f2)) +	  if (TREE_CODE (f2) == FIELD_DECL
> +	      && DECL_NAME (f2) == DECL_NAME (field))
> +	    break;
> +      gcc_assert (f2);
> +      c->norestrict_decl = f2;
> +      field = f2;
> +    }
>    tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field),
>  			 decl, field, NULL_TREE);
> 
> Index: gfortran.h
> ===================================================================
> --- gfortran.h	(Revision 170097)
> +++ gfortran.h	(Arbeitskopie)
> @@ -934,6 +934,10 @@ typedef struct gfc_component
>    gfc_array_spec *as;
> 
>    tree backend_decl;
> +  /* Used to cache a FIELD_DECL matching this same component
> +     but applied to a different base type that was generated by
a different base type sounds a bit odd.
the target variant base type would be clearer (even if less accurate w.r.t. 
how it appears to the middle-end).

> +     gfc_nonrestricted_type.  */
> +  tree norestrict_decl;
>    locus loc;
>    struct gfc_expr *initializer;
>    struct gfc_component *next;
> Index: trans-types.c
> ===================================================================
> --- trans-types.c	(Revision 170097)
> +++ trans-types.c	(Arbeitskopie)
> @@ -1746,6 +1746,124 @@ gfc_build_pointer_type (gfc_symbol * sym
>    else
>      return build_pointer_type (type);
>  }
> +
> +/* Given a type T, returns a different type of the same structure,
> +   except that all types it refers to (recursively) are always
> +   non-restrict qualified types.  */
> +static tree
> +gfc_nonrestricted_type (tree t)
> +{
> +  tree ret = t;
> +  if (!TYPE_LANG_SPECIFIC (t))
> +    TYPE_LANG_SPECIFIC (t)
> +      = ggc_alloc_cleared_lang_type (sizeof (struct lang_type));
> +  /* If we're dealing with this very node already further up
> +     the call chain (recursion via pointers and struct members)
> +     we haven't yet determined if we really need a new type node.
> +     Assume we don't, return T itself.  */
> +  if (TYPE_LANG_SPECIFIC (t)->nonrestricted_type == error_mark_node)
> +    return t;
> +
> +  /* If we have calculated this all already, just return it.  */
> +  if (TYPE_LANG_SPECIFIC (t)->nonrestricted_type)
> +    return TYPE_LANG_SPECIFIC (t)->nonrestricted_type;
> +
> +  /* Mark this type.  */
> +  TYPE_LANG_SPECIFIC (t)->nonrestricted_type = error_mark_node;
> +
> +  switch (TREE_CODE (t))
> +    {
> +      default:
> +	break;
> +
> +      case POINTER_TYPE:
> +      case REFERENCE_TYPE:
> +	{
> +	  tree totype = gfc_nonrestricted_type (TREE_TYPE (t));
> +	  if (totype == TREE_TYPE (t))
> +	    ret = t;
> +	  else if (TREE_CODE (t) == POINTER_TYPE)
> +	    ret = build_pointer_type (totype);
> +	  else
> +	    ret = build_reference_type (totype);
> +	  ret = build_qualified_type (t, TYPE_QUALS (t) &~TYPE_QUAL_RESTRICT);
Shouldn't this be...
ret = build_qualified_type (ret, TYPE_QUALS (ret) & ~TYPE_QUAL_RESTRICT);
...if needed at all?
Also, not sure if it is applicable, but handling it the same way as in the 
other cases (via copy_node) wouldn't drop other infos (other qualifiers, 
type_lang_specific data, ...)


> +	}
> +	break;
> +
> +      case ARRAY_TYPE:
> +	{
> +	  tree elemtype = gfc_nonrestricted_type (TREE_TYPE (t));
> +	  if (elemtype == TREE_TYPE (t))
> +	    ret = t;
> +	  else
> +	    {
> +	      ret = copy_node (t);
> +	      TREE_TYPE (t) = elemtype;
I think it is TREE_TYPE (ret) here.

> +	      /* ??? Change some TYPE_LANG_SPECIFICs too?  */
You mean GFC_TYPE_ARRAY_DATAPTR_TYPE?
Yeah, it seems sensible to change it to the non-restrict type. 
For GFC_TYPE_ARRAY_BASE_DECL, looks like it can't have the restrict attribute 
currently, so no need to bother. 

> +	    }
> +	}
> +	break;
> +
> +      case RECORD_TYPE:
> +      case UNION_TYPE:
> +      case QUAL_UNION_TYPE:
> +	{
> +	  tree field, *chain;
> +	  /* First determine if we need a new type at all.
> +	     Careful, the two calls to gfc_nonrestricted_type per field
> +	     might return different values.  That happens exactly when
> +	     one of the fields reaches back to this very record type
> +	     (via pointers).  The first calls will assume that we don't
> +	     need to copy T (see the error_mark_node marking).  If there
> +	     are any reasons for copying T apart from having to copy T,
> +	     we'll indeed copy it, and the second calls to
> +	     gfc_nonrestricted_type will use that new node if they
> +	     reach back to T.  */
> +	  for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
> +	    if (TREE_CODE (field) == FIELD_DECL)
> +	      {
> +		tree elemtype = gfc_nonrestricted_type (TREE_TYPE (field));
> +		if (elemtype != TREE_TYPE (field))
> +		  break;
> +	      }
> +	  if (!field)
> +	    break;
> +	  ret = copy_node (t);
> +	  TYPE_FIELDS (ret) = NULL_TREE;
> +
> +	  /* Here we make sure that as soon as we know we have to copy
> +	     T, that also fields reaching back to us will use the new
> +	     copy.  It's okay if that copy still contains the old fields,
> +	     we won't look at them.  */
> +	  TYPE_LANG_SPECIFIC (t)->nonrestricted_type = ret;
> +	  chain = &TYPE_FIELDS (ret);
> +	  for (field = TYPE_FIELDS (t); field; field = DECL_CHAIN (field))
> +	    {
> +	      tree newfield = copy_node (field);
> +	      DECL_CONTEXT (newfield) = ret;
> +	      /* The store to DECL_CHAIN might seem redundant with the
> +	         stores to *chain, but not clearing it here would mean
> +		 leaving a chain into the old fields.  If every
> +		 our called functions would look at them confusion
> +		 will arise.  */
> +	      DECL_CHAIN (newfield) = NULL_TREE;
> +	      *chain = newfield;
> +	      chain = &DECL_CHAIN (newfield);
> +
> +	      if (TREE_CODE (field) == FIELD_DECL)
> +		{
> +		  tree elemtype = gfc_nonrestricted_type (TREE_TYPE (field));
> +		  TREE_TYPE (newfield) = elemtype;
> +		}
> +	    }
> +	  *chain = NULL_TREE;
> +	}
> +        break;
> +    }
> +  TYPE_LANG_SPECIFIC (t)->nonrestricted_type = ret;
> +  return ret;
> +}
> +
>  

>  /* Return the type for a symbol.  Special handling is required for
> character types to get the correct level of indirection.
> @@ -1796,6 +1914,9 @@ gfc_sym_type (gfc_symbol * sym)
> 
>    restricted = !sym->attr.target && !sym->attr.pointer
>                 && !sym->attr.proc_pointer && !sym->attr.cray_pointee;
> +  if (!restricted)
> +    type = gfc_nonrestricted_type (type);
> +
>    if (sym->attr.dimension)
>      {
>        if (gfc_is_nodesc_array (sym))
> Index: trans.h
> ===================================================================
> --- trans.h	(Revision 170097)
> +++ trans.h	(Arbeitskopie)
> @@ -700,6 +700,7 @@ struct GTY((variable_size))	lang_type	 {
>    tree dataptr_type;
>    tree span;
>    tree base_decl[2];
> +  tree nonrestricted_type;
>  };
> 
>  struct GTY((variable_size)) lang_decl {
> Index: testsuite/gfortran.dg/lto/pr45586_0.f90
> ===================================================================
> --- testsuite/gfortran.dg/lto/pr45586_0.f90	(Revision 0)
> +++ testsuite/gfortran.dg/lto/pr45586_0.f90	(Revision 0)
> @@ -0,0 +1,29 @@
> +! { dg-lto-do link }
> +MODULE M1see
Please indent the first line like the rest.

> +      INTEGER, PARAMETER :: dp=8
> +      TYPE realspace_grid_type
> +
> +          REAL(KIND=dp), DIMENSION ( :, :, : ), ALLOCATABLE :: r
> +
> +      END TYPE realspace_grid_type
> +      END MODULE
> +
> +      MODULE M2
> +      USE m1
> +      CONTAINS
> +      SUBROUTINE S1(x)
> +      TYPE(realspace_grid_type), POINTER :: x
> +      REAL(dp), DIMENSION(:, :, :), POINTER    :: y
> +      y=>x%r
> +      y=0
> +
> +      END SUBROUTINE
> +      END MODULE
> +
> +      USE M2
> +      TYPE(realspace_grid_type), POINTER :: x
> +      ALLOCATE(x)
> +      ALLOCATE(x%r(10,10,10))
> +      CALL S1(x)
> +      write(6,*) x%r
> +      END

Mikael 



More information about the Fortran mailing list