Fortran: fix assignment to allocatable scalar polymorphic component [PR121616]

Message ID 999b82a5-1210-4b0d-b83d-94b987ac4626@gmx.de
State New
Headers
Series Fortran: fix assignment to allocatable scalar polymorphic component [PR121616] |

Commit Message

Harald Anlauf Sept. 11, 2025, 6:28 p.m. UTC
  Dear all,

here's a - once found - seemingly simple and obvious fix for a memory
corruption happening when intrinsic assignment is used to set a scalar
allocatable polymorphic component of a derived type when the latter
is instanciated as an array of rank > 0.  Just get the dimension
attribute right when using gfc_variable_attr ...

The testcase is an extended version of the reporter's with unlimited
polymorphism, including another simpler one contributed by a friend.
Without the fix, both tests crash with memory corruption of various
kinds.

Regtested on x86_64-pc-linux-gnu.  OK for mainline?

If there are no objections, I would like to backport to at least
15-branch.

Thanks,
Harald
  

Comments

Jerry D Sept. 11, 2025, 7:30 p.m. UTC | #1
On 9/11/25 11:28 AM, Harald Anlauf wrote:
> Dear all,
> 
> here's a - once found - seemingly simple and obvious fix for a memory
> corruption happening when intrinsic assignment is used to set a scalar
> allocatable polymorphic component of a derived type when the latter
> is instanciated as an array of rank > 0.  Just get the dimension
> attribute right when using gfc_variable_attr ...
> 
> The testcase is an extended version of the reporter's with unlimited
> polymorphism, including another simpler one contributed by a friend.
> Without the fix, both tests crash with memory corruption of various
> kinds.
> 
> Regtested on x86_64-pc-linux-gnu.  OK for mainline?
> 
> If there are no objections, I would like to backport to at least
> 15-branch.
> 
> Thanks,
> Harald
> 

OK and backport, very simple.

Jerry
  
Harald Anlauf Sept. 11, 2025, 7:39 p.m. UTC | #2
Hi Jerry!

Am 11.09.25 um 21:30 schrieb Jerry D:
> On 9/11/25 11:28 AM, Harald Anlauf wrote:
>> Dear all,
>>
>> here's a - once found - seemingly simple and obvious fix for a memory
>> corruption happening when intrinsic assignment is used to set a scalar
>> allocatable polymorphic component of a derived type when the latter
>> is instanciated as an array of rank > 0.  Just get the dimension
>> attribute right when using gfc_variable_attr ...
>>
>> The testcase is an extended version of the reporter's with unlimited
>> polymorphism, including another simpler one contributed by a friend.
>> Without the fix, both tests crash with memory corruption of various
>> kinds.
>>
>> Regtested on x86_64-pc-linux-gnu.  OK for mainline?
>>
>> If there are no objections, I would like to backport to at least
>> 15-branch.
>>
>> Thanks,
>> Harald
>>
> 
> OK and backport, very simple.

Thanks for the review!

Pushed as r16-3813-g0899b826f7196f.

I wonder how many more cases we have in the frontend where walking
a reference chain misses similar simple things...

Harald

> Jerry
>
  
Mikael Morin Sept. 11, 2025, 8:27 p.m. UTC | #3
Le 11/09/2025 à 20:28, Harald Anlauf a écrit :
> Dear all,
> 
> here's a - once found - seemingly simple and obvious fix for a memory
> corruption happening when intrinsic assignment is used to set a scalar
> allocatable polymorphic component of a derived type when the latter
> is instanciated as an array of rank > 0.  Just get the dimension
> attribute right when using gfc_variable_attr ...
> 
> The testcase is an extended version of the reporter's with unlimited
> polymorphism, including another simpler one contributed by a friend.
> Without the fix, both tests crash with memory corruption of various
> kinds.
> 
> Regtested on x86_64-pc-linux-gnu.  OK for mainline?
> 
Hello Harald,

> diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
> index 6df95558bb1..2cb930d83b8 100644
> --- a/gcc/fortran/primary.cc
> +++ b/gcc/fortran/primary.cc
> @@ -3057,12 +3057,14 @@ gfc_variable_attr (gfc_expr *expr, gfc_typespec *ts)
>  
>  	if (comp->ts.type == BT_CLASS)
>  	  {
> +	    dimension = CLASS_DATA (comp)->attr.dimension;
>  	    codimension = CLASS_DATA (comp)->attr.codimension;
>  	    pointer = CLASS_DATA (comp)->attr.class_pointer;
>  	    allocatable = CLASS_DATA (comp)->attr.allocatable;
>  	  }
>  	else
>  	  {
> +	    dimension = comp->attr.dimension;
>  	    codimension = comp->attr.codimension;
>  	    if (expr->ts.type == BT_CLASS && strcmp (comp->name, "_data") == 0)
>  	      pointer = comp->attr.class_pointer;

I think the dimension flag should additionally be cleared if there is an 
array element reference after the component.  Otherwise one could get 
the dimension attribute for a scalar expression (say 
derived%array_comp(123)).
I don't really have a testcase that would exhibit a failure, I'm just 
being overly cautious.
Thanks for the patch in any case.
  
Harald Anlauf Sept. 11, 2025, 8:46 p.m. UTC | #4
Am 11.09.25 um 22:27 schrieb Mikael Morin:
> Le 11/09/2025 à 20:28, Harald Anlauf a écrit :
>> Dear all,
>>
>> here's a - once found - seemingly simple and obvious fix for a memory
>> corruption happening when intrinsic assignment is used to set a scalar
>> allocatable polymorphic component of a derived type when the latter
>> is instanciated as an array of rank > 0.  Just get the dimension
>> attribute right when using gfc_variable_attr ...
>>
>> The testcase is an extended version of the reporter's with unlimited
>> polymorphism, including another simpler one contributed by a friend.
>> Without the fix, both tests crash with memory corruption of various
>> kinds.
>>
>> Regtested on x86_64-pc-linux-gnu.  OK for mainline?
>>
> Hello Harald,
> 
>> diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
>> index 6df95558bb1..2cb930d83b8 100644
>> --- a/gcc/fortran/primary.cc
>> +++ b/gcc/fortran/primary.cc
>> @@ -3057,12 +3057,14 @@ gfc_variable_attr (gfc_expr *expr, 
>> gfc_typespec *ts)
>>
>>      if (comp->ts.type == BT_CLASS)
>>        {
>> +        dimension = CLASS_DATA (comp)->attr.dimension;
>>          codimension = CLASS_DATA (comp)->attr.codimension;
>>          pointer = CLASS_DATA (comp)->attr.class_pointer;
>>          allocatable = CLASS_DATA (comp)->attr.allocatable;
>>        }
>>      else
>>        {
>> +        dimension = comp->attr.dimension;
>>          codimension = comp->attr.codimension;
>>          if (expr->ts.type == BT_CLASS && strcmp (comp->name, "_data") 
>> == 0)
>>            pointer = comp->attr.class_pointer;
> 
> I think the dimension flag should additionally be cleared if there is an 
> array element reference after the component.  Otherwise one could get 
> the dimension attribute for a scalar expression (say 
> derived%array_comp(123)).
> I don't really have a testcase that would exhibit a failure, I'm just 
> being overly cautious.
> Thanks for the patch in any case.

You mean further up?

     switch (ref->type)
       {
       case REF_ARRAY:

	switch (ref->u.ar.type)
	  {
...
	  case AR_ELEMENT:
	    /* Handle coarrays.  */
	    if (ref->u.ar.dimen > 0)
	      allocatable = pointer = optional = false;
	    break;

I saw that in passing, but did not hit it in the debugging session.
I'd have to think of a more complex testcase.
  
Mikael Morin Sept. 12, 2025, 9:12 a.m. UTC | #5
Le 11/09/2025 à 22:46, Harald Anlauf a écrit :
> Am 11.09.25 um 22:27 schrieb Mikael Morin:
>> Le 11/09/2025 à 20:28, Harald Anlauf a écrit :
>>> Dear all,
>>>
>>> here's a - once found - seemingly simple and obvious fix for a memory
>>> corruption happening when intrinsic assignment is used to set a scalar
>>> allocatable polymorphic component of a derived type when the latter
>>> is instanciated as an array of rank > 0.  Just get the dimension
>>> attribute right when using gfc_variable_attr ...
>>>
>>> The testcase is an extended version of the reporter's with unlimited
>>> polymorphism, including another simpler one contributed by a friend.
>>> Without the fix, both tests crash with memory corruption of various
>>> kinds.
>>>
>>> Regtested on x86_64-pc-linux-gnu.  OK for mainline?
>>>
>> Hello Harald,
>>
>>> diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
>>> index 6df95558bb1..2cb930d83b8 100644
>>> --- a/gcc/fortran/primary.cc
>>> +++ b/gcc/fortran/primary.cc
>>> @@ -3057,12 +3057,14 @@ gfc_variable_attr (gfc_expr *expr, 
>>> gfc_typespec *ts)
>>>
>>>      if (comp->ts.type == BT_CLASS)
>>>        {
>>> +        dimension = CLASS_DATA (comp)->attr.dimension;
>>>          codimension = CLASS_DATA (comp)->attr.codimension;
>>>          pointer = CLASS_DATA (comp)->attr.class_pointer;
>>>          allocatable = CLASS_DATA (comp)->attr.allocatable;
>>>        }
>>>      else
>>>        {
>>> +        dimension = comp->attr.dimension;
>>>          codimension = comp->attr.codimension;
>>>          if (expr->ts.type == BT_CLASS && strcmp (comp->name, 
>>> "_data") == 0)
>>>            pointer = comp->attr.class_pointer;
>>
>> I think the dimension flag should additionally be cleared if there is 
>> an array element reference after the component.  Otherwise one could 
>> get the dimension attribute for a scalar expression (say 
>> derived%array_comp(123)).
>> I don't really have a testcase that would exhibit a failure, I'm just 
>> being overly cautious.
>> Thanks for the patch in any case.
> 
> You mean further up?
> 
>      switch (ref->type)
>        {
>        case REF_ARRAY:
> 
>      switch (ref->u.ar.type)
>        {
> ...
>        case AR_ELEMENT:
>          /* Handle coarrays.  */
>          if (ref->u.ar.dimen > 0)
>            allocatable = pointer = optional = false;
>          break;
> 
Yes, that's the place.

The more I look at your patch, the less I understand it.
So, given an array expression such as array(:)%scalar_comp, 
gfc_variable_attr on it would return a result without the dimension 
attribute?
  
Harald Anlauf Sept. 12, 2025, 8:51 p.m. UTC | #6
Am 12.09.25 um 11:12 schrieb Mikael Morin:
> Le 11/09/2025 à 22:46, Harald Anlauf a écrit :
>> Am 11.09.25 um 22:27 schrieb Mikael Morin:
>>> Le 11/09/2025 à 20:28, Harald Anlauf a écrit :
>>>> Dear all,
>>>>
>>>> here's a - once found - seemingly simple and obvious fix for a memory
>>>> corruption happening when intrinsic assignment is used to set a scalar
>>>> allocatable polymorphic component of a derived type when the latter
>>>> is instanciated as an array of rank > 0.  Just get the dimension
>>>> attribute right when using gfc_variable_attr ...
>>>>
>>>> The testcase is an extended version of the reporter's with unlimited
>>>> polymorphism, including another simpler one contributed by a friend.
>>>> Without the fix, both tests crash with memory corruption of various
>>>> kinds.
>>>>
>>>> Regtested on x86_64-pc-linux-gnu.  OK for mainline?
>>>>
>>> Hello Harald,
>>>
>>>> diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
>>>> index 6df95558bb1..2cb930d83b8 100644
>>>> --- a/gcc/fortran/primary.cc
>>>> +++ b/gcc/fortran/primary.cc
>>>> @@ -3057,12 +3057,14 @@ gfc_variable_attr (gfc_expr *expr, 
>>>> gfc_typespec *ts)
>>>>
>>>>      if (comp->ts.type == BT_CLASS)
>>>>        {
>>>> +        dimension = CLASS_DATA (comp)->attr.dimension;
>>>>          codimension = CLASS_DATA (comp)->attr.codimension;
>>>>          pointer = CLASS_DATA (comp)->attr.class_pointer;
>>>>          allocatable = CLASS_DATA (comp)->attr.allocatable;
>>>>        }
>>>>      else
>>>>        {
>>>> +        dimension = comp->attr.dimension;
>>>>          codimension = comp->attr.codimension;
>>>>          if (expr->ts.type == BT_CLASS && strcmp (comp->name, 
>>>> "_data") == 0)
>>>>            pointer = comp->attr.class_pointer;
>>>
>>> I think the dimension flag should additionally be cleared if there is 
>>> an array element reference after the component.  Otherwise one could 
>>> get the dimension attribute for a scalar expression (say 
>>> derived%array_comp(123)).
>>> I don't really have a testcase that would exhibit a failure, I'm just 
>>> being overly cautious.
>>> Thanks for the patch in any case.
>>
>> You mean further up?
>>
>>      switch (ref->type)
>>        {
>>        case REF_ARRAY:
>>
>>      switch (ref->u.ar.type)
>>        {
>> ...
>>        case AR_ELEMENT:
>>          /* Handle coarrays.  */
>>          if (ref->u.ar.dimen > 0)
>>            allocatable = pointer = optional = false;
>>          break;
>>
> Yes, that's the place.
> 
> The more I look at your patch, the less I understand it.
> So, given an array expression such as array(:)%scalar_comp, 
> gfc_variable_attr on it would return a result without the dimension 
> attribute?

Well, the comment before gfc_variable_attr says:

/* Given an expression that is a variable, figure out what the
    ultimate variable's type and attribute is, traversing the reference
    structures if necessary.

    This subroutine is trickier than it looks.  We start at the base
    symbol and store the attribute.  Component references load a
    completely new attribute.

...

Assuming that scalar_comp is the ultimate component, its dimension is 0.


The standard appears somewhat ambiguous on the expression you give:

9.4 Scalars

Note 2
ARRAY_PARENT(1:N)%SCALAR_FIELD  component of array section parent

9.5 Arrays

Note 3

SCALAR_PARENT%ARRAY_FIELD(1:N)               array section
SCALAR_PARENT%ARRAY_FIELD(1:N)%SCALAR_FIELD  array section
  
Mikael Morin Sept. 13, 2025, 8:54 p.m. UTC | #7
Le 12/09/2025 à 22:51, Harald Anlauf a écrit :
> Am 12.09.25 um 11:12 schrieb Mikael Morin:
>> Le 11/09/2025 à 22:46, Harald Anlauf a écrit :
>>> Am 11.09.25 um 22:27 schrieb Mikael Morin:
>>>> Le 11/09/2025 à 20:28, Harald Anlauf a écrit :
>>>>> Dear all,
>>>>>
>>>>> here's a - once found - seemingly simple and obvious fix for a memory
>>>>> corruption happening when intrinsic assignment is used to set a scalar
>>>>> allocatable polymorphic component of a derived type when the latter
>>>>> is instanciated as an array of rank > 0.  Just get the dimension
>>>>> attribute right when using gfc_variable_attr ...
>>>>>
>>>>> The testcase is an extended version of the reporter's with unlimited
>>>>> polymorphism, including another simpler one contributed by a friend.
>>>>> Without the fix, both tests crash with memory corruption of various
>>>>> kinds.
>>>>>
>>>>> Regtested on x86_64-pc-linux-gnu.  OK for mainline?
>>>>>
>>>> Hello Harald,
>>>>
>>>>> diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
>>>>> index 6df95558bb1..2cb930d83b8 100644
>>>>> --- a/gcc/fortran/primary.cc
>>>>> +++ b/gcc/fortran/primary.cc
>>>>> @@ -3057,12 +3057,14 @@ gfc_variable_attr (gfc_expr *expr, 
>>>>> gfc_typespec *ts)
>>>>>
>>>>>      if (comp->ts.type == BT_CLASS)
>>>>>        {
>>>>> +        dimension = CLASS_DATA (comp)->attr.dimension;
>>>>>          codimension = CLASS_DATA (comp)->attr.codimension;
>>>>>          pointer = CLASS_DATA (comp)->attr.class_pointer;
>>>>>          allocatable = CLASS_DATA (comp)->attr.allocatable;
>>>>>        }
>>>>>      else
>>>>>        {
>>>>> +        dimension = comp->attr.dimension;
>>>>>          codimension = comp->attr.codimension;
>>>>>          if (expr->ts.type == BT_CLASS && strcmp (comp->name, 
>>>>> "_data") == 0)
>>>>>            pointer = comp->attr.class_pointer;
>>>>
>>>> I think the dimension flag should additionally be cleared if there 
>>>> is an array element reference after the component.  Otherwise one 
>>>> could get the dimension attribute for a scalar expression (say 
>>>> derived%array_comp(123)).
>>>> I don't really have a testcase that would exhibit a failure, I'm 
>>>> just being overly cautious.
>>>> Thanks for the patch in any case.
>>>
>>> You mean further up?
>>>
>>>      switch (ref->type)
>>>        {
>>>        case REF_ARRAY:
>>>
>>>      switch (ref->u.ar.type)
>>>        {
>>> ...
>>>        case AR_ELEMENT:
>>>          /* Handle coarrays.  */
>>>          if (ref->u.ar.dimen > 0)
>>>            allocatable = pointer = optional = false;
>>>          break;
>>>
>> Yes, that's the place.
>>
>> The more I look at your patch, the less I understand it.
>> So, given an array expression such as array(:)%scalar_comp, 
>> gfc_variable_attr on it would return a result without the dimension 
>> attribute?
> 
> Well, the comment before gfc_variable_attr says:
> 
> /* Given an expression that is a variable, figure out what the
>     ultimate variable's type and attribute is, traversing the reference
>     structures if necessary.
> 
>     This subroutine is trickier than it looks.  We start at the base
>     symbol and store the attribute.  Component references load a
>     completely new attribute.
> 
The latter sentence applies to allocatable, pointer/target, etc, but I 
don't think it should apply to dimension.
Dimension is different because it's the parent reference that determines 
whether the subreference is a scalar or an array, thus whether it has 
the dimension attribute or not.

> ...
> 
> Assuming that scalar_comp is the ultimate component, its dimension is 0.
> 
Err, well, no. I mean, it depends on what's before it.
derived(123)%scalar_comp is a scalar, so it doesn't have the dimension 
attribute.
But derived(:)%scalar_comp is an array, so it has the dimension attribute.

> 
> The standard appears somewhat ambiguous on the expression you give:
> 
> 9.4 Scalars
> 
> Note 2
> ARRAY_PARENT(1:N)%SCALAR_FIELD  component of array section parent
> 
That one is definitely an array, I hope we can agree on that.
See the second sentence of 9.4.2 saying:
     A structure component may be a scalar or an array.

So the presence in the section about scalars is not an indication that 
it really is scalar.

> 9.5 Arrays
> 
> Note 3
> 
> SCALAR_PARENT%ARRAY_FIELD(1:N)               array section
> SCALAR_PARENT%ARRAY_FIELD(1:N)%SCALAR_FIELD  array section
> 

Coming back to your patch, rephrasing my previous concerns.
If I understand correctly, your patch changes the dimension attribute 
for the following cases:
                            old value   new value
1. array(i)%scalar_comp       1           0
2. array(:)%scalar_comp       1           0
3. scalar%array_comp(i)       0           1

1. is the desired change, but I think 2. and 3. are undesired.
  
Harald Anlauf Sept. 14, 2025, 7:17 p.m. UTC | #8
Am 13.09.25 um 22:54 schrieb Mikael Morin:
> Le 12/09/2025 à 22:51, Harald Anlauf a écrit :
>> Am 12.09.25 um 11:12 schrieb Mikael Morin:
>>> Le 11/09/2025 à 22:46, Harald Anlauf a écrit :
>>>> Am 11.09.25 um 22:27 schrieb Mikael Morin:
>>>>> Le 11/09/2025 à 20:28, Harald Anlauf a écrit :
>>>>>> Dear all,
>>>>>>
>>>>>> here's a - once found - seemingly simple and obvious fix for a memory
>>>>>> corruption happening when intrinsic assignment is used to set a 
>>>>>> scalar
>>>>>> allocatable polymorphic component of a derived type when the latter
>>>>>> is instanciated as an array of rank > 0.  Just get the dimension
>>>>>> attribute right when using gfc_variable_attr ...
>>>>>>
>>>>>> The testcase is an extended version of the reporter's with unlimited
>>>>>> polymorphism, including another simpler one contributed by a friend.
>>>>>> Without the fix, both tests crash with memory corruption of various
>>>>>> kinds.
>>>>>>
>>>>>> Regtested on x86_64-pc-linux-gnu.  OK for mainline?
>>>>>>
>>>>> Hello Harald,
>>>>>
>>>>>> diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
>>>>>> index 6df95558bb1..2cb930d83b8 100644
>>>>>> --- a/gcc/fortran/primary.cc
>>>>>> +++ b/gcc/fortran/primary.cc
>>>>>> @@ -3057,12 +3057,14 @@ gfc_variable_attr (gfc_expr *expr, 
>>>>>> gfc_typespec *ts)
>>>>>>
>>>>>>      if (comp->ts.type == BT_CLASS)
>>>>>>        {
>>>>>> +        dimension = CLASS_DATA (comp)->attr.dimension;
>>>>>>          codimension = CLASS_DATA (comp)->attr.codimension;
>>>>>>          pointer = CLASS_DATA (comp)->attr.class_pointer;
>>>>>>          allocatable = CLASS_DATA (comp)->attr.allocatable;
>>>>>>        }
>>>>>>      else
>>>>>>        {
>>>>>> +        dimension = comp->attr.dimension;
>>>>>>          codimension = comp->attr.codimension;
>>>>>>          if (expr->ts.type == BT_CLASS && strcmp (comp->name, 
>>>>>> "_data") == 0)
>>>>>>            pointer = comp->attr.class_pointer;
>>>>>
>>>>> I think the dimension flag should additionally be cleared if there 
>>>>> is an array element reference after the component.  Otherwise one 
>>>>> could get the dimension attribute for a scalar expression (say 
>>>>> derived%array_comp(123)).
>>>>> I don't really have a testcase that would exhibit a failure, I'm 
>>>>> just being overly cautious.
>>>>> Thanks for the patch in any case.
>>>>
>>>> You mean further up?
>>>>
>>>>      switch (ref->type)
>>>>        {
>>>>        case REF_ARRAY:
>>>>
>>>>      switch (ref->u.ar.type)
>>>>        {
>>>> ...
>>>>        case AR_ELEMENT:
>>>>          /* Handle coarrays.  */
>>>>          if (ref->u.ar.dimen > 0)
>>>>            allocatable = pointer = optional = false;
>>>>          break;
>>>>
>>> Yes, that's the place.
>>>
>>> The more I look at your patch, the less I understand it.
>>> So, given an array expression such as array(:)%scalar_comp, 
>>> gfc_variable_attr on it would return a result without the dimension 
>>> attribute?
>>
>> Well, the comment before gfc_variable_attr says:
>>
>> /* Given an expression that is a variable, figure out what the
>>     ultimate variable's type and attribute is, traversing the reference
>>     structures if necessary.
>>
>>     This subroutine is trickier than it looks.  We start at the base
>>     symbol and store the attribute.  Component references load a
>>     completely new attribute.
>>
> The latter sentence applies to allocatable, pointer/target, etc, but I 
> don't think it should apply to dimension.
> Dimension is different because it's the parent reference that determines 
> whether the subreference is a scalar or an array, thus whether it has 
> the dimension attribute or not.
> 
>> ...
>>
>> Assuming that scalar_comp is the ultimate component, its dimension is 0.
>>
> Err, well, no. I mean, it depends on what's before it.
> derived(123)%scalar_comp is a scalar, so it doesn't have the dimension 
> attribute.
> But derived(:)%scalar_comp is an array, so it has the dimension attribute.
> 
>>
>> The standard appears somewhat ambiguous on the expression you give:
>>
>> 9.4 Scalars
>>
>> Note 2
>> ARRAY_PARENT(1:N)%SCALAR_FIELD  component of array section parent
>>
> That one is definitely an array, I hope we can agree on that.
> See the second sentence of 9.4.2 saying:
>      A structure component may be a scalar or an array.
> 
> So the presence in the section about scalars is not an indication that 
> it really is scalar.
> 
>> 9.5 Arrays
>>
>> Note 3
>>
>> SCALAR_PARENT%ARRAY_FIELD(1:N)               array section
>> SCALAR_PARENT%ARRAY_FIELD(1:N)%SCALAR_FIELD  array section
>>
> 
> Coming back to your patch, rephrasing my previous concerns.
> If I understand correctly, your patch changes the dimension attribute 
> for the following cases:
>                             old value   new value
> 1. array(i)%scalar_comp       1           0
> 2. array(:)%scalar_comp       1           0
> 3. scalar%array_comp(i)       0           1
> 
> 1. is the desired change, but I think 2. and 3. are undesired.

Well, the patch changes gfc_variable_attr, but see also the comment
I cited.  This is needed that the scalarized assignment sees the
ultimate component, which is an allocatable scalar for the testcase.

I did not claim that gfc_expr_attr always returns the right attributes.
  
Mikael Morin Sept. 15, 2025, 8:56 a.m. UTC | #9
Le 14/09/2025 à 21:17, Harald Anlauf a écrit :
> Am 13.09.25 um 22:54 schrieb Mikael Morin:
>> Le 12/09/2025 à 22:51, Harald Anlauf a écrit :
>>> Am 12.09.25 um 11:12 schrieb Mikael Morin:
>>>> Le 11/09/2025 à 22:46, Harald Anlauf a écrit :
>>>>> Am 11.09.25 um 22:27 schrieb Mikael Morin:
>>>>>> Le 11/09/2025 à 20:28, Harald Anlauf a écrit :
>>>>>>> Dear all,
>>>>>>>
>>>>>>> here's a - once found - seemingly simple and obvious fix for a 
>>>>>>> memory
>>>>>>> corruption happening when intrinsic assignment is used to set a 
>>>>>>> scalar
>>>>>>> allocatable polymorphic component of a derived type when the latter
>>>>>>> is instanciated as an array of rank > 0.  Just get the dimension
>>>>>>> attribute right when using gfc_variable_attr ...
>>>>>>>
>>>>>>> The testcase is an extended version of the reporter's with unlimited
>>>>>>> polymorphism, including another simpler one contributed by a friend.
>>>>>>> Without the fix, both tests crash with memory corruption of various
>>>>>>> kinds.
>>>>>>>
>>>>>>> Regtested on x86_64-pc-linux-gnu.  OK for mainline?
>>>>>>>
>>>>>> Hello Harald,
>>>>>>
>>>>>>> diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
>>>>>>> index 6df95558bb1..2cb930d83b8 100644
>>>>>>> --- a/gcc/fortran/primary.cc
>>>>>>> +++ b/gcc/fortran/primary.cc
>>>>>>> @@ -3057,12 +3057,14 @@ gfc_variable_attr (gfc_expr *expr, 
>>>>>>> gfc_typespec *ts)
>>>>>>>
>>>>>>>      if (comp->ts.type == BT_CLASS)
>>>>>>>        {
>>>>>>> +        dimension = CLASS_DATA (comp)->attr.dimension;
>>>>>>>          codimension = CLASS_DATA (comp)->attr.codimension;
>>>>>>>          pointer = CLASS_DATA (comp)->attr.class_pointer;
>>>>>>>          allocatable = CLASS_DATA (comp)->attr.allocatable;
>>>>>>>        }
>>>>>>>      else
>>>>>>>        {
>>>>>>> +        dimension = comp->attr.dimension;
>>>>>>>          codimension = comp->attr.codimension;
>>>>>>>          if (expr->ts.type == BT_CLASS && strcmp (comp->name, 
>>>>>>> "_data") == 0)
>>>>>>>            pointer = comp->attr.class_pointer;
>>>>>>
>>>>>> I think the dimension flag should additionally be cleared if there 
>>>>>> is an array element reference after the component.  Otherwise one 
>>>>>> could get the dimension attribute for a scalar expression (say 
>>>>>> derived%array_comp(123)).
>>>>>> I don't really have a testcase that would exhibit a failure, I'm 
>>>>>> just being overly cautious.
>>>>>> Thanks for the patch in any case.
>>>>>
>>>>> You mean further up?
>>>>>
>>>>>      switch (ref->type)
>>>>>        {
>>>>>        case REF_ARRAY:
>>>>>
>>>>>      switch (ref->u.ar.type)
>>>>>        {
>>>>> ...
>>>>>        case AR_ELEMENT:
>>>>>          /* Handle coarrays.  */
>>>>>          if (ref->u.ar.dimen > 0)
>>>>>            allocatable = pointer = optional = false;
>>>>>          break;
>>>>>
>>>> Yes, that's the place.
>>>>
>>>> The more I look at your patch, the less I understand it.
>>>> So, given an array expression such as array(:)%scalar_comp, 
>>>> gfc_variable_attr on it would return a result without the dimension 
>>>> attribute?
>>>
>>> Well, the comment before gfc_variable_attr says:
>>>
>>> /* Given an expression that is a variable, figure out what the
>>>     ultimate variable's type and attribute is, traversing the reference
>>>     structures if necessary.
>>>
>>>     This subroutine is trickier than it looks.  We start at the base
>>>     symbol and store the attribute.  Component references load a
>>>     completely new attribute.
>>>
>> The latter sentence applies to allocatable, pointer/target, etc, but I 
>> don't think it should apply to dimension.
>> Dimension is different because it's the parent reference that 
>> determines whether the subreference is a scalar or an array, thus 
>> whether it has the dimension attribute or not.
>>
>>> ...
>>>
>>> Assuming that scalar_comp is the ultimate component, its dimension is 0.
>>>
>> Err, well, no. I mean, it depends on what's before it.
>> derived(123)%scalar_comp is a scalar, so it doesn't have the dimension 
>> attribute.
>> But derived(:)%scalar_comp is an array, so it has the dimension 
>> attribute.
>>
>>>
>>> The standard appears somewhat ambiguous on the expression you give:
>>>
>>> 9.4 Scalars
>>>
>>> Note 2
>>> ARRAY_PARENT(1:N)%SCALAR_FIELD  component of array section parent
>>>
>> That one is definitely an array, I hope we can agree on that.
>> See the second sentence of 9.4.2 saying:
>>      A structure component may be a scalar or an array.
>>
>> So the presence in the section about scalars is not an indication that 
>> it really is scalar.
>>
>>> 9.5 Arrays
>>>
>>> Note 3
>>>
>>> SCALAR_PARENT%ARRAY_FIELD(1:N)               array section
>>> SCALAR_PARENT%ARRAY_FIELD(1:N)%SCALAR_FIELD  array section
>>>
>>
>> Coming back to your patch, rephrasing my previous concerns.
>> If I understand correctly, your patch changes the dimension attribute 
>> for the following cases:
>>                             old value   new value
>> 1. array(i)%scalar_comp       1           0
>> 2. array(:)%scalar_comp       1           0
>> 3. scalar%array_comp(i)       0           1
>>
>> 1. is the desired change, but I think 2. and 3. are undesired.
> 
> Well, the patch changes gfc_variable_attr, but see also the comment
> I cited.  This is needed that the scalarized assignment sees the
> ultimate component, which is an allocatable scalar for the testcase.
> 
> I did not claim that gfc_expr_attr always returns the right attributes.
> 
I bet it does for some definition of "right".
Anyway, I'm propably wasting my time arguing about this.
Let's wait and see if something breaks.
  
Jerry D Sept. 15, 2025, 5:21 p.m. UTC | #10
On 9/15/25 1:56 AM, Mikael Morin wrote:
> Le 14/09/2025 à 21:17, Harald Anlauf a écrit :
>> Am 13.09.25 um 22:54 schrieb Mikael Morin:
>>> Le 12/09/2025 à 22:51, Harald Anlauf a écrit :
>>>> Am 12.09.25 um 11:12 schrieb Mikael Morin:
>>>>> Le 11/09/2025 à 22:46, Harald Anlauf a écrit :
>>>>>> Am 11.09.25 um 22:27 schrieb Mikael Morin:
>>>>>>> Le 11/09/2025 à 20:28, Harald Anlauf a écrit :
>>>>>>>> Dear all,
>>>>>>>>
>>>>>>>> here's a - once found - seemingly simple and obvious fix for a memory
>>>>>>>> corruption happening when intrinsic assignment is used to set a scalar
>>>>>>>> allocatable polymorphic component of a derived type when the latter
>>>>>>>> is instanciated as an array of rank > 0.  Just get the dimension
>>>>>>>> attribute right when using gfc_variable_attr ...
>>>>>>>>
>>>>>>>> The testcase is an extended version of the reporter's with unlimited
>>>>>>>> polymorphism, including another simpler one contributed by a friend.
>>>>>>>> Without the fix, both tests crash with memory corruption of various
>>>>>>>> kinds.
>>>>>>>>
>>>>>>>> Regtested on x86_64-pc-linux-gnu.  OK for mainline?
>>>>>>>>
>>>>>>> Hello Harald,
>>>>>>>
>>>>>>>> diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
>>>>>>>> index 6df95558bb1..2cb930d83b8 100644
>>>>>>>> --- a/gcc/fortran/primary.cc
>>>>>>>> +++ b/gcc/fortran/primary.cc
>>>>>>>> @@ -3057,12 +3057,14 @@ gfc_variable_attr (gfc_expr *expr, gfc_typespec 
>>>>>>>> *ts)
>>>>>>>>
>>>>>>>>      if (comp->ts.type == BT_CLASS)
>>>>>>>>        {
>>>>>>>> +        dimension = CLASS_DATA (comp)->attr.dimension;
>>>>>>>>          codimension = CLASS_DATA (comp)->attr.codimension;
>>>>>>>>          pointer = CLASS_DATA (comp)->attr.class_pointer;
>>>>>>>>          allocatable = CLASS_DATA (comp)->attr.allocatable;
>>>>>>>>        }
>>>>>>>>      else
>>>>>>>>        {
>>>>>>>> +        dimension = comp->attr.dimension;
>>>>>>>>          codimension = comp->attr.codimension;
>>>>>>>>          if (expr->ts.type == BT_CLASS && strcmp (comp->name, "_data") 
>>>>>>>> == 0)
>>>>>>>>            pointer = comp->attr.class_pointer;
>>>>>>>
>>>>>>> I think the dimension flag should additionally be cleared if there is an 
>>>>>>> array element reference after the component.  Otherwise one could get the 
>>>>>>> dimension attribute for a scalar expression (say derived%array_comp(123)).
>>>>>>> I don't really have a testcase that would exhibit a failure, I'm just 
>>>>>>> being overly cautious.
>>>>>>> Thanks for the patch in any case.
>>>>>>
>>>>>> You mean further up?
>>>>>>
>>>>>>      switch (ref->type)
>>>>>>        {
>>>>>>        case REF_ARRAY:
>>>>>>
>>>>>>      switch (ref->u.ar.type)
>>>>>>        {
>>>>>> ...
>>>>>>        case AR_ELEMENT:
>>>>>>          /* Handle coarrays.  */
>>>>>>          if (ref->u.ar.dimen > 0)
>>>>>>            allocatable = pointer = optional = false;
>>>>>>          break;
>>>>>>
>>>>> Yes, that's the place.
>>>>>
>>>>> The more I look at your patch, the less I understand it.
>>>>> So, given an array expression such as array(:)%scalar_comp, 
>>>>> gfc_variable_attr on it would return a result without the dimension attribute?
>>>>
>>>> Well, the comment before gfc_variable_attr says:
>>>>
>>>> /* Given an expression that is a variable, figure out what the
>>>>     ultimate variable's type and attribute is, traversing the reference
>>>>     structures if necessary.
>>>>
>>>>     This subroutine is trickier than it looks.  We start at the base
>>>>     symbol and store the attribute.  Component references load a
>>>>     completely new attribute.
>>>>
>>> The latter sentence applies to allocatable, pointer/target, etc, but I don't 
>>> think it should apply to dimension.
>>> Dimension is different because it's the parent reference that determines 
>>> whether the subreference is a scalar or an array, thus whether it has the 
>>> dimension attribute or not.
>>>
>>>> ...
>>>>
>>>> Assuming that scalar_comp is the ultimate component, its dimension is 0.
>>>>
>>> Err, well, no. I mean, it depends on what's before it.
>>> derived(123)%scalar_comp is a scalar, so it doesn't have the dimension 
>>> attribute.
>>> But derived(:)%scalar_comp is an array, so it has the dimension attribute.
>>>
>>>>
>>>> The standard appears somewhat ambiguous on the expression you give:
>>>>
>>>> 9.4 Scalars
>>>>
>>>> Note 2
>>>> ARRAY_PARENT(1:N)%SCALAR_FIELD  component of array section parent
>>>>
>>> That one is definitely an array, I hope we can agree on that.
>>> See the second sentence of 9.4.2 saying:
>>>      A structure component may be a scalar or an array.
>>>
>>> So the presence in the section about scalars is not an indication that it 
>>> really is scalar.
>>>
>>>> 9.5 Arrays
>>>>
>>>> Note 3
>>>>
>>>> SCALAR_PARENT%ARRAY_FIELD(1:N)               array section
>>>> SCALAR_PARENT%ARRAY_FIELD(1:N)%SCALAR_FIELD  array section
>>>>
>>>
>>> Coming back to your patch, rephrasing my previous concerns.
>>> If I understand correctly, your patch changes the dimension attribute for the 
>>> following cases:
>>>                             old value   new value
>>> 1. array(i)%scalar_comp       1           0
>>> 2. array(:)%scalar_comp       1           0
>>> 3. scalar%array_comp(i)       0           1
>>>
>>> 1. is the desired change, but I think 2. and 3. are undesired.
>>
>> Well, the patch changes gfc_variable_attr, but see also the comment
>> I cited.  This is needed that the scalarized assignment sees the
>> ultimate component, which is an allocatable scalar for the testcase.
>>
>> I did not claim that gfc_expr_attr always returns the right attributes.
>>
> I bet it does for some definition of "right".
> Anyway, I'm propably wasting my time arguing about this.
> Let's wait and see if something breaks.

It is never a waste of time to have open dialogue. We all learn from this 
exchange. Breaking things is also a way to learn and promote further investigation.

Cheers to all,

Jerry
  
Harald Anlauf Sept. 15, 2025, 7:33 p.m. UTC | #11
Am 15.09.25 um 19:21 schrieb Jerry D:
> On 9/15/25 1:56 AM, Mikael Morin wrote:
>> Le 14/09/2025 à 21:17, Harald Anlauf a écrit :
>>> Am 13.09.25 um 22:54 schrieb Mikael Morin:
>>>> Le 12/09/2025 à 22:51, Harald Anlauf a écrit :
>>> Well, the patch changes gfc_variable_attr, but see also the comment
>>> I cited.  This is needed that the scalarized assignment sees the
>>> ultimate component, which is an allocatable scalar for the testcase.
>>>
>>> I did not claim that gfc_expr_attr always returns the right attributes.
>>>
>> I bet it does for some definition of "right".
>> Anyway, I'm propably wasting my time arguing about this.
>> Let's wait and see if something breaks.
> 
> It is never a waste of time to have open dialogue. We all learn from 
> this exchange. Breaking things is also a way to learn and promote 
> further investigation.

Quite true.

Ideally, if we kick the tree, all bad apples (bugs) will fall down
eventually.

Regarding attributes, dimensions, and all that stuff, there is an
apparent history visible when looking at the code.  And when it
comes to component, substring, or specially inquiry references
(type, kind, real and imaginary part, all of which were added
over time), the handling seems scattered over lots of places.

I've been wondering if there is some strategy to "differentially"
debug the frontend: using a simple testcase, and replacing just
a single token by another one, and see when and how the path
splits and maybe rejoins later.

Cases at hand: pr108581.  Replacing fixed-length character by
deferred length.  Or pr121939: character(kind=4) vs. kind=1.

Cheers!

> Cheers to all,
> 
> Jerry
>
  
Mikael Morin Sept. 15, 2025, 8:08 p.m. UTC | #12
Le 15/09/2025 à 19:21, Jerry D a écrit :
> On 9/15/25 1:56 AM, Mikael Morin wrote:
>> Le 14/09/2025 à 21:17, Harald Anlauf a écrit :
>>> Am 13.09.25 um 22:54 schrieb Mikael Morin:
>>>> Le 12/09/2025 à 22:51, Harald Anlauf a écrit :
>>>>> Am 12.09.25 um 11:12 schrieb Mikael Morin:
>>>>>> Le 11/09/2025 à 22:46, Harald Anlauf a écrit :
>>>>>>> Am 11.09.25 um 22:27 schrieb Mikael Morin:
>>>>>>>> Le 11/09/2025 à 20:28, Harald Anlauf a écrit :
>>>>>>>>> Dear all,
>>>>>>>>>
>>>>>>>>> here's a - once found - seemingly simple and obvious fix for a 
>>>>>>>>> memory
>>>>>>>>> corruption happening when intrinsic assignment is used to set a 
>>>>>>>>> scalar
>>>>>>>>> allocatable polymorphic component of a derived type when the 
>>>>>>>>> latter
>>>>>>>>> is instanciated as an array of rank > 0.  Just get the dimension
>>>>>>>>> attribute right when using gfc_variable_attr ...
>>>>>>>>>
>>>>>>>>> The testcase is an extended version of the reporter's with 
>>>>>>>>> unlimited
>>>>>>>>> polymorphism, including another simpler one contributed by a 
>>>>>>>>> friend.
>>>>>>>>> Without the fix, both tests crash with memory corruption of 
>>>>>>>>> various
>>>>>>>>> kinds.
>>>>>>>>>
>>>>>>>>> Regtested on x86_64-pc-linux-gnu.  OK for mainline?
>>>>>>>>>
>>>>>>>> Hello Harald,
>>>>>>>>
>>>>>>>>> diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
>>>>>>>>> index 6df95558bb1..2cb930d83b8 100644
>>>>>>>>> --- a/gcc/fortran/primary.cc
>>>>>>>>> +++ b/gcc/fortran/primary.cc
>>>>>>>>> @@ -3057,12 +3057,14 @@ gfc_variable_attr (gfc_expr *expr, 
>>>>>>>>> gfc_typespec *ts)
>>>>>>>>>
>>>>>>>>>      if (comp->ts.type == BT_CLASS)
>>>>>>>>>        {
>>>>>>>>> +        dimension = CLASS_DATA (comp)->attr.dimension;
>>>>>>>>>          codimension = CLASS_DATA (comp)->attr.codimension;
>>>>>>>>>          pointer = CLASS_DATA (comp)->attr.class_pointer;
>>>>>>>>>          allocatable = CLASS_DATA (comp)->attr.allocatable;
>>>>>>>>>        }
>>>>>>>>>      else
>>>>>>>>>        {
>>>>>>>>> +        dimension = comp->attr.dimension;
>>>>>>>>>          codimension = comp->attr.codimension;
>>>>>>>>>          if (expr->ts.type == BT_CLASS && strcmp (comp->name, 
>>>>>>>>> "_data") == 0)
>>>>>>>>>            pointer = comp->attr.class_pointer;
>>>>>>>>
>>>>>>>> I think the dimension flag should additionally be cleared if 
>>>>>>>> there is an array element reference after the component.  
>>>>>>>> Otherwise one could get the dimension attribute for a scalar 
>>>>>>>> expression (say derived%array_comp(123)).
>>>>>>>> I don't really have a testcase that would exhibit a failure, I'm 
>>>>>>>> just being overly cautious.
>>>>>>>> Thanks for the patch in any case.
>>>>>>>
>>>>>>> You mean further up?
>>>>>>>
>>>>>>>      switch (ref->type)
>>>>>>>        {
>>>>>>>        case REF_ARRAY:
>>>>>>>
>>>>>>>      switch (ref->u.ar.type)
>>>>>>>        {
>>>>>>> ...
>>>>>>>        case AR_ELEMENT:
>>>>>>>          /* Handle coarrays.  */
>>>>>>>          if (ref->u.ar.dimen > 0)
>>>>>>>            allocatable = pointer = optional = false;
>>>>>>>          break;
>>>>>>>
>>>>>> Yes, that's the place.
>>>>>>
>>>>>> The more I look at your patch, the less I understand it.
>>>>>> So, given an array expression such as array(:)%scalar_comp, 
>>>>>> gfc_variable_attr on it would return a result without the 
>>>>>> dimension attribute?
>>>>>
>>>>> Well, the comment before gfc_variable_attr says:
>>>>>
>>>>> /* Given an expression that is a variable, figure out what the
>>>>>     ultimate variable's type and attribute is, traversing the 
>>>>> reference
>>>>>     structures if necessary.
>>>>>
>>>>>     This subroutine is trickier than it looks.  We start at the base
>>>>>     symbol and store the attribute.  Component references load a
>>>>>     completely new attribute.
>>>>>
>>>> The latter sentence applies to allocatable, pointer/target, etc, but 
>>>> I don't think it should apply to dimension.
>>>> Dimension is different because it's the parent reference that 
>>>> determines whether the subreference is a scalar or an array, thus 
>>>> whether it has the dimension attribute or not.
>>>>
>>>>> ...
>>>>>
>>>>> Assuming that scalar_comp is the ultimate component, its dimension 
>>>>> is 0.
>>>>>
>>>> Err, well, no. I mean, it depends on what's before it.
>>>> derived(123)%scalar_comp is a scalar, so it doesn't have the 
>>>> dimension attribute.
>>>> But derived(:)%scalar_comp is an array, so it has the dimension 
>>>> attribute.
>>>>
>>>>>
>>>>> The standard appears somewhat ambiguous on the expression you give:
>>>>>
>>>>> 9.4 Scalars
>>>>>
>>>>> Note 2
>>>>> ARRAY_PARENT(1:N)%SCALAR_FIELD  component of array section parent
>>>>>
>>>> That one is definitely an array, I hope we can agree on that.
>>>> See the second sentence of 9.4.2 saying:
>>>>      A structure component may be a scalar or an array.
>>>>
>>>> So the presence in the section about scalars is not an indication 
>>>> that it really is scalar.
>>>>
>>>>> 9.5 Arrays
>>>>>
>>>>> Note 3
>>>>>
>>>>> SCALAR_PARENT%ARRAY_FIELD(1:N)               array section
>>>>> SCALAR_PARENT%ARRAY_FIELD(1:N)%SCALAR_FIELD  array section
>>>>>
>>>>
>>>> Coming back to your patch, rephrasing my previous concerns.
>>>> If I understand correctly, your patch changes the dimension 
>>>> attribute for the following cases:
>>>>                             old value   new value
>>>> 1. array(i)%scalar_comp       1           0
>>>> 2. array(:)%scalar_comp       1           0
>>>> 3. scalar%array_comp(i)       0           1
>>>>
>>>> 1. is the desired change, but I think 2. and 3. are undesired.
>>>
>>> Well, the patch changes gfc_variable_attr, but see also the comment
>>> I cited.  This is needed that the scalarized assignment sees the
>>> ultimate component, which is an allocatable scalar for the testcase.
>>>
>>> I did not claim that gfc_expr_attr always returns the right attributes.
>>>
>> I bet it does for some definition of "right".
>> Anyway, I'm propably wasting my time arguing about this.
>> Let's wait and see if something breaks.
> 
> It is never a waste of time to have open dialogue. 
Yeah, well, communication can be difficult.

My premise when I started commenting was that the function should return 
a value as defined by the standard (for the standard attributes). Harald 
doesn't seem to agree with that, and without that premise the function 
is free to return any result, so my point becomes moot.

> We all learn from 
> this exchange. Breaking things is also a way to learn and promote 
> further investigation.
>
  
Mikael Morin Sept. 15, 2025, 8:32 p.m. UTC | #13
Le 15/09/2025 à 21:33, Harald Anlauf a écrit :
> Am 15.09.25 um 19:21 schrieb Jerry D:
>> On 9/15/25 1:56 AM, Mikael Morin wrote:
>>> Le 14/09/2025 à 21:17, Harald Anlauf a écrit :
>>>> Am 13.09.25 um 22:54 schrieb Mikael Morin:
>>>>> Le 12/09/2025 à 22:51, Harald Anlauf a écrit :
>>>> Well, the patch changes gfc_variable_attr, but see also the comment
>>>> I cited.  This is needed that the scalarized assignment sees the
>>>> ultimate component, which is an allocatable scalar for the testcase.
>>>>
>>>> I did not claim that gfc_expr_attr always returns the right attributes.
>>>>
>>> I bet it does for some definition of "right".
>>> Anyway, I'm propably wasting my time arguing about this.
>>> Let's wait and see if something breaks.
>>
>> It is never a waste of time to have open dialogue. We all learn from 
>> this exchange. Breaking things is also a way to learn and promote 
>> further investigation.
> 
> Quite true.
> 
> Ideally, if we kick the tree, all bad apples (bugs) will fall down
> eventually.
> 
> Regarding attributes, dimensions, and all that stuff, there is an
> apparent history visible when looking at the code.  And when it
> comes to component, substring, or specially inquiry references
> (type, kind, real and imaginary part, all of which were added
> over time), the handling seems scattered over lots of places.
> 
> I've been wondering if there is some strategy to "differentially"
> debug the frontend: using a simple testcase, and replacing just
> a single token by another one, and see when and how the path
> splits and maybe rejoins later.
> 
Maybe you can use code coverage data, but I'm not aware of any 
ready-made diff tool for it.  gcov can produce json data with the 
--json-format argument, that can be a good starting point.
  
Harald Anlauf Sept. 15, 2025, 8:44 p.m. UTC | #14
Am 15.09.25 um 22:32 schrieb Mikael Morin:
> Le 15/09/2025 à 21:33, Harald Anlauf a écrit :
>> I've been wondering if there is some strategy to "differentially"
>> debug the frontend: using a simple testcase, and replacing just
>> a single token by another one, and see when and how the path
>> splits and maybe rejoins later.
>>
> Maybe you can use code coverage data, but I'm not aware of any ready- 
> made diff tool for it.  gcov can produce json data with the --json- 
> format argument, that can be a good starting point.

I have no idea how to use that.

What I meant: the modified token may show up e.g. in a variable decl,
and when it is passed to some function in trans*.cc, that tiny
difference evolves etc.

I just get overwhelmed by all the forest I usually end up with,
and hardly see the tiny little twig that counts.
  

Patch

From 0899b826f7196f609fc8991456eb728802061318 Mon Sep 17 00:00:00 2001
From: Harald Anlauf <anlauf@gmx.de>
Date: Thu, 11 Sep 2025 20:17:31 +0200
Subject: [PATCH] Fortran: fix assignment to allocatable scalar polymorphic
 component [PR121616]

	PR fortran/121616

gcc/fortran/ChangeLog:

	* primary.cc (gfc_variable_attr): Properly set dimension attribute
	from a component ref.

gcc/testsuite/ChangeLog:

	* gfortran.dg/alloc_comp_assign_17.f90: New test.
---
 gcc/fortran/primary.cc                        |  2 +
 .../gfortran.dg/alloc_comp_assign_17.f90      | 96 +++++++++++++++++++
 2 files changed, 98 insertions(+)
 create mode 100644 gcc/testsuite/gfortran.dg/alloc_comp_assign_17.f90

diff --git a/gcc/fortran/primary.cc b/gcc/fortran/primary.cc
index 6df95558bb1..2cb930d83b8 100644
--- a/gcc/fortran/primary.cc
+++ b/gcc/fortran/primary.cc
@@ -3057,12 +3057,14 @@  gfc_variable_attr (gfc_expr *expr, gfc_typespec *ts)
 
 	if (comp->ts.type == BT_CLASS)
 	  {
+	    dimension = CLASS_DATA (comp)->attr.dimension;
 	    codimension = CLASS_DATA (comp)->attr.codimension;
 	    pointer = CLASS_DATA (comp)->attr.class_pointer;
 	    allocatable = CLASS_DATA (comp)->attr.allocatable;
 	  }
 	else
 	  {
+	    dimension = comp->attr.dimension;
 	    codimension = comp->attr.codimension;
 	    if (expr->ts.type == BT_CLASS && strcmp (comp->name, "_data") == 0)
 	      pointer = comp->attr.class_pointer;
diff --git a/gcc/testsuite/gfortran.dg/alloc_comp_assign_17.f90 b/gcc/testsuite/gfortran.dg/alloc_comp_assign_17.f90
new file mode 100644
index 00000000000..7a659f2e0c0
--- /dev/null
+++ b/gcc/testsuite/gfortran.dg/alloc_comp_assign_17.f90
@@ -0,0 +1,96 @@ 
+! { dg-do run }
+! PR fortran/121616
+!
+! Test fix for intrinsic assignment to allocatable scalar polymorphic component
+
+program p
+  call pr121616 ()
+  call test_ts  ()
+end
+
+! Derived from original PR (contributed by Jean Vézina)
+subroutine pr121616 ()
+  implicit none
+  integer :: i
+  type general
+     class(*), allocatable :: x
+  end type general
+  type(general) :: a(4), b(4)
+  ! Intrinsic assignment to a variable of unlimited polymorphic type
+  a(1)%x = 1
+  a(2)%x = 3.14
+  a(3)%x = .true.
+  a(4)%x = 'abc'
+  ! The workaround was to use a structure constructor
+  b(1) = general(1)
+  b(2) = general(3.14)
+  b(3) = general(.true.)
+  b(4) = general('abc') 
+  do i = 1, 4
+     if (.not. allocated (a(i)%x)) stop 10+i
+     if (.not. allocated (b(i)%x)) stop 20+i
+     call prt (a(i)%x, b(i)%x)
+  end do
+  do i = 1, 4
+     deallocate (a(i)%x, b(i)%x)
+  end do
+contains
+  subroutine prt (x, y)
+    class(*), intent(in) :: x, y
+    select type (v=>x)
+    type is (integer)
+       print *,v
+    type is (real)
+       print *,v
+    type is (logical)
+       print *,v
+    type is (character(*))
+       print *,v
+    class default
+       error stop 99
+    end select
+    if (.not. same_type_as (x, y)) stop 30+i
+  end subroutine prt
+end
+
+! Contributed by a friend (private communication)
+subroutine test_ts ()
+  implicit none
+
+  type :: t_inner
+    integer :: i
+  end type
+
+  type :: t_outer
+    class(t_inner), allocatable :: inner
+  end type
+
+  class(t_inner), allocatable :: inner
+  type(t_outer),  allocatable :: outer(:)
+  integer :: i
+
+  allocate(t_inner :: inner)
+  inner% i = 0
+
+  !------------------------------------------------
+  ! Size of outer must be > 1 for the bug to appear
+  !------------------------------------------------
+  allocate(outer(2))
+
+  !------------------------------
+  ! Loop is necessary for the bug
+  !------------------------------
+  do i = 1, size(outer)
+    write(*,*) i
+    !----------------------------------------------------
+    ! Expect intrinsic assignment to polymorphic variable
+    !----------------------------------------------------
+    outer(i)% inner = inner
+    deallocate (outer(i)% inner)
+  end do
+
+  write(*,*) 'Loop DONE'
+  deallocate(outer)
+  deallocate(inner)
+  write(*,*) 'Dellocation DONE'
+end
-- 
2.51.0