[PATCH 0/9] fortran: array descriptor part 7: Scalar descriptor init tweaks [PR122521]

Jerry D jvdelisle2@gmail.com
Mon Sep 14 19:48:43 GMT 2026


As I state at the bottom of all this, Part 6 is approved when you are ready.

See further below, all good.

On 9/14/26 4:47 AM, Mikael Morin wrote:
> Le 12/09/2026 à 21:40, Jerry D a écrit :
>> On 9/3/26 12:27 PM, Mikael Morin wrote:
>>> From: Mikael Morin <mikael@gcc.gnu.org>
>>>
>>> Hello,
>>>
>>> this is the seventh part of the array descriptor series.  The previous part,
>>> still awaiting review, isolated the initialization of scalar descriptors to
>>> three dedicated functions.  These three functions do more or less the same
>>> thing, but with subtle differences, either caused by bugs, useless code, or
>>> different requirements or assumptions about their input.
>>>
>>> This part fixes the bugs, removes useless differences and unifies the three
>>> implementations.

--- snip ---

>> Nit, same function: the explanatory comment sits between the break
>> and the fall-through marker, reading as if it belonged to the break:
>>
>>        case BT_CLASS:
>>          if (VOID_TYPE_P (etype))
>>            break;
>>          /* For classes, the element length isn't a known constant, ... */
>>          /* Fall through.  */
>>        default:
>>
>> Clearer above the case label.
> Do you mean like this?
> 
>        /* For classes, ... */
>        case BT_CLASS:
>          if (VOID_TYPE_P (etype))
>            break;
>          /* Fall through.  */
>        default:
> 

It was not clear to me if the comment applied to the if clause or explaining why 
  fall through.

          case BT_CLASS:
	   /* For classes, ... */   ?????
	   if (VOID_TYPE_P (etype))
	   break;
	   /* Fall through.  */
          default:


>> == Patch 4: gcc_unreachable, and duplicated ref walking ==
>>
>> 1. gcc_unreachable on the unexpected shape:
>>
>>      tree class_ref;
>>      if (!is_polymorphic_ref (scalar, &class_ref))
>>        gcc_unreachable ();
>>
>>    Patch 3, immediately before, exists precisely because the input is
>>    not always a class container reference.   Turning the remaining
>>    unexpected shapes into a hard abort trades a wrong-but-working
>>    result for an ICE.
> The function is only used from gfc_conv_class_to_class, so I'm pretty sure the 
> input is a polymorphic reference.  But admittedly there is no strong guarantee.
> 
>>    If the invariant does hold after patch 3,
>>    gcc_checking_assert states it without aborting release compilers.
> OK, I can do that.
> 
>>
>>    Also class_ref is left uninitialized on the false path, which some
>>    configurations will flag as -Wmaybe-uninitialized.
> Ok, will fix.
> 
>>
>> 2. Duplicated ref walking.  After this patch, is_polymorphic_ref has
>>    already located the container, yet the test patch 3 added
>>    re-derives it:
>>
>>      if (GFC_CLASS_TYPE_P (TREE_TYPE (tmp))
>>          || (POINTER_TYPE_P (TREE_TYPE (tmp))
>>              && GFC_CLASS_TYPE_P (TREE_TYPE (TREE_TYPE (tmp)))))
>>        tmp = gfc_class_data_get (tmp);
>>
>>    Deriving tmp from class_ref would drop it.  Keeping patch 3
>>    separate makes sense if it may want backporting, but patch 4 could
>>    clean up.
> There is indeed ref walking that is redundant, to avoid creating a new data 
> reference when the input already has what's needed.  I'll see what can be done; 
> the function has to accept several input patterns, which doesn't help.  Just 
> adding the data to class_ref won't work for assumed rank scalar inputs, having 
> pattern class->_data.data and for which the tmp should be the same class- 
>  >_data.data.
> 
>>
>> == Patch 6: stale libgfortran hunk; span left indeterminate ==
>>
>> 1. The libgfortran hunk is stale (needs resolving).  Mainline
>>    5e8f400f12c (PR126964, 2026-09-01) rewrote that check two days
>>    before this posting.  associated() now reads:
>>
>>        /* Require that the storage sequences are the same.  */
>>        if (GFC_DESCRIPTOR_SIZE (pointer) != GFC_DESCRIPTOR_SIZE (target)
>>            && GFC_DESCRIPTOR_SPAN (pointer) != GFC_DESCRIPTOR_SPAN (target))
>>          return 0;
>>
>>    The line the patch deletes no longer exists, so patch 6 does not
>>    apply.  I tested with that hunk dropped; nothing in the testsuite
>>    depended on it.
> Yes, the plan is to remove the span check to fix PR127233, and then associated.c 
> no longer needs any change.
> 
> You've had conflict issues with the part 5 series, so I've decided to post 
> patches that were sitting on the previous series strictly as posted, not on a 
> newer rebased variant.   Of course I can't both do that and integrate changes 
> from trunk at the same time.

I completely get it. Its complicated.

> 
>>
>> 2. The span is left indeterminate, not zeroed.  This is my main
>>    concern.  Removing the initialization does not set the span to
>>    anything -- it leaves whatever the descriptor variable held.
>>    gfc_conv_scalar_to_descriptor builds it with gfc_create_var, so
>>    that is indeterminate stack contents, not zero.  Confirmed by tree
>>    dump for a scalar passed to an assumed-rank dummy:
>>
>>        before:  desc.data = (void * restrict) &i;
>>                 desc.span = (integer(kind=8)) desc.0.dtype.elem_len;
>>        after:   desc.data = (void * restrict) &i;
>>
>>    Two reasons this matters more than "a scalar has one element":
>>
>>      - The library already defines a meaning for an unset span.  See
>>        stride_in_bytes() in associated.c:
>>
>>            index_type span = GFC_DESCRIPTOR_SPAN (desc);
>>            if (span == 0)
>>              span = GFC_DESCRIPTOR_SIZE (desc);
>>
>>        That contract wants 0, and 0 is exactly what the patch does
>>        not write.
> stride_in_bytes is only used in a loop guarded by rank, so I don't think it 
> matters.

OK

> 
>>
>>      - There is a rank-0 span read that is not guarded by rank.  In
>>        libgfortran/caf/single.c:696:
>>
>>            size_t dsize = opt_dst_desc->span;
>>            for (int i = 0; i < GFC_DESCRIPTOR_RANK (opt_dst_desc); ++i)
>>              dsize *= GFC_DESCRIPTOR_EXTENT (opt_dst_desc, i);
>>            memcpy (old_dst_data_ptr, opt_dst_desc->base_addr, dsize);
>>
>>        For rank 0 the loop body never executes, so dsize *is* the
>>        span and becomes a memcpy length directly.
> OK, that one is possibly bad, but note that a 0 value isn't much better.
> That code looks dubious in any case.  It doesn't seem to support span != elem_len.
> 
>>
>>    Also worth noting the blast radius: gfc_conv_scalar_to_descriptor
>>    has 19 call sites across trans.cc, trans-array.cc, trans-expr.cc,
>>    trans-decl.cc, trans-intrinsic.cc and trans-openmp.cc, so this is
>>    not confined to the polymorphic-scalar case.
>>
>>    Suggestion: set the span explicitly to 0 in the scalar case rather
>>    than not setting it.  That honours the convention the library
>>    already implements, costs one store, and makes the libgfortran
>>    hunk in item 1 unnecessary.
> I'm not that sure there is such a convention about 0 span; is it documented 
> anywhere?.  The caf/single.c snippet you quote above doesn't have it at least.
> 
> Either the span is really useless and keeping it undefined is fine, or it is 
> used and it should to be set to the right value.  I would rather drop the patch 
> than set the span to some wrong value.
> 
> Anyway, there seems to be some controversy about this, so maybe it's best to 
> submit the patch separatedly from the rest.  Nothing depends on it.
> 

No need for another go around on this.>>
>>    I did not manage to build a failing testcase -- scalar and class
>>    coarray transfers behave identically before and after in both
>>    -fcoarray=single and -fcoarray=lib -- so this is latent rather
>>    than demonstrated.
>>
> 
>> == Patch 9: unlimited polymorphic character ==
>>
>> gfc_vptr_size_get gives the vptr _size with no _len scaling, so for
>> CLASS(*) holding a character the element length is the kind size, not
>> the character length:
>>
>>     character(len=7) :: c
>>     class(*), allocatable :: y;  allocate (y, source=c)
>>     ! passed on to a CLASS(*) :: a(..) dummy
>>     sizeof(a)  =>  1,  expected 7
>>
>> This is pre-existing -- I measured the same value with and without
>> the series, so it is not a regression -- but since patch 9's purpose
>> is to get the polymorphic elem_len right, it looks like an
>> incompleteness.  gfc_resize_class_size_with_len (trans.cc) exists for
>> this, and gfc_get_span already uses it on the equivalent path.  Was
>> the unlimited polymorphic case meant to be covered here?
> Not really.  In fact this patch didn't exist initially.  But patch 1 was so 
> obviously insufficient that I had to add this one.
> I have created a new PR:
> https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127384
> 

OK

>>
>> One thing I checked and withdrew: I initially thought the vptr load
>> could fault for an absent optional polymorphic actual, since the guard
>> tests the vptr value and loading it dereferences the container.  It
>> cannot: gfc_conv_class_to_class wraps the whole block in a presence
>> COND_EXPR, so the load is already guarded.  Verified at run time with
>> an absent optional class scalar passed to an assumed-rank dummy.
> Thanks for checking.
> What I wondered myself after writing the patch is whether I should guard with a 
> check on the _vptr or on the _data.  The patch wasn't regressing so I kept the 
> _vptr check without looking any further.


All good, by the way, I have no comments on part 6 so consider it good to go 
when you are ready.

Cheers,

Jerry



More information about the Fortran mailing list