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.

Reply via email to