continue;
}
+ /* Addressing PR82943, this will fix the issue where a function or
+ subroutine is declared as not a member of the PDT instance.
+ The reason for this is because the PDT instance did not have access
+ to its template's f2k_derived namespace in order to find the
+ typebound procedures.
+
+ The number of references to the PDT template's f2k_derived will
+ ensure that f2k_derived is properly freed later on. */
+
+ if (!instance->f2k_derived && pdt->f2k_derived)
+ {
+ instance->f2k_derived = pdt->f2k_derived;
+ instance->f2k_derived->refs++;
+ }
+
/* Set the component kind using the parameterized expression. */
if ((c1->ts.kind == 0 || c1->ts.type == BT_CHARACTER)
&& c1->kind_expr != NULL)
gfc_typebound_proc* gfc_get_typebound_proc (gfc_typebound_proc*);
gfc_symbol* gfc_get_derived_super_type (gfc_symbol*);
bool gfc_type_is_extension_of (gfc_symbol *, gfc_symbol *);
+bool gfc_pdt_is_instance_of (gfc_symbol *, gfc_symbol *);
bool gfc_type_compatible (gfc_typespec *, gfc_typespec *);
void gfc_copy_formal_args_intr (gfc_symbol *, gfc_intrinsic_sym *,
goto error;
}
- if (CLASS_DATA (me_arg)->ts.u.derived
- != resolve_bindings_derived)
+ /* The derived type is not a PDT template. Resolve as usual. */
+ if (!resolve_bindings_derived->attr.pdt_template
+ && (CLASS_DATA (me_arg)->ts.u.derived != resolve_bindings_derived))
{
- gfc_error ("Argument %qs of %qs with PASS(%s) at %L must be of"
- " the derived-type %qs", me_arg->name, proc->name,
+ gfc_error ("Argument %qs of %qs with PASS(%s) at %L must be of "
+ "the derived-type %qs", me_arg->name, proc->name,
me_arg->name, &where, resolve_bindings_derived->name);
goto error;
}
+ if (resolve_bindings_derived->attr.pdt_template
+ && !gfc_pdt_is_instance_of (resolve_bindings_derived,
+ CLASS_DATA (me_arg)->ts.u.derived))
+ {
+ gfc_error ("Argument %qs of %qs with PASS(%s) at %L must be of "
+ "the parametric derived-type %qs", me_arg->name,
+ proc->name, me_arg->name, &where,
+ resolve_bindings_derived->name);
+ goto error;
+ }
+
+ if (resolve_bindings_derived->attr.pdt_template
+ && gfc_pdt_is_instance_of (resolve_bindings_derived,
+ CLASS_DATA (me_arg)->ts.u.derived)
+ && (me_arg->param_list != NULL)
+ && (gfc_spec_list_type (me_arg->param_list,
+ CLASS_DATA(me_arg)->ts.u.derived)
+ != SPEC_ASSUMED))
+ {
+
+ /* Add a check to verify if there are any LEN parameters in the
+ first place. If there are LEN parameters, throw this error.
+ If there are only KIND parameters, then don't trigger
+ this error. */
+ gfc_component *c;
+ bool seen_len_param = false;
+ gfc_actual_arglist *me_arg_param = me_arg->param_list;
+
+ for (; me_arg_param; me_arg_param = me_arg_param->next)
+ {
+ c = gfc_find_component (CLASS_DATA(me_arg)->ts.u.derived,
+ me_arg_param->name, true, true, NULL);
+
+ gcc_assert (c != NULL);
+
+ if (c->attr.pdt_kind)
+ continue;
+
+ /* Getting here implies that there is a pdt_len parameter
+ in the list. */
+ seen_len_param = true;
+ break;
+ }
+
+ if (seen_len_param)
+ {
+ gfc_error ("All LEN type parameters of the passed dummy "
+ "argument %qs of %qs at %L must be ASSUMED.",
+ me_arg->name, proc->name, &where);
+ goto error;
+ }
+ }
+
gcc_assert (me_arg->ts.type == BT_CLASS);
if (CLASS_DATA (me_arg)->as && CLASS_DATA (me_arg)->as->rank != 0)
{
else if (param->spec_type == SPEC_ASSUMED)
assumed_len_exprs = true;
- if (param->spec_type == SPEC_DEFERRED
- && !attr->allocatable && !attr->pointer)
- gfc_error ("The object %qs at %L has a deferred LEN "
- "parameter %qs and is neither allocatable "
- "nor a pointer", sym->name, &sym->declared_at,
+ if (param->spec_type == SPEC_DEFERRED && !attr->allocatable
+ && ((sym->ts.type == BT_DERIVED && !attr->pointer)
+ || (sym->ts.type == BT_CLASS && !attr->class_pointer)))
+ gfc_error ("Entity %qs at %L has a deferred LEN "
+ "parameter %qs and requires either the POINTER "
+ "or ALLOCATABLE attribute",
+ sym->name, &sym->declared_at,
param->name);
}
return gfc_compare_derived_types (t1, t2);
}
+/* Check if parameterized derived type t2 is an instance of pdt template t1
+
+ gfc_symbol *t1 -> pdt template to verify t2 against.
+ gfc_symbol *t2 -> pdt instance to be verified.
+
+ In decl.cc, gfc_get_pdt_instance, a pdt instance is given a 3 character
+ prefix "Pdt", followed by an underscore list of the kind parameters,
+ up to a maximum of 8 kind parameters. To verify if a PDT Type corresponds
+ to the template, this functions extracts t2's derive_type name,
+ and compares it to the derive_type name of t1 for compatibility.
+
+ For example:
+
+ t2->name = Pdtf_2_2; extract out the 'f' and compare with t1->name. */
+
+bool
+gfc_pdt_is_instance_of (gfc_symbol *t1, gfc_symbol *t2)
+{
+ if ( !t1->attr.pdt_template || !t2->attr.pdt_type )
+ return false;
+
+ /* Limit comparison to length of t1->name to ignore new kind params. */
+ if ( !(strncmp (&(t2->name[3]), t1->name, strlen (t1->name)) == 0) )
+ return false;
+
+ return true;
+}
/* Check if two typespecs are type compatible (F03:5.1.1.2):
If ts1 is nonpolymorphic, ts2 must be the same type.
--- /dev/null
+! { dg-do compile }
+!
+! Tests the fixes for PR82943.
+!
+! Contributed by Alexander Westbrooks <ctechnodev@gmail.com>
+!
+module m
+ public :: foo, bar, foobar
+
+ type, public :: good_type(n)
+ integer, len :: n = 1
+ contains
+ procedure :: foo
+ end type
+
+ type, public :: good_type2(k)
+ integer, kind :: k = 1
+ contains
+ procedure :: bar
+ end type
+
+ type, public :: good_type3(n, k)
+ integer, len :: n = 1
+ integer, kind :: k = 1
+ contains
+ procedure :: foobar
+ end type
+
+ contains
+ subroutine foo(this)
+ class(good_type(*)), intent(inout) :: this
+ end subroutine
+
+ subroutine bar(this)
+ class(good_type2(2)), intent(inout) :: this
+ end subroutine
+
+ subroutine foobar(this)
+ class(good_type3(*,2)), intent(inout) :: this
+ end subroutine
+
+ end module
\ No newline at end of file
--- /dev/null
+! { dg-do compile }
+!
+! Tests the fixes for PR82943.
+!
+! This test focuses on inheritance for the type bound procedures.
+!
+! Contributed by Alexander Westbrooks <ctechnodev@gmail.com>
+!
+module m
+
+ public :: foo, bar, foobar
+
+ type, public :: goodpdt_lvl_0(a, b)
+ integer, kind :: a = 1
+ integer, len :: b
+ contains
+ procedure :: foo
+ end type
+
+ type, public, EXTENDS(goodpdt_lvl_0) :: goodpdt_lvl_1 (c)
+ integer, len :: c
+ contains
+ procedure :: bar
+ end type
+
+ type, public, EXTENDS(goodpdt_lvl_1) :: goodpdt_lvl_2 (d)
+ integer, len :: d
+ contains
+ procedure :: foobar
+ end type
+
+contains
+ subroutine foo(this)
+ class(goodpdt_lvl_0(1,*)), intent(inout) :: this
+ end subroutine
+
+ subroutine bar(this)
+ class(goodpdt_lvl_1(1,*,*)), intent(inout) :: this
+ end subroutine
+
+ subroutine foobar(this)
+ class(goodpdt_lvl_2(1,*,*,*)), intent(inout) :: this
+ end subroutine
+
+end module
\ No newline at end of file
--- /dev/null
+! { dg-do run }
+!
+! Tests the fixes for PR82943.
+!
+! This test focuses on calling the type bound procedures in a program.
+!
+! Contributed by Alexander Westbrooks <ctechnodev@gmail.com>
+!
+module testmod
+
+ public :: foo
+
+ type, public :: tough_lvl_0(a, b)
+ integer, kind :: a = 1
+ integer, len :: b
+ contains
+ procedure :: foo
+ end type
+
+ type, public, EXTENDS(tough_lvl_0) :: tough_lvl_1 (c)
+ integer, len :: c
+ contains
+ procedure :: bar
+ end type
+
+ type, public, EXTENDS(tough_lvl_1) :: tough_lvl_2 (d)
+ integer, len :: d
+ contains
+ procedure :: foobar
+ end type
+
+contains
+ subroutine foo(this)
+ class(tough_lvl_0(1,*)), intent(inout) :: this
+ end subroutine
+
+ subroutine bar(this)
+ class(tough_lvl_1(1,*,*)), intent(inout) :: this
+ end subroutine
+
+ subroutine foobar(this)
+ class(tough_lvl_2(1,*,*,*)), intent(inout) :: this
+ end subroutine
+
+end module
+
+PROGRAM testprogram
+ USE testmod
+
+ TYPE(tough_lvl_0(1,5)) :: test_pdt_0
+ TYPE(tough_lvl_1(1,5,6)) :: test_pdt_1
+ TYPE(tough_lvl_2(1,5,6,7)) :: test_pdt_2
+
+ CALL test_pdt_0%foo()
+
+ CALL test_pdt_1%foo()
+ CALL test_pdt_1%bar()
+
+ CALL test_pdt_2%foo()
+ CALL test_pdt_2%bar()
+ CALL test_pdt_2%foobar()
+
+
+END PROGRAM testprogram
+
\ No newline at end of file
--- /dev/null
+! { dg-do compile }
+!
+! Tests the fixes for PR82943.
+!
+! This test focuses on the errors produced by incorrect LEN parameters for dummy
+! arguments of PDT Typebound Procedures.
+!
+! Contributed by Alexander Westbrooks <ctechnodev@gmail.com>
+!
+module test_len_param
+ implicit none
+ type :: param_deriv_type(a)
+ integer, len :: a
+ contains
+ procedure :: assumed_len_param ! Good. No error expected.
+ procedure :: assumed_len_param_ptr ! { dg-error "must not be POINTER" }
+ procedure :: assumed_len_param_alloc ! { dg-error "must not be ALLOCATABLE" }
+ procedure :: deferred_len_param ! { dg-error "must be ASSUMED" }
+ procedure :: deferred_len_param_ptr ! { dg-error "must be ASSUMED" }
+ procedure :: deferred_len_param_alloc ! { dg-error "must be ASSUMED" }
+ procedure :: fixed_len_param ! { dg-error "must be ASSUMED" }
+ procedure :: fixed_len_param_ptr ! { dg-error "must be ASSUMED" }
+ procedure :: fixed_len_param_alloc ! { dg-error "must be ASSUMED" }
+
+ end type
+
+contains
+ subroutine assumed_len_param(this)
+ class(param_deriv_type(*)), intent(inout) :: this ! Good. No error expected.
+ ! TYPE(param_deriv_type(*)), intent(inout) :: that ! Good. No error expected.
+ end subroutine
+
+ subroutine assumed_len_param_ptr(this, that)
+ class(param_deriv_type(*)), intent(inout), pointer :: this ! Good. No error expected.
+ TYPE(param_deriv_type(*)), intent(inout), allocatable :: that ! Good. No error expected.
+ end subroutine
+
+ subroutine assumed_len_param_alloc(this, that)
+ class(param_deriv_type(*)), intent(inout), allocatable :: this ! Good. No error expected.
+ TYPE(param_deriv_type(*)), intent(inout), allocatable :: that ! Good. No error expected.
+ end subroutine
+
+ subroutine deferred_len_param(this, that) ! { dg-error "requires either the POINTER or ALLOCATABLE attribute" }
+ class(param_deriv_type(:)), intent(inout) :: this
+ TYPE(param_deriv_type(:)), intent(inout) :: that ! Good. No error expected.
+ end subroutine
+
+ subroutine deferred_len_param_ptr(this, that)
+ class(param_deriv_type(:)), intent(inout), pointer :: this ! Good. No error expected.
+ TYPE(param_deriv_type(:)), intent(inout), pointer :: that ! Good. No error expected.
+ end subroutine
+
+ subroutine deferred_len_param_alloc(this, that)
+ class(param_deriv_type(:)), intent(inout), allocatable :: this ! Good. No error expected.
+ TYPE(param_deriv_type(:)), intent(inout), allocatable :: that ! Good. No error expected.
+ end subroutine
+
+ subroutine fixed_len_param(this, that)
+ class(param_deriv_type(10)), intent(inout) :: this ! Good. No error expected.
+ TYPE(param_deriv_type(10)), intent(inout) :: that ! Good. No error expected.
+ end subroutine
+
+ subroutine fixed_len_param_ptr(this, that)
+ class(param_deriv_type(10)), intent(inout), pointer :: this ! Good. No error expected.
+ TYPE(param_deriv_type(10)), intent(inout), pointer :: that ! Good. No error expected.
+ end subroutine
+
+ subroutine fixed_len_param_alloc(this, that)
+ class(param_deriv_type(10)), intent(inout), allocatable :: this ! Good. No error expected.
+ TYPE(param_deriv_type(10)), intent(inout), allocatable :: that ! Good. No error expected.
+ end subroutine
+
+end module
+
subroutine foo(arg)
type (mytype(4, *)) :: arg ! OK
end subroutine
- subroutine bar(arg) ! { dg-error "is neither allocatable nor a pointer" }
+ subroutine bar(arg) ! { dg-error "requires either the POINTER or ALLOCATABLE attribute" }
type (thytype(8, :, 4)) :: arg
end subroutine
subroutine foobar(arg) ! OK