https://gcc.gnu.org/bugzilla/show_bug.cgi?id=127637
Bug ID: 127637
Summary: gfc_variable_attr doesn't correctly report attributes
of polymorphic symbols or components
Product: gcc
Version: 17.0
Status: UNCONFIRMED
Severity: normal
Priority: P3
Component: fortran
Assignee: unassigned at gcc dot gnu.org
Reporter: mikael at gcc dot gnu.org
Target Milestone: ---
The function gfc_variable_attr which returns the set of attributes of a data
reference, is implemented roughly as:
3042 attr = sym->attr;
3043
3044 optional = attr.optional;
...
3109 for (ref = expr->ref; ref; ref = ref->next)
3110 switch (ref->type)
3111 {
...
3141 case REF_COMPONENT:
3142 optional = false;
3143 comp = ref->u.c.component;
3144 attr = comp->attr;
...
3174 break;
...
3180 }
3181
3182 attr.dimension = dimension;
3183 attr.codimension = codimension;
3184 attr.pointer = pointer;
3185 attr.allocatable = allocatable;
3186 attr.target = target;
3187 attr.save = sym->attr.save;
3188 attr.optional = optional;
3189
3190 return attr;
So except for the dimension, codimension, pointer, allocatable, target, save
and optional attributes, the attributes are copied from the last component ref
if any, otherwise from the symbol. This is mostly good, except
gfc_fix_class_refs may introduce an intermediary component reference to the
_data component of class containers, making the attributes from the original
symbol or component invisible.
gfc_build_class_symbol does roughly:
743 if (fclass == NULL)
744 {
...
747 fclass = gfc_new_symbol (name, ns);
...
761 if (!gfc_add_component (fclass, "_data", &c))
762 return false;
...
765 c->attr.access = ACCESS_PRIVATE;
766 c->ts.u.derived = ts->u.derived;
767 c->attr.class_pointer = attr->pointer;
768 c->attr.pointer = attr->pointer || (attr->dummy &&
!attr->allocatable)
769 || attr->select_type_temporary;
770 c->attr.allocatable = attr->allocatable;
771 c->attr.dimension = attr->dimension;
772 c->attr.codimension = attr->codimension;
773 c->attr.abstract = fclass->attr.abstract;
...
803 }
...
821 fclass->attr.is_class = 1;
822 orig_ts->u.derived = fclass;
823 attr->allocatable = attr->pointer = attr->dimension =
attr->codimension = 0;
So, the allocatable, dimension and codimension attributes are moved from the
original entity to the first class container component, the pointer is cleared
in the entity and set in the class container component, and the access,
class_pointer and abstract attributes are additionally set in the class
container component. For the other attributes, they remain in the original
entity but they are hidden by the implicit _data component reference after it.
I encountered the problem on the PR127613 testcase with the contiguous
attribute. And the testcase below is another failing example with the optional
attribute which has the same problem, even if it is using a dedicated variable
to track the attribute through the reference chain.
program prog
implicit none
integer, parameter :: n = 5
type :: t
integer :: c
end type
type(t), allocatable :: x(:)
integer :: i
call sub()
contains
elemental function f(a) result(r)
type(t), optional, intent(in) :: a
integer :: r
r = 42
if (present(a)) r = a%c
end function
subroutine sub(o)
class(t), optional, intent(in) :: o(:)
integer, allocatable :: y(:)
allocate(y(n))
y(:) = f(o)
if (any(y /= 42)) error stop 1
end
end program
This fails at runtime because the scalarization is using the size of o as loop
upper bound in the scalarization of the assignment y(:) = f(o), which is an
uninitialized variable as o is absent. The scalarizer should see that o is
optional and pick the loop bound from y instead, but it doesn't happen here as
o is polymorphic and gfc_expr_attr doesn't return optional among the set of
attributes.