* [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array @ 2015-02-26 17:19 Andre Vehreschild 2015-03-23 12:29 ` Mikael Morin 0 siblings, 1 reply; 18+ messages in thread From: Andre Vehreschild @ 2015-02-26 17:19 UTC (permalink / raw) To: GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis [-- Attachment #1: Type: text/plain, Size: 680 bytes --] Hi all, please find attached the first part of a two parts patch fixing pr/60322. This first patch is only preparatory and does not change any of the semantics of gfortran at all. It only modifies the compiler code to have the symbol_attribute and the gfc_array_spec in a separate variable in the some routines. The second part of the patch will then initialize these variables with either the (sym.attr and sym.as) or (CLASS_DATA(sym).attr and CLASS_DATA(sym).as), respectively, depending on whether the current symbol is a regular array or a class array. Bootstraps and regtests ok on x86_64-linux-gnu/F20. Regards, Andre -- Andre Vehreschild * Email: vehre ad gmx dot de [-- Attachment #2: pr60322_base_1.clog --] [-- Type: application/octet-stream, Size: 413 bytes --] gcc/fortran/ChangeLog: 2015-02-26 Andre Vehreschild <vehre@gmx.de> * expr.c (gfc_lval_expr_from_sym): Added array_attr- and as- pointer to address the class arrays and regular arrays. * trans-array.c (gfc_trans_dummy_array_bias): Same. * trans-decl.c (gfc_build_qualified_array): Same. (gfc_build_dummy_array_decl): Same. (gfc_trans_deferred_vars): Same. * trans-types.c (gfc_is_nodesc_array): Same. [-- Attachment #3: pr60322_base_1.patch --] [-- Type: text/x-patch, Size: 11832 bytes --] diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c index ab6f7a5..d28cf77 100644 --- a/gcc/fortran/expr.c +++ b/gcc/fortran/expr.c @@ -4052,6 +4052,7 @@ gfc_expr * gfc_lval_expr_from_sym (gfc_symbol *sym) { gfc_expr *lval; + gfc_array_spec *as; lval = gfc_get_expr (); lval->expr_type = EXPR_VARIABLE; lval->where = sym->declared_at; @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name); /* It will always be a full array. */ - lval->rank = sym->as ? sym->as->rank : 0; + as = sym->as; + lval->rank = as ? as->rank : 0; if (lval->rank) - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? - CLASS_DATA (sym)->as : sym->as); + gfc_add_full_array_ref (lval, as); return lval; } diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 642110d..0d4d7b2 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -5898,6 +5898,7 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, int checkparm; int no_repack; bool optional_arg; + gfc_array_spec *as; /* Do nothing for pointer and allocatable arrays. */ if (sym->attr.pointer || sym->attr.allocatable) @@ -5917,13 +5918,14 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, gcc_assert (GFC_ARRAY_TYPE_P (type)); dumdesc = GFC_DECL_SAVED_DESCRIPTOR (tmpdesc); dumdesc = build_fold_indirect_ref_loc (input_location, dumdesc); + as = sym->as; gfc_start_block (&init); if (sym->ts.type == BT_CHARACTER && TREE_CODE (sym->ts.u.cl->backend_decl) == VAR_DECL) gfc_conv_string_length (sym->ts.u.cl, NULL, &init); - checkparm = (sym->as->type == AS_EXPLICIT + checkparm = (as->type == AS_EXPLICIT && (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)); no_repack = !(GFC_DECL_PACKED_ARRAY (tmpdesc) @@ -5999,9 +6001,9 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, size = gfc_index_one_node; /* Evaluate the bounds of the array. */ - for (n = 0; n < sym->as->rank; n++) + for (n = 0; n < as->rank; n++) { - if (checkparm || !sym->as->upper[n]) + if (checkparm || !as->upper[n]) { /* Get the bounds of the actual parameter. */ dubound = gfc_conv_descriptor_ubound_get (dumdesc, gfc_rank_cst[n]); @@ -6017,7 +6019,7 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, if (!INTEGER_CST_P (lbound)) { gfc_init_se (&se, NULL); - gfc_conv_expr_type (&se, sym->as->lower[n], + gfc_conv_expr_type (&se, as->lower[n], gfc_array_index_type); gfc_add_block_to_block (&init, &se.pre); gfc_add_modify (&init, lbound, se.expr); @@ -6025,13 +6027,13 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, ubound = GFC_TYPE_ARRAY_UBOUND (type, n); /* Set the desired upper bound. */ - if (sym->as->upper[n]) + if (as->upper[n]) { /* We know what we want the upper bound to be. */ if (!INTEGER_CST_P (ubound)) { gfc_init_se (&se, NULL); - gfc_conv_expr_type (&se, sym->as->upper[n], + gfc_conv_expr_type (&se, as->upper[n], gfc_array_index_type); gfc_add_block_to_block (&init, &se.pre); gfc_add_modify (&init, ubound, se.expr); @@ -6084,7 +6086,7 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, gfc_array_index_type, offset, tmp); /* The size of this dimension, and the stride of the next. */ - if (n + 1 < sym->as->rank) + if (n + 1 < as->rank) { stride = GFC_TYPE_ARRAY_STRIDE (type, n + 1); diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c index 3664824..e571a17 100644 --- a/gcc/fortran/trans-decl.c +++ b/gcc/fortran/trans-decl.c @@ -811,8 +811,12 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) int dim; int nest; gfc_namespace* procns; + symbol_attribute *array_attr; + gfc_array_spec *as; type = TREE_TYPE (decl); + array_attr = &sym->attr; + as = sym->as; /* We just use the descriptor, if there is one. */ if (GFC_DESCRIPTOR_TYPE_P (type)) @@ -823,8 +827,8 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) nest = (procns->proc_name->backend_decl != current_function_decl) && !sym->attr.contained; - if (sym->attr.codimension && flag_coarray == GFC_FCOARRAY_LIB - && sym->as->type != AS_ASSUMED_SHAPE + if (array_attr->codimension && flag_coarray == GFC_FCOARRAY_LIB + && as->type != AS_ASSUMED_SHAPE && GFC_TYPE_ARRAY_CAF_TOKEN (type) == NULL_TREE) { tree token; @@ -877,8 +881,8 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) } /* Don't try to use the unknown bound for assumed shape arrays. */ if (GFC_TYPE_ARRAY_UBOUND (type, dim) == NULL_TREE - && (sym->as->type != AS_ASSUMED_SIZE - || dim < GFC_TYPE_ARRAY_RANK (type) - 1)) + && (as->type != AS_ASSUMED_SIZE + || dim < GFC_TYPE_ARRAY_RANK (type) - 1)) { GFC_TYPE_ARRAY_UBOUND (type, dim) = create_index_var ("ubound", nest); TREE_NO_WARNING (GFC_TYPE_ARRAY_UBOUND (type, dim)) = 1; @@ -919,7 +923,7 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) } if (GFC_TYPE_ARRAY_SIZE (type) == NULL_TREE - && sym->as->type != AS_ASSUMED_SIZE) + && as->type != AS_ASSUMED_SIZE) { GFC_TYPE_ARRAY_SIZE (type) = create_index_var ("size", nest); TREE_NO_WARNING (GFC_TYPE_ARRAY_SIZE (type)) = 1; @@ -946,12 +950,12 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) } if (TYPE_NAME (type) != NULL_TREE - && GFC_TYPE_ARRAY_UBOUND (type, sym->as->rank - 1) != NULL_TREE - && TREE_CODE (GFC_TYPE_ARRAY_UBOUND (type, sym->as->rank - 1)) == VAR_DECL) + && GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1) != NULL_TREE + && TREE_CODE (GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1)) == VAR_DECL) { tree gtype = DECL_ORIGINAL_TYPE (TYPE_NAME (type)); - for (dim = 0; dim < sym->as->rank - 1; dim++) + for (dim = 0; dim < as->rank - 1; dim++) { gcc_assert (TREE_CODE (gtype) == ARRAY_TYPE); gtype = TREE_TYPE (gtype); @@ -965,7 +969,7 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) { tree gtype = TREE_TYPE (type), rtype, type_decl; - for (dim = sym->as->rank - 1; dim >= 0; dim--) + for (dim = as->rank - 1; dim >= 0; dim--) { tree lbound, ubound; lbound = GFC_TYPE_ARRAY_LBOUND (type, dim); @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) tree decl; tree type; gfc_array_spec *as; + symbol_attribute *array_attr; char *name; gfc_packed packed; int n; bool known_size; - if (sym->attr.pointer || sym->attr.allocatable - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) + /* Use the array as and attr. */ + as = sym->as; + array_attr = &sym->attr; + + /* The pointer attribute is always set on a _data component, therefore check + the sym's attribute only. */ + if (sym->attr.pointer || array_attr->allocatable + || (as && as->type == AS_ASSUMED_RANK)) return dummy; - /* Add to list of variables if not a fake result variable. */ + /* Add to list of variables if not a fake result variable. + These symbols are set on the symbol only, not on the class component. */ if (sym->attr.result || sym->attr.dummy) gfc_defer_symbol_init (sym); @@ -1047,7 +1059,6 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) if (GFC_DESCRIPTOR_TYPE_P (type)) { /* Create a descriptorless array pointer. */ - as = sym->as; packed = PACKED_NO; /* Even when -frepack-arrays is used, symbols with TARGET attribute @@ -1079,7 +1090,7 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) } type = gfc_typenode_for_spec (&sym->ts); - type = gfc_get_nodesc_array_type (type, sym->as, packed, + type = gfc_get_nodesc_array_type (type, as, packed, !sym->attr.target); } else @@ -1109,7 +1120,7 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) /* We should never get deferred shape arrays here. We used to because of frontend bugs. */ - gcc_assert (sym->as->type != AS_DEFERRED); + gcc_assert (as->type != AS_DEFERRED); if (packed == PACKED_PARTIAL) GFC_DECL_PARTIAL_PACKED_ARRAY (decl) = 1; @@ -3973,16 +3984,25 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) } else if (sym->attr.dimension || sym->attr.codimension) { - /* Assumed-size Cray pointees need to be treated as AS_EXPLICIT. */ - array_type tmp = sym->as->type; - if (tmp == AS_ASSUMED_SIZE && sym->as->cp_was_assumed) - tmp = AS_EXPLICIT; - switch (tmp) + symbol_attribute *array_attr; + gfc_array_spec *as; + array_type tmp; + + array_attr = &sym->attr; + as = sym->as; + /* Assumed-size Cray pointees need to be treated as AS_EXPLICIT. */ + tmp = as->type; + if (tmp == AS_ASSUMED_SIZE && as->cp_was_assumed) + tmp = AS_EXPLICIT; + switch (tmp) { case AS_EXPLICIT: if (sym->attr.dummy || sym->attr.result) gfc_trans_dummy_array_bias (sym, sym->backend_decl, block); - else if (sym->attr.pointer || sym->attr.allocatable) + /* In a class array the _data component always has the pointer + attribute set. Therefore only check for allocatable in the + array attributes and for pointer in the symbol. */ + else if (sym->attr.pointer || array_attr->allocatable) { if (TREE_STATIC (sym->backend_decl)) { @@ -3997,7 +4017,8 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) gfc_trans_deferred_array (sym, block); } } - else if (sym->attr.codimension && TREE_STATIC (sym->backend_decl)) + else if (sym->attr.codimension + && TREE_STATIC (sym->backend_decl)) { gfc_init_block (&tmpblock); gfc_trans_array_cobounds (TREE_TYPE (sym->backend_decl), @@ -4036,7 +4057,7 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) case AS_ASSUMED_SIZE: /* Must be a dummy parameter. */ - gcc_assert (sym->attr.dummy || sym->as->cp_was_assumed); + gcc_assert (sym->attr.dummy || as->cp_was_assumed); /* We should always pass assumed size arrays the g77 way. */ if (sym->attr.dummy) diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c index 53da053..bce4d24 100644 --- a/gcc/fortran/trans-types.c +++ b/gcc/fortran/trans-types.c @@ -1288,25 +1288,32 @@ gfc_get_element_type (tree type) int gfc_is_nodesc_array (gfc_symbol * sym) { - gcc_assert (sym->attr.dimension || sym->attr.codimension); + symbol_attribute *array_attr; + gfc_array_spec *as; + + array_attr = &sym->attr; + as = sym->as; + + gcc_assert (array_attr->dimension || array_attr->codimension); /* We only want local arrays. */ - if (sym->attr.pointer || sym->attr.allocatable) + if (sym->attr.pointer || array_attr->allocatable) return 0; /* We want a descriptor for associate-name arrays that do not have an - explicitly known shape already. */ - if (sym->assoc && sym->as->type != AS_EXPLICIT) + explicitly known shape already. */ + if (sym->assoc && as->type != AS_EXPLICIT) return 0; + /* The dummy is stored in sym and not in the component. */ if (sym->attr.dummy) - return sym->as->type != AS_ASSUMED_SHAPE - && sym->as->type != AS_ASSUMED_RANK; + return as->type != AS_ASSUMED_SHAPE + && as->type != AS_ASSUMED_RANK; if (sym->attr.result || sym->attr.function) return 0; - gcc_assert (sym->as->type == AS_EXPLICIT || sym->as->cp_was_assumed); + gcc_assert (as->type == AS_EXPLICIT || as->cp_was_assumed); return 1; } ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-02-26 17:19 [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array Andre Vehreschild @ 2015-03-23 12:29 ` Mikael Morin 2015-03-23 12:44 ` Andre Vehreschild 0 siblings, 1 reply; 18+ messages in thread From: Mikael Morin @ 2015-03-23 12:29 UTC (permalink / raw) To: Andre Vehreschild, GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis 26/02/2015 18:17, Andre Vehreschild a écrit : > This first patch is only preparatory and does not change any of the semantics of > gfortran at all. Sure? > diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c > index ab6f7a5..d28cf77 100644 > --- a/gcc/fortran/expr.c > +++ b/gcc/fortran/expr.c > @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) > lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name); > > /* It will always be a full array. */ > - lval->rank = sym->as ? sym->as->rank : 0; > + as = sym->as; > + lval->rank = as ? as->rank : 0; > if (lval->rank) > - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? > - CLASS_DATA (sym)->as : sym->as); > + gfc_add_full_array_ref (lval, as); This is a change of semantics. Or do you know that sym->ts.type != BT_CLASS? > diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c > index 3664824..e571a17 100644 > --- a/gcc/fortran/trans-decl.c > +++ b/gcc/fortran/trans-decl.c > @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) > tree decl; > tree type; > gfc_array_spec *as; > + symbol_attribute *array_attr; > char *name; > gfc_packed packed; > int n; > bool known_size; > > - if (sym->attr.pointer || sym->attr.allocatable > - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) > + /* Use the array as and attr. */ > + as = sym->as; > + array_attr = &sym->attr; > + > + /* The pointer attribute is always set on a _data component, therefore check > + the sym's attribute only. */ > + if (sym->attr.pointer || array_attr->allocatable > + || (as && as->type == AS_ASSUMED_RANK)) > return dummy; > Any reason to sometimes use array_attr, sometimes not, like here? By the way, the comment is misleading: for classes, there is the class_pointer attribute (and it is a pain, I know). Mikael ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-03-23 12:29 ` Mikael Morin @ 2015-03-23 12:44 ` Andre Vehreschild 2015-03-23 14:58 ` Mikael Morin 2015-03-24 10:13 ` Paul Richard Thomas 0 siblings, 2 replies; 18+ messages in thread From: Andre Vehreschild @ 2015-03-23 12:44 UTC (permalink / raw) To: Mikael Morin; +Cc: GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis [-- Attachment #1: Type: text/plain, Size: 3148 bytes --] Hi Mikael, thanks for looking at the patch. Please note, that Paul has sent an addendum to the patches for 60322, which I deliberately have attached. > 26/02/2015 18:17, Andre Vehreschild a écrit : > > This first patch is only preparatory and does not change any of the > > semantics of gfortran at all. > Sure? With the counterexample you found below, this of course is a wrong statement. > > diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c > > index ab6f7a5..d28cf77 100644 > > --- a/gcc/fortran/expr.c > > +++ b/gcc/fortran/expr.c > > @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) > > lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name); > > > > /* It will always be a full array. */ > > - lval->rank = sym->as ? sym->as->rank : 0; > > + as = sym->as; > > + lval->rank = as ? as->rank : 0; > > if (lval->rank) > > - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? > > - CLASS_DATA (sym)->as : sym->as); > > + gfc_add_full_array_ref (lval, as); > > This is a change of semantics. Or do you know that sym->ts.type != > BT_CLASS? You are completely right. I have made a mistake here. I have to tell the truth, I never ran a regtest with only part 1 of the patches applied. The second part of the patch will correct this, by setting the variable as depending on whether type == BT_CLASS or not. Sorry for the mistake. > > diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c > > index 3664824..e571a17 100644 > > --- a/gcc/fortran/trans-decl.c > > +++ b/gcc/fortran/trans-decl.c > > @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree > > dummy) tree decl; > > tree type; > > gfc_array_spec *as; > > + symbol_attribute *array_attr; > > char *name; > > gfc_packed packed; > > int n; > > bool known_size; > > > > - if (sym->attr.pointer || sym->attr.allocatable > > - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) > > + /* Use the array as and attr. */ > > + as = sym->as; > > + array_attr = &sym->attr; > > + > > + /* The pointer attribute is always set on a _data component, therefore > > check > > + the sym's attribute only. */ > > + if (sym->attr.pointer || array_attr->allocatable > > + || (as && as->type == AS_ASSUMED_RANK)) > > return dummy; > > > Any reason to sometimes use array_attr, sometimes not, like here? > By the way, the comment is misleading: for classes, there is the > class_pointer attribute (and it is a pain, I know). Yes, and a good one. Array_attr is sometimes sym->attr and sometimes CLASS_DATA(sym)->attr aka sym->ts.u.derived->components->attr. In the later case .pointer is always set to 1 in the _data component's attr. I.e., the above if, would always yield true for a class_array, which is not intended, but rather destructive. I know about the class_pointer attribute, but I figured, that it is not relevant here. Any idea how to formulate the comment better, to reflect what I just explained? Regards, Andre -- Andre Vehreschild * Email: vehre ad gmx dot de [-- Attachment #2: Type: message/rfc822, Size: 6575 bytes --] [-- Attachment #2.1.1: Type: text/plain, Size: 1632 bytes --] Dear Andre and Dominique, I have found that LOC is returning the address of the class container rather than the _data component for class scalars. See the source below, which you will recognise! A fix is attached. Note that the scalar allocate fails with MOLD= and so I substituted SOURCE=. Cheers Paul class(*), allocatable :: a(:), e ! Change 'e' to an array and second memcpy works correctly ! Problem is with loc(e), which returns the address of the ! class container. allocate (e, source = 99.0) allocate (a(2), source = [1.0, 2.0]) call add_element_poly (a,e) select type (a) type is (real) print *, a end select contains subroutine add_element_poly(a,e) use iso_c_binding class(*),allocatable,intent(inout),target :: a(:) class(*),intent(in),target :: e class(*),allocatable,target :: tmp(:) type(c_ptr) :: dummy interface function memcpy(dest,src,n) bind(C,name="memcpy") result(res) import type(c_ptr) :: res integer(c_intptr_t),value :: dest integer(c_intptr_t),value :: src integer(c_size_t),value :: n end function end interface if (.not.allocated(a)) then allocate(a(1), source=e) else allocate(tmp(size(a)),source=a) deallocate(a) allocate(a(size(tmp)+1),source=e) ! mold gives a segfault dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) end if end subroutine end [-- Attachment #2.1.2: loc_patch.diff --] [-- Type: text/plain, Size: 1043 bytes --] Index: gcc/fortran/trans-intrinsic.c =================================================================== *** gcc/fortran/trans-intrinsic.c (revision 221500) --- gcc/fortran/trans-intrinsic.c (working copy) *************** gfc_conv_intrinsic_loc (gfc_se * se, gfc *** 7080,7086 **** arg_expr = expr->value.function.actual->expr; if (arg_expr->rank == 0) ! gfc_conv_expr_reference (se, arg_expr); else gfc_conv_array_parameter (se, arg_expr, true, NULL, NULL, NULL); se->expr = convert (gfc_get_int_type (gfc_index_integer_kind), se->expr); --- 7080,7091 ---- arg_expr = expr->value.function.actual->expr; if (arg_expr->rank == 0) ! { ! if (arg_expr->symtree->n.sym->ts.type == BT_CLASS ! && !CLASS_DATA (arg_expr->symtree->n.sym)->as) ! gfc_add_component_ref (arg_expr, "_data"); ! gfc_conv_expr_reference (se, arg_expr); ! } else gfc_conv_array_parameter (se, arg_expr, true, NULL, NULL, NULL); se->expr = convert (gfc_get_int_type (gfc_index_integer_kind), se->expr); ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-03-23 12:44 ` Andre Vehreschild @ 2015-03-23 14:58 ` Mikael Morin 2015-03-23 15:49 ` Andre Vehreschild 2015-03-24 10:13 ` Paul Richard Thomas 1 sibling, 1 reply; 18+ messages in thread From: Mikael Morin @ 2015-03-23 14:58 UTC (permalink / raw) To: Andre Vehreschild; +Cc: GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis Le 23/03/2015 13:43, Andre Vehreschild a écrit : > Hi Mikael, > > thanks for looking at the patch. Please note, that Paul has sent an addendum to > the patches for 60322, which I deliberately have attached. > >> 26/02/2015 18:17, Andre Vehreschild a écrit : >>> This first patch is only preparatory and does not change any of the >>> semantics of gfortran at all. >> Sure? > > With the counterexample you found below, this of course is a wrong statement. > >>> diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c >>> index ab6f7a5..d28cf77 100644 >>> --- a/gcc/fortran/expr.c >>> +++ b/gcc/fortran/expr.c >>> @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) >>> lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name); >>> >>> /* It will always be a full array. */ >>> - lval->rank = sym->as ? sym->as->rank : 0; >>> + as = sym->as; >>> + lval->rank = as ? as->rank : 0; >>> if (lval->rank) >>> - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? >>> - CLASS_DATA (sym)->as : sym->as); >>> + gfc_add_full_array_ref (lval, as); >> >> This is a change of semantics. Or do you know that sym->ts.type != >> BT_CLASS? > > You are completely right. I have made a mistake here. I have to tell the truth, > I never ran a regtest with only part 1 of the patches applied. The second part > of the patch will correct this, by setting the variable as depending on whether > type == BT_CLASS or not. Sorry for the mistake. > >>> diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c >>> index 3664824..e571a17 100644 >>> --- a/gcc/fortran/trans-decl.c >>> +++ b/gcc/fortran/trans-decl.c >>> @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree >>> dummy) tree decl; >>> tree type; >>> gfc_array_spec *as; >>> + symbol_attribute *array_attr; >>> char *name; >>> gfc_packed packed; >>> int n; >>> bool known_size; >>> >>> - if (sym->attr.pointer || sym->attr.allocatable >>> - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) >>> + /* Use the array as and attr. */ >>> + as = sym->as; >>> + array_attr = &sym->attr; >>> + >>> + /* The pointer attribute is always set on a _data component, therefore >>> check >>> + the sym's attribute only. */ >>> + if (sym->attr.pointer || array_attr->allocatable >>> + || (as && as->type == AS_ASSUMED_RANK)) >>> return dummy; >>> >> Any reason to sometimes use array_attr, sometimes not, like here? >> By the way, the comment is misleading: for classes, there is the >> class_pointer attribute (and it is a pain, I know). > > Yes, and a good one. Array_attr is sometimes sym->attr and sometimes > CLASS_DATA(sym)->attr aka sym->ts.u.derived->components->attr. In the later > case .pointer is always set to 1 in the _data component's attr. I.e., the above > if, would always yield true for a class_array, which is not intended, but rather > destructive. I know about the class_pointer attribute, but I figured, that it > is not relevant here. Any idea how to formulate the comment better, to reflect > what I just explained? > This pointer stuff is very difficult to swallow to me. I understand that for classes, the CLASS_DATA (sym)->pointer is always set, but almost everywhere the checks for pointerness are like (sym->ts.type != BT_CLASS && sym->attr.pointer) || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) and I don't see a convincing reason to have it different here. At least gfc_is_nodesc_array should return 0 if sym->ts.type == BT_CLASS which solves the problem there; for the other cases, I think that class_pointer should be looked at. gfc_build_class_symbol clears the sym->attr.pointer flag for class containers so it doesn't make sense to test that flag. Mikael ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-03-23 14:58 ` Mikael Morin @ 2015-03-23 15:49 ` Andre Vehreschild 2015-03-23 19:28 ` Mikael Morin 0 siblings, 1 reply; 18+ messages in thread From: Andre Vehreschild @ 2015-03-23 15:49 UTC (permalink / raw) To: Mikael Morin; +Cc: GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis Hi Mikael, > This pointer stuff is very difficult to swallow to me. I totally understand. When doing the patch I had to restart twice, because I mixed up the development on the class arrays so completely, that I couldn't get it right again. > I understand that for classes, the CLASS_DATA (sym)->pointer is always > set, but almost everywhere the checks for pointerness are like > (sym->ts.type != BT_CLASS && sym->attr.pointer) > || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) > and I don't see a convincing reason to have it different here. I see your point. Currently I am bootstraping and regtesting some patches for commit. While this is running, my machine is nearly unusable. I will look into this as soon, as my machine allows, but probably not before tomorrow. > At least gfc_is_nodesc_array should return 0 if sym->ts.type == BT_CLASS > which solves the problem there; for the other cases, I think that > class_pointer should be looked at. gfc_build_class_symbol clears the > sym->attr.pointer flag for class containers so it doesn't make sense to > test that flag. Completely right again. But I figured, that because sym->attr.pointer is never set for BT_CLASS there is no harm to check it and furthermore no need to guard it by checking whether ts.type == BT_CLASS. Fortunately not checking for class_pointer in _data's attr, didn't throw any regressions. Thinking about it now, I also think that it is probably safer to add the check for the class_pointer attribute were attr.pointer is checked on the sym, having the expression like you pointed out: > (sym->ts.type != BT_CLASS && sym->attr.pointer) > || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) Regards, Andre -- Andre Vehreschild * Email: vehre ad gmx dot de ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-03-23 15:49 ` Andre Vehreschild @ 2015-03-23 19:28 ` Mikael Morin 0 siblings, 0 replies; 18+ messages in thread From: Mikael Morin @ 2015-03-23 19:28 UTC (permalink / raw) To: Andre Vehreschild; +Cc: GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis Le 23/03/2015 16:49, Andre Vehreschild a écrit : > I see your point. Currently I am bootstraping and regtesting some patches for > commit. While this is running, my machine is nearly unusable. I will look into > this as soon, as my machine allows, but probably not before tomorrow. > There is no hurry, the patch(es) will probably have to wait for next stage 1. ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-03-23 12:44 ` Andre Vehreschild 2015-03-23 14:58 ` Mikael Morin @ 2015-03-24 10:13 ` Paul Richard Thomas 2015-03-24 17:06 ` [Patch, Fortran, pr60322] was: " Andre Vehreschild 1 sibling, 1 reply; 18+ messages in thread From: Paul Richard Thomas @ 2015-03-24 10:13 UTC (permalink / raw) To: Andre Vehreschild Cc: Mikael Morin, GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis Dear Andre, Dominique pointed out to me that the 'loc' patch causes a ICE in the testsuite. It seems that 'loc' should provide the address of the class container in some places and the address of the data in others. I will put my thinking cap on tonight :-) Cheers Paul On 23 March 2015 at 13:43, Andre Vehreschild <vehre@gmx.de> wrote: > Hi Mikael, > > thanks for looking at the patch. Please note, that Paul has sent an addendum to > the patches for 60322, which I deliberately have attached. > >> 26/02/2015 18:17, Andre Vehreschild a écrit : >> > This first patch is only preparatory and does not change any of the >> > semantics of gfortran at all. >> Sure? > > With the counterexample you found below, this of course is a wrong statement. > >> > diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c >> > index ab6f7a5..d28cf77 100644 >> > --- a/gcc/fortran/expr.c >> > +++ b/gcc/fortran/expr.c >> > @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) >> > lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name); >> > >> > /* It will always be a full array. */ >> > - lval->rank = sym->as ? sym->as->rank : 0; >> > + as = sym->as; >> > + lval->rank = as ? as->rank : 0; >> > if (lval->rank) >> > - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? >> > - CLASS_DATA (sym)->as : sym->as); >> > + gfc_add_full_array_ref (lval, as); >> >> This is a change of semantics. Or do you know that sym->ts.type != >> BT_CLASS? > > You are completely right. I have made a mistake here. I have to tell the truth, > I never ran a regtest with only part 1 of the patches applied. The second part > of the patch will correct this, by setting the variable as depending on whether > type == BT_CLASS or not. Sorry for the mistake. > >> > diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c >> > index 3664824..e571a17 100644 >> > --- a/gcc/fortran/trans-decl.c >> > +++ b/gcc/fortran/trans-decl.c >> > @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree >> > dummy) tree decl; >> > tree type; >> > gfc_array_spec *as; >> > + symbol_attribute *array_attr; >> > char *name; >> > gfc_packed packed; >> > int n; >> > bool known_size; >> > >> > - if (sym->attr.pointer || sym->attr.allocatable >> > - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) >> > + /* Use the array as and attr. */ >> > + as = sym->as; >> > + array_attr = &sym->attr; >> > + >> > + /* The pointer attribute is always set on a _data component, therefore >> > check >> > + the sym's attribute only. */ >> > + if (sym->attr.pointer || array_attr->allocatable >> > + || (as && as->type == AS_ASSUMED_RANK)) >> > return dummy; >> > >> Any reason to sometimes use array_attr, sometimes not, like here? >> By the way, the comment is misleading: for classes, there is the >> class_pointer attribute (and it is a pain, I know). > > Yes, and a good one. Array_attr is sometimes sym->attr and sometimes > CLASS_DATA(sym)->attr aka sym->ts.u.derived->components->attr. In the later > case .pointer is always set to 1 in the _data component's attr. I.e., the above > if, would always yield true for a class_array, which is not intended, but rather > destructive. I know about the class_pointer attribute, but I figured, that it > is not relevant here. Any idea how to formulate the comment better, to reflect > what I just explained? > > Regards, > Andre > -- > Andre Vehreschild * Email: vehre ad gmx dot de > > > ---------- Forwarded message ---------- > From: Paul Richard Thomas <paul.richard.thomas@gmail.com> > To: Andre Vehreschild <vehre@gmx.de>, Dominique Dhumieres <dominiq@lps.ens.fr> > Cc: > Date: Sun, 22 Mar 2015 21:20:20 +0100 > Subject: Bug in intrinsic LOC for scalar class objects > Dear Andre and Dominique, > > I have found that LOC is returning the address of the class container > rather than the _data component for class scalars. See the source > below, which you will recognise! A fix is attached. > > Note that the scalar allocate fails with MOLD= and so I substituted SOURCE=. > > Cheers > > Paul > > class(*), allocatable :: a(:), e ! Change 'e' to an array and > second memcpy works correctly > ! Problem is with loc(e), which > returns the address of the > ! class container. > allocate (e, source = 99.0) > allocate (a(2), source = [1.0, 2.0]) > call add_element_poly (a,e) > select type (a) > type is (real) > print *, a > end select > > contains > > subroutine add_element_poly(a,e) > use iso_c_binding > class(*),allocatable,intent(inout),target :: a(:) > class(*),intent(in),target :: e > class(*),allocatable,target :: tmp(:) > type(c_ptr) :: dummy > > interface > function memcpy(dest,src,n) bind(C,name="memcpy") result(res) > import > type(c_ptr) :: res > integer(c_intptr_t),value :: dest > integer(c_intptr_t),value :: src > integer(c_size_t),value :: n > end function > end interface > > if (.not.allocated(a)) then > allocate(a(1), source=e) > else > allocate(tmp(size(a)),source=a) > deallocate(a) > allocate(a(size(tmp)+1),source=e) ! mold gives a segfault > dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) > dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) > end if > end subroutine > end > -- Outside of a dog, a book is a man's best friend. Inside of a dog it's too dark to read. Groucho Marx ^ permalink raw reply [flat|nested] 18+ messages in thread
* [Patch, Fortran, pr60322] was: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-03-24 10:13 ` Paul Richard Thomas @ 2015-03-24 17:06 ` Andre Vehreschild 2015-03-25 9:43 ` Dominique d'Humières 2015-03-27 12:48 ` Paul Richard Thomas 0 siblings, 2 replies; 18+ messages in thread From: Andre Vehreschild @ 2015-03-24 17:06 UTC (permalink / raw) To: Paul Richard Thomas Cc: Mikael Morin, GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis, Dominique Dhumieres [-- Attachment #1: Type: text/plain, Size: 7086 bytes --] Hi all, I have worked on the comments Mikael gave me. I am now checking for class_pointer in the way he pointed out. Furthermore did I *join the two parts* of the patch into this one, because keeping both in sync was no benefit but only tedious and did not prove to be reviewed faster. Paul, Dominique: I have addressed the LOC issue that came up lately. Or rather the patch addressed it already. I feel like this is not tested very well, not the loc() call nor the sizeof() call as given in the 57305 second's download. Unfortunately, is that download not runable. I would love to see a test similar to that download, but couldn't come up with one, that satisfied me. Given that the patch's review will last some days, I still have enough time to come up with something beautiful which I will add then. Bootstraps and regtests ok on x86_64-linux-gnu/F20. Regards, Andre On Tue, 24 Mar 2015 11:13:27 +0100 Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: > Dear Andre, > > Dominique pointed out to me that the 'loc' patch causes a ICE in the > testsuite. It seems that 'loc' should provide the address of the class > container in some places and the address of the data in others. I will > put my thinking cap on tonight :-) > > Cheers > > Paul > > On 23 March 2015 at 13:43, Andre Vehreschild <vehre@gmx.de> wrote: > > Hi Mikael, > > > > thanks for looking at the patch. Please note, that Paul has sent an > > addendum to the patches for 60322, which I deliberately have attached. > > > >> 26/02/2015 18:17, Andre Vehreschild a écrit : > >> > This first patch is only preparatory and does not change any of the > >> > semantics of gfortran at all. > >> Sure? > > > > With the counterexample you found below, this of course is a wrong > > statement. > > > >> > diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c > >> > index ab6f7a5..d28cf77 100644 > >> > --- a/gcc/fortran/expr.c > >> > +++ b/gcc/fortran/expr.c > >> > @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) > >> > lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name); > >> > > >> > /* It will always be a full array. */ > >> > - lval->rank = sym->as ? sym->as->rank : 0; > >> > + as = sym->as; > >> > + lval->rank = as ? as->rank : 0; > >> > if (lval->rank) > >> > - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? > >> > - CLASS_DATA (sym)->as : sym->as); > >> > + gfc_add_full_array_ref (lval, as); > >> > >> This is a change of semantics. Or do you know that sym->ts.type != > >> BT_CLASS? > > > > You are completely right. I have made a mistake here. I have to tell the > > truth, I never ran a regtest with only part 1 of the patches applied. The > > second part of the patch will correct this, by setting the variable as > > depending on whether type == BT_CLASS or not. Sorry for the mistake. > > > >> > diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c > >> > index 3664824..e571a17 100644 > >> > --- a/gcc/fortran/trans-decl.c > >> > +++ b/gcc/fortran/trans-decl.c > >> > @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, > >> > tree dummy) tree decl; > >> > tree type; > >> > gfc_array_spec *as; > >> > + symbol_attribute *array_attr; > >> > char *name; > >> > gfc_packed packed; > >> > int n; > >> > bool known_size; > >> > > >> > - if (sym->attr.pointer || sym->attr.allocatable > >> > - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) > >> > + /* Use the array as and attr. */ > >> > + as = sym->as; > >> > + array_attr = &sym->attr; > >> > + > >> > + /* The pointer attribute is always set on a _data component, therefore > >> > check > >> > + the sym's attribute only. */ > >> > + if (sym->attr.pointer || array_attr->allocatable > >> > + || (as && as->type == AS_ASSUMED_RANK)) > >> > return dummy; > >> > > >> Any reason to sometimes use array_attr, sometimes not, like here? > >> By the way, the comment is misleading: for classes, there is the > >> class_pointer attribute (and it is a pain, I know). > > > > Yes, and a good one. Array_attr is sometimes sym->attr and sometimes > > CLASS_DATA(sym)->attr aka sym->ts.u.derived->components->attr. In the later > > case .pointer is always set to 1 in the _data component's attr. I.e., the > > above if, would always yield true for a class_array, which is not intended, > > but rather destructive. I know about the class_pointer attribute, but I > > figured, that it is not relevant here. Any idea how to formulate the > > comment better, to reflect what I just explained? > > > > Regards, > > Andre > > -- > > Andre Vehreschild * Email: vehre ad gmx dot de > > > > > > ---------- Forwarded message ---------- > > From: Paul Richard Thomas <paul.richard.thomas@gmail.com> > > To: Andre Vehreschild <vehre@gmx.de>, Dominique Dhumieres > > <dominiq@lps.ens.fr> Cc: > > Date: Sun, 22 Mar 2015 21:20:20 +0100 > > Subject: Bug in intrinsic LOC for scalar class objects > > Dear Andre and Dominique, > > > > I have found that LOC is returning the address of the class container > > rather than the _data component for class scalars. See the source > > below, which you will recognise! A fix is attached. > > > > Note that the scalar allocate fails with MOLD= and so I substituted SOURCE=. > > > > Cheers > > > > Paul > > > > class(*), allocatable :: a(:), e ! Change 'e' to an array and > > second memcpy works correctly > > ! Problem is with loc(e), which > > returns the address of the > > ! class container. > > allocate (e, source = 99.0) > > allocate (a(2), source = [1.0, 2.0]) > > call add_element_poly (a,e) > > select type (a) > > type is (real) > > print *, a > > end select > > > > contains > > > > subroutine add_element_poly(a,e) > > use iso_c_binding > > class(*),allocatable,intent(inout),target :: a(:) > > class(*),intent(in),target :: e > > class(*),allocatable,target :: tmp(:) > > type(c_ptr) :: dummy > > > > interface > > function memcpy(dest,src,n) bind(C,name="memcpy") result(res) > > import > > type(c_ptr) :: res > > integer(c_intptr_t),value :: dest > > integer(c_intptr_t),value :: src > > integer(c_size_t),value :: n > > end function > > end interface > > > > if (.not.allocated(a)) then > > allocate(a(1), source=e) > > else > > allocate(tmp(size(a)),source=a) > > deallocate(a) > > allocate(a(size(tmp)+1),source=e) ! mold gives a segfault > > dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) > > dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) > > end if > > end subroutine > > end > > > > > -- Andre Vehreschild * Email: vehre ad gmx dot de [-- Attachment #2: pr60322_4.clog --] [-- Type: application/octet-stream, Size: 2465 bytes --] gcc/fortran/ChangeLog: 2015-03-24 Andre Vehreschild <vehre@gmx.de> PR fortran/60322 * expr.c (gfc_lval_expr_from_sym): Code to select the regular or class array added. * gfortran.h: Added IS_CLASS_ARRAY macro. * trans-array.c (gfc_add_loop_ss_code): Treat class objects always to be referenced. (build_class_array_ref): Adapt retrieval of array descriptor. (build_array_ref): Likewise. (gfc_trans_array_cobounds): Select correct gfc_array_spec for regular and class arrays. (gfc_trans_array_bounds): Likewise. (gfc_trans_dummy_array_bias): Likewise. (gfc_conv_expr_descriptor): Set the array's offset to -1 when lbound in inner most dim is 1 and symbol non-pointer/assoc. * trans-decl.c (gfc_build_qualified_array): Select correct gfc_array_spec for regular and class arrays. (gfc_build_dummy_array_decl): Likewise. (gfc_get_symbol_decl): Get a dummy array for class arrays, too. (gfc_trans_deferred_vars): Tell conv_expr that the descriptor is desired. * trans-expr.c (gfc_class_vptr_get): Get the class descriptor from the correct location for class arrays. (gfc_class_len_get): Likewise. (gfc_conv_class_to_class): Prevent access to unset array data when the array is an optional argument. (gfc_trans_class_init_assign): Ensure that the rank of _def_init is zero. (gfc_conv_variable): Make sure the temp array descriptor is returned for class arrays, too, and that class arrays are dereferenced correctly. (gfc_conv_procedure_call): For polymorphic type initialization the initializer has to be a pointer to _def_init stored in a dummy variable, which then needs to be used by value. * trans-intrinsic.c (gfc_conv_intrinsic_sizeof): Use the temporary array descriptor for class arrays, too. (gfc_conv_intrinsic_storage_size): Likewise. * trans-stmt.c (trans_associate_var): Use a temporary array descriptor for the associate variable of class arrays, too, making the array one-based (lbound == 1). * trans-types.c (gfc_is_nodesc_array): Use the correct array data. * trans.c (gfc_build_array_ref): Use the dummy array descriptor when present. gcc/testsuite/ChangeLog: 2015-03-24 Andre Vehreschild <vehre@gmx.de> * gfortran.dg/class_array_20.f03: New test. * gfortran.dg/finalize_10.f90: Correct scan tree expressions to cope with temporary array descriptors for class arrays. * gfortran.dg/finalize_15.f90: Fixing comparision to model initialization correctly. * gfortran.dg/finalize_29.f08: New test. [-- Attachment #3: pr60322_4.patch --] [-- Type: text/x-patch, Size: 44646 bytes --] diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c index 65495d2..7f3a59d 100644 --- a/gcc/fortran/expr.c +++ b/gcc/fortran/expr.c @@ -4060,7 +4060,7 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name); /* It will always be a full array. */ - as = sym->ts.type == BT_CLASS ? CLASS_DATA (sym)->as : sym->as; + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; lval->rank = as ? as->rank : 0; if (lval->rank) gfc_add_full_array_ref (lval, as); diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 8e6595f..901a1c0 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -3206,6 +3206,11 @@ bool gfc_is_finalizable (gfc_symbol *, gfc_expr **); && CLASS_DATA (sym) \ && CLASS_DATA (sym)->ts.u.derived \ && CLASS_DATA (sym)->ts.u.derived->attr.unlimited_polymorphic) +#define IS_CLASS_ARRAY(sym) \ + (sym->ts.type == BT_CLASS \ + && CLASS_DATA (sym) \ + && CLASS_DATA (sym)->attr.dimension \ + && !CLASS_DATA (sym)->attr.class_pointer) /* frontend-passes.c */ diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index afe73a9..0804d45 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -2495,11 +2495,14 @@ gfc_add_loop_ss_code (gfc_loopinfo * loop, gfc_ss * ss, bool subscript, case GFC_SS_REFERENCE: /* Scalar argument to elemental procedure. */ gfc_init_se (&se, NULL); - if (ss_info->can_be_null_ref) + if (ss_info->can_be_null_ref || (expr->symtree + && (expr->symtree->n.sym->ts.type == BT_DERIVED + || expr->symtree->n.sym->ts.type == BT_CLASS))) { /* If the actual argument can be absent (in other words, it can be a NULL reference), don't try to evaluate it; pass instead - the reference directly. */ + the reference directly. The reference is also needed when + expr is of type class or derived. */ gfc_conv_expr_reference (&se, expr); } else @@ -3046,7 +3049,14 @@ build_class_array_ref (gfc_se *se, tree base, tree index) return false; } else if (class_ref == NULL) - decl = expr->symtree->n.sym->backend_decl; + { + decl = expr->symtree->n.sym->backend_decl; + /* For class arrays the tree containing the class is stored in + GFC_DECL_SAVED_DESCRIPTOR of the sym's backend_decl. + For all others it's sym's backend_decl directly. */ + if (DECL_LANG_SPECIFIC (decl) && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); + } else { /* Remove everything after the last class reference, convert the @@ -3159,26 +3169,41 @@ build_array_ref (tree desc, tree offset, tree decl) { tree tmp; tree type; + tree cdecl; + bool classarray = false; + + /* For class arrays the class declaration is stored in the saved + descriptor. */ + if (INDIRECT_REF_P (desc) + && DECL_LANG_SPECIFIC (TREE_OPERAND (desc, 0)) + && GFC_DECL_SAVED_DESCRIPTOR (TREE_OPERAND (desc, 0))) + cdecl = gfc_class_data_get (GFC_DECL_SAVED_DESCRIPTOR ( + TREE_OPERAND (desc, 0))); + else + cdecl = desc; /* Class container types do not always have the GFC_CLASS_TYPE_P but the canonical type does. */ - if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)) - && TREE_CODE (desc) == COMPONENT_REF) + if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (cdecl)) + && TREE_CODE (cdecl) == COMPONENT_REF) { - type = TREE_TYPE (TREE_OPERAND (desc, 0)); + type = TREE_TYPE (TREE_OPERAND (cdecl, 0)); if (TYPE_CANONICAL (type) && GFC_CLASS_TYPE_P (TYPE_CANONICAL (type))) - type = TYPE_CANONICAL (type); + { + type = TREE_TYPE (desc); + classarray = true; + } } else type = NULL; /* Class array references need special treatment because the assigned type size needs to be used to point to the element. */ - if (type && GFC_CLASS_TYPE_P (type)) + if (classarray) { - type = gfc_get_element_type (TREE_TYPE (desc)); - tmp = TREE_OPERAND (desc, 0); + type = gfc_get_element_type (type); + tmp = TREE_OPERAND (cdecl, 0); tmp = gfc_get_class_array_ref (offset, tmp); tmp = fold_convert (build_pointer_type (type), tmp); tmp = build_fold_indirect_ref_loc (input_location, tmp); @@ -5570,7 +5595,7 @@ gfc_trans_array_cobounds (tree type, stmtblock_t * pblock, gfc_se se; gfc_array_spec *as; - as = sym->as; + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; for (dim = as->rank; dim < as->rank + as->corank; dim++) { @@ -5613,7 +5638,7 @@ gfc_trans_array_bounds (tree type, gfc_symbol * sym, tree * poffset, int dim; - as = sym->as; + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; size = gfc_index_one_node; offset = gfc_index_zero_node; @@ -5901,12 +5926,16 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, int no_repack; bool optional_arg; gfc_array_spec *as; + bool is_classarray = IS_CLASS_ARRAY (sym); /* Do nothing for pointer and allocatable arrays. */ - if (sym->attr.pointer || sym->attr.allocatable) + if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) + || sym->attr.allocatable + || (is_classarray && CLASS_DATA (sym)->attr.allocatable)) return; - if (sym->attr.dummy && gfc_is_nodesc_array (sym)) + if (!is_classarray && sym->attr.dummy && gfc_is_nodesc_array (sym)) { gfc_trans_g77_array (sym, block); return; @@ -5919,8 +5948,13 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, type = TREE_TYPE (tmpdesc); gcc_assert (GFC_ARRAY_TYPE_P (type)); dumdesc = GFC_DECL_SAVED_DESCRIPTOR (tmpdesc); - dumdesc = build_fold_indirect_ref_loc (input_location, dumdesc); - as = sym->as; + if (is_classarray) + /* For a class array the dummy array descriptor is in the _class + component. */ + dumdesc = gfc_class_data_get (dumdesc); + else + dumdesc = build_fold_indirect_ref_loc (input_location, dumdesc); + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; gfc_start_block (&init); if (sym->ts.type == BT_CHARACTER @@ -6791,6 +6825,7 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) tree from; tree to; tree base; + bool onebased = false; ndim = info->ref ? info->ref->u.ar.dimen : ss->dimen; @@ -6932,6 +6967,7 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) gfc_array_index_type, to, tmp); from = gfc_index_one_node; } + onebased = integer_onep (from); gfc_conv_descriptor_lbound_set (&loop.pre, parm, gfc_rank_cst[dim], from); @@ -6988,13 +7024,27 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) gfc_get_dataptr_offset (&loop.pre, parm, desc, offset, subref_array_target, expr); - if (((se->direct_byref || GFC_ARRAY_TYPE_P (TREE_TYPE (desc))) - && !se->data_not_needed) - || (se->use_offset && base != NULL_TREE)) + /* Force the offset to be -1, when the lower bound of the highest + dimension is one and the symbol is present and is not a + pointer/allocatable or associated. */ + if (onebased && se->use_offset + && expr->symtree + && !expr->symtree->n.sym->attr.allocatable + && !expr->symtree->n.sym->attr.pointer + && !expr->symtree->n.sym->attr.host_assoc + && !expr->symtree->n.sym->attr.use_assoc) { - /* Set the offset. */ - gfc_conv_descriptor_offset_set (&loop.pre, parm, base); + /* Set the offset to -1. */ + mpz_t minus_one; + mpz_init_set_si (minus_one, -1); + tmp = gfc_conv_mpz_to_tree (minus_one, gfc_index_integer_kind); + gfc_conv_descriptor_offset_set (&loop.pre, parm, tmp); } + else if (((se->direct_byref || GFC_ARRAY_TYPE_P (TREE_TYPE (desc))) + && !se->data_not_needed) + || (se->use_offset && base != NULL_TREE)) + /* Set the offset depending on base. */ + gfc_conv_descriptor_offset_set (&loop.pre, parm, base); else { /* Only the callee knows what the correct offset it, so just set diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c index d3fcdd1..895733b 100644 --- a/gcc/fortran/trans-decl.c +++ b/gcc/fortran/trans-decl.c @@ -814,10 +814,11 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) gfc_namespace* procns; symbol_attribute *array_attr; gfc_array_spec *as; + bool is_classarray = IS_CLASS_ARRAY (sym); type = TREE_TYPE (decl); - array_attr = &sym->attr; - as = sym->as; + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; /* We just use the descriptor, if there is one. */ if (GFC_DESCRIPTOR_TYPE_P (type)) @@ -1023,14 +1024,19 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) gfc_packed packed; int n; bool known_size; + bool is_classarray = IS_CLASS_ARRAY (sym); /* Use the array as and attr. */ - as = sym->as; - array_attr = &sym->attr; - - /* The pointer attribute is always set on a _data component, therefore check - the sym's attribute only. */ - if (sym->attr.pointer || array_attr->allocatable + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + + /* The dummy is returned for pointer, allocatable or assumed rank arrays. + The check for pointerness needs to be repeated here (it is done in + IS_CLASS_ARRAY (), too), because for class arrays that are pointers, as + is the one of the sym, which is incorrect here. */ + if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) + || array_attr->allocatable || (as && as->type == AS_ASSUMED_RANK)) return dummy; @@ -1039,24 +1045,27 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) if (sym->attr.result || sym->attr.dummy) gfc_defer_symbol_init (sym); - type = TREE_TYPE (dummy); + /* For a class array the array descriptor is in the _data component, while + for a regular array the TREE_TYPE of the dummy is a pointer to the + descriptor. */ + type = TREE_TYPE (is_classarray ? gfc_class_data_get (dummy) + : TREE_TYPE (dummy)); + /* type now is the array descriptor w/o any indirection. */ gcc_assert (TREE_CODE (dummy) == PARM_DECL - && POINTER_TYPE_P (type)); + && POINTER_TYPE_P (TREE_TYPE (dummy))); /* Do we know the element size? */ known_size = sym->ts.type != BT_CHARACTER || INTEGER_CST_P (sym->ts.u.cl->backend_decl); - if (known_size && !GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (type))) + if (known_size && !GFC_DESCRIPTOR_TYPE_P (type)) { /* For descriptorless arrays with known element size the actual argument is sufficient. */ - gcc_assert (GFC_ARRAY_TYPE_P (type)); gfc_build_qualified_array (dummy, sym); return dummy; } - type = TREE_TYPE (type); if (GFC_DESCRIPTOR_TYPE_P (type)) { /* Create a descriptorless array pointer. */ @@ -1090,7 +1099,10 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) packed = PACKED_PARTIAL; } - type = gfc_typenode_for_spec (&sym->ts); + /* For classarrays the element type is required, but + gfc_typenode_for_spec () returns the array descriptor. */ + type = is_classarray ? gfc_get_element_type (type) + : gfc_typenode_for_spec (&sym->ts); type = gfc_get_nodesc_array_type (type, as, packed, !sym->attr.target); } @@ -1440,13 +1452,30 @@ gfc_get_symbol_decl (gfc_symbol * sym) sym->backend_decl = decl; } + /* Returning the descriptor for dummy class arrays is hazardous, because + some caller is expecting an expression to apply the component refs to. + Therefore the descriptor is only created and stored in + sym->backend_decl's GFC_DECL_SAVED_DESCRIPTOR. The caller is then + responsible to extract it from there, when the descriptor is + desired. */ + if (IS_CLASS_ARRAY (sym) + && (!DECL_LANG_SPECIFIC (sym->backend_decl) + || !GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl))) + { + decl = gfc_build_dummy_array_decl (sym, sym->backend_decl); + /* Prevent the dummy from being detected as unused if it is copied. */ + if (sym->backend_decl != NULL && decl != sym->backend_decl) + DECL_ARTIFICIAL (sym->backend_decl) = 1; + sym->backend_decl = decl; + } + TREE_USED (sym->backend_decl) = 1; if (sym->attr.assign && GFC_DECL_ASSIGN (sym->backend_decl) == 0) { gfc_add_assign_aux_vars (sym); } - if (sym->attr.dimension + if ((sym->attr.dimension || IS_CLASS_ARRAY (sym)) && DECL_LANG_SPECIFIC (sym->backend_decl) && GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl) && DECL_CONTEXT (sym->backend_decl) != current_function_decl) @@ -3987,14 +4016,16 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) = gfc_class_set_static_fields (sym->backend_decl, vptr, tmp); TREE_CONSTANT (DECL_INITIAL (sym->backend_decl)) = 1; } - else if (sym->attr.dimension || sym->attr.codimension) + else if (sym->attr.dimension || sym->attr.codimension + || (IS_CLASS_ARRAY (sym) && !CLASS_DATA (sym)->attr.allocatable)) { + bool is_classarray = IS_CLASS_ARRAY (sym); symbol_attribute *array_attr; gfc_array_spec *as; array_type tmp; - array_attr = &sym->attr; - as = sym->as; + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; /* Assumed-size Cray pointees need to be treated as AS_EXPLICIT. */ tmp = as->type; if (tmp == AS_ASSUMED_SIZE && as->cp_was_assumed) @@ -4004,10 +4035,12 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) case AS_EXPLICIT: if (sym->attr.dummy || sym->attr.result) gfc_trans_dummy_array_bias (sym, sym->backend_decl, block); - /* In a class array the _data component always has the pointer - attribute set. Therefore only check for allocatable in the - array attributes and for pointer in the symbol. */ - else if (sym->attr.pointer || array_attr->allocatable) + /* Allocatable and pointer arrays need to processed + explicitly. */ + else if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS + && CLASS_DATA (sym)->attr.class_pointer) + || array_attr->allocatable) { if (TREE_STATIC (sym->backend_decl)) { @@ -4124,6 +4157,7 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) } else { + se.descriptor_only = 1; gfc_conv_expr (&se, e); descriptor = se.expr; se.expr = gfc_conv_descriptor_data_addr (se.expr); diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index 9bf976a..664c2c6 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -149,6 +149,11 @@ tree gfc_class_vptr_get (tree decl) { tree vptr; + /* For class arrays decl may be a temporary descriptor handle, the vptr is + then available through the saved descriptor. */ + if (TREE_CODE (decl) == VAR_DECL && DECL_LANG_SPECIFIC (decl) + && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); if (POINTER_TYPE_P (TREE_TYPE (decl))) decl = build_fold_indirect_ref_loc (input_location, decl); vptr = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (decl)), @@ -163,6 +168,11 @@ tree gfc_class_len_get (tree decl) { tree len; + /* For class arrays decl may be a temporary descriptor handle, the len is + then available through the saved descriptor. */ + if (TREE_CODE (decl) == VAR_DECL && DECL_LANG_SPECIFIC (decl) + && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); if (POINTER_TYPE_P (TREE_TYPE (decl))) decl = build_fold_indirect_ref_loc (input_location, decl); len = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (decl)), @@ -883,7 +893,11 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts, tmp = NULL_TREE; if (class_ref == NULL && e->symtree && e->symtree->n.sym->ts.type == BT_CLASS) - tmp = e->symtree->n.sym->backend_decl; + { + tmp = e->symtree->n.sym->backend_decl; + if (DECL_LANG_SPECIFIC (tmp) && GFC_DECL_SAVED_DESCRIPTOR (tmp)) + tmp = GFC_DECL_SAVED_DESCRIPTOR (tmp); + } else { /* Remove everything after the last class reference, convert the @@ -918,6 +932,13 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts, tree tmp2; cond = gfc_conv_expr_present (e->symtree->n.sym); + /* parmse->pre may contain some preparatory instructions for the + temporary array descriptor. Those may only be executed when the + optional argument is set, therefore add parmse->pre's instructions + to block, which is later guarded by an if (optional_arg_given). */ + gfc_add_block_to_block (&parmse->pre, &block); + block.head = parmse->pre.head; + parmse->pre.head = NULL_TREE; tmp = gfc_finish_block (&block); if (optional_alloc_ptr) @@ -1191,6 +1212,8 @@ gfc_trans_class_init_assign (gfc_code *code) been referenced. */ gfc_get_derived_type (rhs->ts.u.derived); gfc_add_def_init_component (rhs); + /* The _def_init is always scalar. */ + rhs->rank = 0; if (code->expr1->ts.type == BT_CLASS && CLASS_DATA (code->expr1)->attr.dimension) @@ -2246,8 +2269,11 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) bool return_value; bool alternate_entry; bool entry_master; + bool is_classarray; + bool first_time = true; sym = expr->symtree->n.sym; + is_classarray = IS_CLASS_ARRAY (sym); ss = se->ss; if (ss != NULL) { @@ -2351,9 +2377,24 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) } else if (!sym->attr.value) { + /* Dereference temporaries for class array dummy arguments. */ + if (sym->attr.dummy && is_classarray + && GFC_ARRAY_TYPE_P (TREE_TYPE (se->expr))) + { + if (!se->descriptor_only) + se->expr = GFC_DECL_SAVED_DESCRIPTOR (se->expr); + + se->expr = build_fold_indirect_ref_loc (input_location, + se->expr); + } + /* Dereference non-character scalar dummy arguments. */ if (sym->attr.dummy && !sym->attr.dimension - && !(sym->attr.codimension && sym->attr.allocatable)) + && !(sym->attr.codimension && sym->attr.allocatable) + && (sym->ts.type != BT_CLASS + || (!CLASS_DATA (sym)->attr.dimension + && !(CLASS_DATA (sym)->attr.codimension + && CLASS_DATA (sym)->attr.allocatable)))) se->expr = build_fold_indirect_ref_loc (input_location, se->expr); @@ -2365,11 +2406,12 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) se->expr = build_fold_indirect_ref_loc (input_location, se->expr); - /* Dereference non-character pointer variables. + /* Dereference non-character, non-class pointer variables. These must be dummies, results, or scalars. */ - if ((sym->attr.pointer || sym->attr.allocatable - || gfc_is_associate_pointer (sym) - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) + if (!is_classarray + && (sym->attr.pointer || sym->attr.allocatable + || gfc_is_associate_pointer (sym) + || (sym->as && sym->as->type == AS_ASSUMED_RANK)) && (sym->attr.dummy || sym->attr.function || sym->attr.result @@ -2377,6 +2419,32 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) && (!sym->attr.codimension || !sym->attr.allocatable)))) se->expr = build_fold_indirect_ref_loc (input_location, se->expr); + /* Now treat the class array pointer variables accordingly. */ + else if (sym->ts.type == BT_CLASS + && sym->attr.dummy + && (CLASS_DATA (sym)->attr.dimension + || CLASS_DATA (sym)->attr.codimension) + && ((CLASS_DATA (sym)->as + && CLASS_DATA (sym)->as->type == AS_ASSUMED_RANK) + || CLASS_DATA (sym)->attr.allocatable + || CLASS_DATA (sym)->attr.class_pointer)) + se->expr = build_fold_indirect_ref_loc (input_location, + se->expr); + /* And the case where a non-dummy, non-result, non-function, + non-allotable and non-pointer classarray is present. This case was + previously covered by the first if, but with introducing the + condition !is_classarray there, that case has to be covered + explicitly. */ + else if (sym->ts.type == BT_CLASS + && !sym->attr.dummy + && !sym->attr.function + && !sym->attr.result + && (CLASS_DATA (sym)->attr.dimension + || CLASS_DATA (sym)->attr.codimension) + && !CLASS_DATA (sym)->attr.allocatable + && !CLASS_DATA (sym)->attr.class_pointer) + se->expr = build_fold_indirect_ref_loc (input_location, + se->expr); } ref = expr->ref; @@ -2414,6 +2482,18 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) break; case REF_COMPONENT: + if (first_time && is_classarray && sym->attr.dummy + && se->descriptor_only + && !CLASS_DATA (sym)->attr.allocatable + && !CLASS_DATA (sym)->attr.class_pointer + && CLASS_DATA (sym)->as + && CLASS_DATA (sym)->as->type != AS_ASSUMED_RANK + && strcmp ("_data", ref->u.c.component->name) == 0) + /* Skip the first ref of a _data component, because for class + arrays that one is already done by introducing a temporary + array descriptor. */ + break; + if (ref->u.c.sym->attr.extension) conv_parent_component_references (se, ref); @@ -2433,6 +2513,7 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) gcc_unreachable (); break; } + first_time = false; ref = ref->next; } /* Pointer assignment, allocation or pass by reference. Arrays are handled @@ -4559,7 +4640,19 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, gfc_init_se (&parmse, se); parm_kind = ELEMENTAL; - if (fsym && fsym->attr.value) + /* For all value functions or polymorphic scalar non-pointer + non-allocatable variables use the expression in e directly. This + ensures, that initializers of polymorphic entities are correctly + copied. */ + if (fsym && (fsym->attr.value + || (e->expr_type == EXPR_VARIABLE + && fsym->ts.type == BT_DERIVED + && e->ts.type == BT_DERIVED + && !e->ts.u.derived->attr.dimension + && !e->rank + && (!e->symtree + || (!e->symtree->n.sym->attr.allocatable + && !e->symtree->n.sym->attr.pointer))))) gfc_conv_expr (&parmse, e); else gfc_conv_expr_reference (&parmse, e); diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index c4ccb7b..cb693c0 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -5921,8 +5921,17 @@ gfc_conv_intrinsic_sizeof (gfc_se *se, gfc_expr *expr) } else if (arg->ts.type == BT_CLASS) { - if (arg->rank) + /* For deferred length arrays, conv_expr_descriptor returns an + indirect_ref to the component. */ + if (arg->rank < 0 + || (arg->rank > 0 && !VAR_P (argse.expr) + && GFC_DECL_CLASS (TREE_OPERAND (argse.expr, 0)))) byte_size = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0)); + else if (arg->rank > 0) + /* The scalarizer added an additional temp. To get the class' vptr + one has to look at the original backend_decl. */ + byte_size = gfc_class_vtab_size_get ( + GFC_DECL_SAVED_DESCRIPTOR (arg->symtree->n.sym->backend_decl)); else byte_size = gfc_class_vtab_size_get (argse.expr); } @@ -6053,7 +6062,11 @@ gfc_conv_intrinsic_storage_size (gfc_se *se, gfc_expr *expr) gfc_conv_expr_descriptor (&argse, arg); if (arg->ts.type == BT_CLASS) { - tmp = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0)); + if (arg->rank > 0) + tmp = gfc_class_vtab_size_get ( + GFC_DECL_SAVED_DESCRIPTOR (arg->symtree->n.sym->backend_decl)); + else + tmp = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0)); tmp = fold_convert (result_type, tmp); goto done; } diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c index a6fb52c..6ffae6e79e 100644 --- a/gcc/fortran/trans-stmt.c +++ b/gcc/fortran/trans-stmt.c @@ -1260,12 +1260,29 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) gfc_init_se (&se, NULL); se.descriptor_only = 1; - gfc_conv_expr (&se, e); + /* In a select type the (temporary) associate variable shall point to + a standart fortran array (lower bound == 1), but conv_expr () + just maps to the input array in the class object, whose lbound may + be arbitrary. conv_expr_descriptor solves this by inserting a + temporary array descriptor. */ + gfc_conv_expr_descriptor (&se, e); - gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se.expr))); + gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se.expr)) + || GFC_ARRAY_TYPE_P (TREE_TYPE (se.expr))); gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (sym->backend_decl))); - gfc_add_modify (&se.pre, sym->backend_decl, se.expr); + if (GFC_ARRAY_TYPE_P (TREE_TYPE (se.expr))) + { + if (INDIRECT_REF_P (se.expr)) + tmp = TREE_OPERAND (se.expr, 0); + else + tmp = se.expr; + + gfc_add_modify (&se.pre, sym->backend_decl, + gfc_class_data_get (GFC_DECL_SAVED_DESCRIPTOR (tmp))); + } + else + gfc_add_modify (&se.pre, sym->backend_decl, se.expr); if (unlimited) { @@ -1276,7 +1293,7 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) gfc_get_dtype (TREE_TYPE (sym->backend_decl))); } - gfc_add_init_cleanup (block, gfc_finish_block( &se.pre), + gfc_add_init_cleanup (block, gfc_finish_block (&se.pre), gfc_finish_block (&se.post)); } @@ -1319,9 +1336,18 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) } if (need_len_assign) { - /* Get the _len comp from the target expr by stripping _data - from it and adding component-ref to _len. */ - tmp = gfc_class_len_get (TREE_OPERAND (target_expr, 0)); + if (e->symtree + && DECL_LANG_SPECIFIC (e->symtree->n.sym->backend_decl) + && GFC_DECL_SAVED_DESCRIPTOR (e->symtree->n.sym->backend_decl)) + /* Use the original class descriptor stored in the saved + descriptor to get the target_expr. */ + target_expr = + GFC_DECL_SAVED_DESCRIPTOR (e->symtree->n.sym->backend_decl); + else + /* Strip the _data component from the target_expr. */ + target_expr = TREE_OPERAND (target_expr, 0); + /* Add a reference to the _len comp to the target expr. */ + tmp = gfc_class_len_get (target_expr); /* Get the component-ref for the temp structure's _len comp. */ charlen = gfc_class_len_get (se.expr); /* Add the assign to the beginning of the the block... */ diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c index 1838a2e..b9f662d 100644 --- a/gcc/fortran/trans-types.c +++ b/gcc/fortran/trans-types.c @@ -1290,14 +1290,17 @@ gfc_is_nodesc_array (gfc_symbol * sym) { symbol_attribute *array_attr; gfc_array_spec *as; + bool is_classarray = IS_CLASS_ARRAY (sym); - array_attr = &sym->attr; - as = sym->as; + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; gcc_assert (array_attr->dimension || array_attr->codimension); /* We only want local arrays. */ - if (sym->attr.pointer || array_attr->allocatable) + if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) + || array_attr->allocatable) return 0; /* We want a descriptor for associate-name arrays that do not have an diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c index b7ec0e5..394745e 100644 --- a/gcc/fortran/trans.c +++ b/gcc/fortran/trans.c @@ -362,16 +362,23 @@ gfc_build_array_ref (tree base, tree offset, tree decl) { if (GFC_DECL_CLASS (decl)) { - /* Allow for dummy arguments and other good things. */ - if (POINTER_TYPE_P (TREE_TYPE (decl))) - decl = build_fold_indirect_ref_loc (input_location, decl); - - /* Check if '_data' is an array descriptor. If it is not, - the array must be one of the components of the class object, - so return a normal array reference. */ - if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (gfc_class_data_get (decl)))) - return build4_loc (input_location, ARRAY_REF, type, base, - offset, NULL_TREE, NULL_TREE); + /* When a temporary is in place for the class array, then the original + class' declaration is stored in the saved descriptor. */ + if (DECL_LANG_SPECIFIC (decl) && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); + else + { + /* Allow for dummy arguments and other good things. */ + if (POINTER_TYPE_P (TREE_TYPE (decl))) + decl = build_fold_indirect_ref_loc (input_location, decl); + + /* Check if '_data' is an array descriptor. If it is not, + the array must be one of the components of the class object, + so return a normal array reference. */ + if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (gfc_class_data_get (decl)))) + return build4_loc (input_location, ARRAY_REF, type, base, + offset, NULL_TREE, NULL_TREE); + } span = gfc_class_vtab_size_get (decl); } diff --git a/gcc/testsuite/gfortran.dg/class_array_20.f03 b/gcc/testsuite/gfortran.dg/class_array_20.f03 new file mode 100644 index 0000000..c49f7d2 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/class_array_20.f03 @@ -0,0 +1,100 @@ +! {dg-do run} +! +! Test contributed by Thomas L. Clune via pr60322 +! and Antony Lewis via pr64692 + +program class_array_20 + implicit none + + type Foo + end type + + type(foo), dimension(2:3) :: arg + integer :: oneDarr(2) + integer :: twoDarr(2,3) + integer :: x, y + double precision :: P(2, 2) + + ! Checking for PR/60322 + call copyFromClassArray([Foo(), Foo()]) + call copyFromClassArray(arg) + call copyFromClassArray(arg(:)) + + x= 3 + y= 4 + oneDarr = [x, y] + call W([x, y]) + call W(oneDarr) + call W([3, 4]) + + twoDarr = reshape([3, 4, 5, 5, 6, 7], [2, 3]) + call WtwoD(twoDarr) + call WtwoD(reshape([3, 4, 5, 5, 6, 7], [2, 3])) + + ! Checking for PR/64692 + P(1:2, 1) = [1.d0, 2.d0] + P(1:2, 2) = [3.d0, 4.d0] + call AddArray(P(1:2, 2)) + +contains + + subroutine copyFromClassArray(classarray) + class (Foo), intent(in) :: classarray(:) + + if (lbound(classarray, 1) .ne. 1) call abort() + if (ubound(classarray, 1) .ne. 2) call abort() + if (size(classarray) .ne. 2) call abort() + end subroutine + + subroutine AddArray(P) + class(*), target, intent(in) :: P(:) + class(*), pointer :: Pt(:) + + allocate(Pt(1:size(P)), source= P) + + select type (P) + type is (double precision) + if (abs(P(1)-3.d0) .gt. 1.d-8) call abort() + if (abs(P(2)-4.d0) .gt. 1.d-8) call abort() + class default + call abort() + end select + + select type (Pt) + type is (double precision) + if (abs(Pt(1)-3.d0) .gt. 1.d-8) call abort() + if (abs(Pt(2)-4.d0) .gt. 1.d-8) call abort() + class default + call abort() + end select + end subroutine + + subroutine W(ar) + class(*), intent(in) :: ar(:) + + if (lbound(ar, 1) /= 1) call abort() + select type (ar) + type is (integer) + ! The indeces 1:2 are essential here, or else one would not + ! note, that the array internally starts at 0, although the + ! check for the lbound above went fine. + if (any (ar(1:2) .ne. [3, 4])) call abort() + class default + call abort() + end select + end subroutine + + subroutine WtwoD(ar) + class(*), intent(in) :: ar(:,:) + + if (any (lbound(ar) /= [1, 1])) call abort() + select type (ar) + type is (integer) + if (any (reshape(ar(1:2,1:3), [6]) .ne. [3, 4, 5, 5, 6, 7])) & + call abort() + class default + call abort() + end select + end subroutine +end program class_array_20 + diff --git a/gcc/testsuite/gfortran.dg/finalize_10.f90 b/gcc/testsuite/gfortran.dg/finalize_10.f90 index e042f11..32386ce 100644 --- a/gcc/testsuite/gfortran.dg/finalize_10.f90 +++ b/gcc/testsuite/gfortran.dg/finalize_10.f90 @@ -27,8 +27,8 @@ end subroutine foo ! Finalize CLASS + set default init ! { dg-final { scan-tree-dump-times "y->_vptr->_final \\(&desc.\[0-9\]+, y->_vptr->_size, 0\\);" 1 "original" } } ! { dg-final { scan-tree-dump "__builtin_memcpy \\(\\(void .\\) y->_data, \\(void .\\) y->_vptr->_def_init, \\((unsigned long|unsigned int|character\\(kind=4\\))\\) y->_vptr->_size\\);" "original" } } -! { dg-final { scan-tree-dump-times "x->_vptr->_final \\(&x->_data, x->_vptr->_size, 0\\);" 1 "original" } } -! { dg-final { scan-tree-dump-times "x->_vptr->_copy \\(x->_vptr->_def_init, &x->_data\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times "x->_vptr->_final \\(&parm.\[0-9\]+, x->_vptr->_size, 0\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times "x->_vptr->_copy \\(" 1 "original" } } ! FINALIZE TYPE: ! { dg-final { scan-tree-dump-times "parm.\[0-9\]+.data = \\(void \\*\\) &\\(\\*aa.\[0-9\]+\\)\\\[0\\\];" 1 "original" } } diff --git a/gcc/testsuite/gfortran.dg/finalize_15.f90 b/gcc/testsuite/gfortran.dg/finalize_15.f90 index 3c18b2a..d5ba28f 100644 --- a/gcc/testsuite/gfortran.dg/finalize_15.f90 +++ b/gcc/testsuite/gfortran.dg/finalize_15.f90 @@ -9,37 +9,37 @@ module m implicit none type t1 - integer :: i + integer :: i = 1 contains final :: fini_elem end type t1 type, extends(t1) :: t1e - integer :: j + integer :: j = 11 contains final :: fini_elem2 end type t1e type t2 - integer :: i + integer :: i = 2 contains final :: fini_shape end type t2 type, extends(t2) :: t2e - integer :: j + integer :: j = 22 contains final :: fini_shape2 end type t2e type t3 - integer :: i + integer :: i = 3 contains final :: fini_explicit end type t3 type, extends(t3) :: t3e - integer :: j + integer :: j = 33 contains final :: fini_explicit2 end type t3e @@ -204,31 +204,31 @@ program test select type(x) type is (t1e) - call check_val(x%i, 1) - call check_val(x%j, 100) + call check_val(x%i, 1, 1) + call check_val(x%j, 100, 11) end select select type(y) type is (t2e) - call check_val(y%i, 1) - call check_val(y%j, 100) + call check_val(y%i, 1, 2) + call check_val(y%j, 100, 22) end select select type(z) type is (t3e) - call check_val(z%i, 1) - call check_val(z%j, 100) + call check_val(z%i, 1, 3) + call check_val(z%j, 100, 33) end select contains - subroutine check_val(x, factor) + subroutine check_val(x, factor, val) integer :: x(:,:) - integer, value :: factor + integer, value :: factor, val integer :: i, j do i = 1, 10 do j = 1, 10 if (mod (j-1, 2) == 0 .and. mod (i-1, 3) == 0) then - if (x(j,i) /= (j + 100*i)*factor*(-13)) call abort () + if (x(j,i) /= val) call abort () else if (x(j,i) /= (j + 100*i)*factor) call abort () end if diff --git a/gcc/testsuite/gfortran.dg/finalize_29.f08 b/gcc/testsuite/gfortran.dg/finalize_29.f08 new file mode 100644 index 0000000..1f5f7424 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/finalize_29.f08 @@ -0,0 +1,289 @@ +! {dg-do run} +! +! Testcase contributed by Andre Vehreschild <vehre@gcc.gnu.org> + +module module_finalize_29 + implicit none + + ! The type name is encoding the state of its finalizer being + ! elemental (second letter 'e'), or non-element (second letter 'n') + ! or array shaped (second letter 'a'), or shape-specific routine + ! (generic; second letter 'g'), + ! and whether the init-routine is elemental or not (third letter + ! either 'e' or 'n'). + type ten + integer :: i = 40 + contains + final :: ten_fin + end type ten + + type tee + integer :: i = 41 + contains + final :: tee_fin + end type tee + + type tne + integer :: i = 42 + contains + final :: tne_fin + end type tne + + type tnn + integer :: i = 43 + contains + final :: tnn_fin + end type tnn + + type tae + integer :: i = 44 + contains + final :: tae_fin + end type tae + + type tan + integer :: i = 45 + contains + final :: tan_fin + end type tan + + type tge + integer :: i = 46 + contains + final :: tge_scalar_fin, tge_array_fin + end type tge + + type tgn + integer :: i = 47 + contains + final :: tgn_scalar_fin, tgn_array_fin + end type tgn + + integer :: ten_fin_counts, tee_fin_counts, tne_fin_counts, tnn_fin_counts + integer :: tae_fin_counts, tan_fin_counts + integer :: tge_scalar_fin_counts, tge_array_fin_counts + integer :: tgn_scalar_fin_counts, tgn_array_fin_counts +contains + impure elemental subroutine ten_fin(x) + type(ten), intent(inout) :: x + x%i = -10 * x%i + ten_fin_counts = ten_fin_counts + 1 + end subroutine ten_fin + + impure elemental subroutine tee_fin(x) + type(tee), intent(inout) :: x + x%i = -11 * x%i + tee_fin_counts = tee_fin_counts + 1 + end subroutine tee_fin + + subroutine tne_fin(x) + type(tne), intent(inout) :: x + x%i = -12 * x%i + tne_fin_counts = tne_fin_counts + 1 + end subroutine tne_fin + + subroutine tnn_fin(x) + type(tnn), intent(inout) :: x + x%i = -13 * x%i + tnn_fin_counts = tnn_fin_counts + 1 + end subroutine tnn_fin + + subroutine tae_fin(x) + type(tae), intent(inout) :: x(:,:) + x%i = -14 * x%i + tae_fin_counts = tae_fin_counts + 1 + end subroutine tae_fin + + subroutine tan_fin(x) + type(tan), intent(inout) :: x(:,:) + x%i = -15 * x%i + tan_fin_counts = tan_fin_counts + 1 + end subroutine tan_fin + + subroutine tge_scalar_fin(x) + type(tge), intent(inout) :: x + x%i = -16 * x%i + tge_scalar_fin_counts = tge_scalar_fin_counts + 1 + end subroutine tge_scalar_fin + + subroutine tge_array_fin(x) + type(tge), intent(inout) :: x(:,:) + x%i = -17 * x%i + tge_array_fin_counts = tge_array_fin_counts + 1 + end subroutine tge_array_fin + + subroutine tgn_scalar_fin(x) + type(tgn), intent(inout) :: x + x%i = -18 * x%i + tgn_scalar_fin_counts = tgn_scalar_fin_counts + 1 + end subroutine tgn_scalar_fin + + subroutine tgn_array_fin(x) + type(tgn), intent(inout) :: x(:,:) + x%i = -19 * x%i + tgn_array_fin_counts = tgn_array_fin_counts + 1 + end subroutine tgn_array_fin + + ! The finalizer/initializer call producer + subroutine ten_init(x) + class(ten), intent(out) :: x(:,:) + end subroutine ten_init + + impure elemental subroutine tee_init(x) + class(tee), intent(out) :: x + end subroutine tee_init + + impure elemental subroutine tne_init(x) + class(tne), intent(out) :: x + end subroutine tne_init + + subroutine tnn_init(x) + class(tnn), intent(out) :: x(:,:) + end subroutine tnn_init + + impure elemental subroutine tae_init(x) + class(tae), intent(out) :: x + end subroutine tae_init + + subroutine tan_init(x) + class(tan), intent(out) :: x(:,:) + end subroutine tan_init + + impure elemental subroutine tge_init(x) + class(tge), intent(out) :: x + end subroutine tge_init + + subroutine tgn_init(x) + class(tgn), intent(out) :: x(:,:) + end subroutine tgn_init +end module module_finalize_29 + +program finalize_29 + use module_finalize_29 + implicit none + + type(ten), allocatable :: x_ten(:,:) + type(tee), allocatable :: x_tee(:,:) + type(tne), allocatable :: x_tne(:,:) + type(tnn), allocatable :: x_tnn(:,:) + type(tae), allocatable :: x_tae(:,:) + type(tan), allocatable :: x_tan(:,:) + type(tge), allocatable :: x_tge(:,:) + type(tgn), allocatable :: x_tgn(:,:) + + ! Set the global counts to zero. + ten_fin_counts = 0 + tee_fin_counts = 0 + tne_fin_counts = 0 + tnn_fin_counts = 0 + tae_fin_counts = 0 + tan_fin_counts = 0 + tge_scalar_fin_counts = 0 + tge_array_fin_counts = 0 + tgn_scalar_fin_counts = 0 + tgn_array_fin_counts = 0 + + allocate(ten :: x_ten(5,5)) + allocate(tee :: x_tee(5,5)) + allocate(tne :: x_tne(5,5)) + allocate(tnn :: x_tnn(5,5)) + allocate(tae :: x_tae(5,5)) + allocate(tan :: x_tan(5,5)) + allocate(tge :: x_tge(5,5)) + allocate(tgn :: x_tgn(5,5)) + + x_ten%i = 1 + x_tee%i = 2 + x_tne%i = 3 + x_tnn%i = 4 + x_tae%i = 5 + x_tan%i = 6 + x_tge%i = 7 + x_tgn%i = 8 + + call ten_init(x_ten(::2, ::3)) + + if (ten_fin_counts /= 6) call abort() + if (tee_fin_counts + tne_fin_counts + tnn_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + ten_fin_counts = 0 + + call tee_init(x_tee(::2, ::3)) + + if (tee_fin_counts /= 6) call abort() + if (ten_fin_counts + tne_fin_counts + tnn_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tee_fin_counts = 0 + + call tne_init(x_tne(::2, ::3)) + + if (tne_fin_counts /= 6) call abort() + if (ten_fin_counts + tee_fin_counts + tnn_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tne_fin_counts = 0 + + call tnn_init(x_tnn(::2, ::3)) + + if (tnn_fin_counts /= 0) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + + call tae_init(x_tae(::2, ::3)) + + if (tae_fin_counts /= 0) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + + call tan_init(x_tan(::2, ::3)) + + if (tan_fin_counts /= 1) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tae_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tan_fin_counts = 0 + + call tge_init(x_tge(::2, ::3)) + + if (tge_scalar_fin_counts /= 6) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tae_fin_counts + tan_fin_counts + tgn_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tge_scalar_fin_counts = 0 + + call tgn_init(x_tgn(::2, ::3)) + + if (tgn_array_fin_counts /= 1) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tae_fin_counts + tan_fin_counts + tge_scalar_fin_counts + & + tge_array_fin_counts + tgn_scalar_fin_counts /= 0) call abort() + tgn_array_fin_counts = 0 + + if (any (reshape (x_ten%i, [25]) /= [[40, 1, 40, 1, 40], [1, 1, 1, 1, 1],& + [1, 1, 1, 1, 1], [40, 1, 40, 1, 40], [1, 1, 1, 1, 1]])) call abort() + + if (any (reshape (x_tee%i, [25]) /= [[41, 2, 41, 2, 41], [2, 2, 2, 2, 2],& + [2, 2, 2, 2, 2], [41, 2, 41, 2, 41], [2, 2, 2, 2, 2]])) call abort() + + if (any (reshape (x_tne%i, [25]) /= [[42, 3, 42, 3, 42], [3, 3, 3, 3, 3],& + [3, 3, 3, 3, 3], [42, 3, 42, 3, 42], [3, 3, 3, 3, 3]])) call abort() + + if (any (reshape (x_tnn%i, [25]) /= [[43, 4, 43, 4, 43], [4, 4, 4, 4, 4],& + [4, 4, 4, 4, 4], [43, 4, 43, 4, 43], [4, 4, 4, 4, 4]])) call abort() + + if (any (reshape (x_tae%i, [25]) /= [[44, 5, 44, 5, 44], [5, 5, 5, 5, 5],& + [5, 5, 5, 5, 5], [44, 5, 44, 5, 44], [5, 5, 5, 5, 5]])) call abort() + + if (any (reshape (x_tan%i, [25]) /= [[45, 6, 45, 6, 45], [6, 6, 6, 6, 6],& + [6, 6, 6, 6, 6], [45, 6, 45, 6, 45], [6, 6, 6, 6, 6]])) call abort() + + if (any (reshape (x_tge%i, [25]) /= [[46, 7, 46, 7, 46], [7, 7, 7, 7, 7],& + [7, 7, 7, 7, 7], [46, 7, 46, 7, 46], [7, 7, 7, 7, 7]])) call abort() + + if (any (reshape (x_tgn%i, [25]) /= [[47, 8, 47, 8, 47], [8, 8, 8, 8, 8],& + [8, 8, 8, 8, 8], [47, 8, 47, 8, 47], [8, 8, 8, 8, 8]])) call abort() +end program finalize_29 ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Patch, Fortran, pr60322] was: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-03-24 17:06 ` [Patch, Fortran, pr60322] was: " Andre Vehreschild @ 2015-03-25 9:43 ` Dominique d'Humières 2015-03-25 16:57 ` Andre Vehreschild 2015-03-27 12:48 ` Paul Richard Thomas 1 sibling, 1 reply; 18+ messages in thread From: Dominique d'Humières @ 2015-03-25 9:43 UTC (permalink / raw) To: Andre Vehreschild Cc: Paul Richard Thomas, Mikael Morin, GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis Hi Andre, > Le 24 mars 2015 à 18:06, Andre Vehreschild <vehre@gmx.de> a écrit : > > Hi all, > > I have worked on the comments Mikael gave me. I am now checking for > class_pointer in the way he pointed out. > > Furthermore did I *join the two parts* of the patch into this one, because > keeping both in sync was no benefit but only tedious and did not prove to be > reviewed faster. Are you sure that you attached the right patch? It does not apply on a clean tree unless I apply the patch at https://gcc.gnu.org/ml/fortran/2015-02/msg00105.html with minor surgery for gcc/fortran/expr.c. > Paul, Dominique: I have addressed the LOC issue that came up lately. Or rather > the patch addressed it already. I feel like this is not tested very well, not > the loc() call nor the sizeof() call as given in the 57305 second's download. The ICE is fixed and the LOC issue seems fixed. > Unfortunately, is that download not runable. I would love to see a test similar > to that download, but couldn't come up with one, that satisfied me. Given that > the patch's review will last some days, I still have enough time to come up > with something beautiful which I will add then. I have changed the test to use iso_c_binding implicit none real, target :: e class(*), allocatable, target :: a(:) e = 1.0 call add_element_poly(a,e) print *, size(a) call add_element_poly(a,e) print *, size(a) select type (a) type is (real) print *, a end select contains subroutine add_element_poly(a,e) use iso_c_binding class(*),allocatable,intent(inout),target :: a(:) class(*),intent(in),target :: e class(*),allocatable,target :: tmp(:) type(c_ptr) :: dummy interface function memcpy(dest,src,n) bind(C,name="memcpy") result(res) import type(c_ptr) :: res integer(c_intptr_t),value :: dest integer(c_intptr_t),value :: src integer(c_size_t),value :: n end function end interface if (.not.allocated(a)) then allocate(a(1), source=e) else print *, size(a) allocate(tmp(size(a)),source=a) print *, size(a), size(tmp) + 1 print *, loc(a(1)),loc(tmp),sizeof(tmp) deallocate(a) ! allocate(a(size(tmp)+1),mold=e) allocate(a(size(tmp)+1),source=e) print *, size(a), size(tmp) dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) end if end subroutine end As pointed by Paul, I get a segfault at run time if I use the commented line, i.e. ‘mold’ instead of ‘source’. > Bootstraps and regtests ok on x86_64-linux-gnu/F20. > > Regards, > Andre Thanks for your work. Dominique ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Patch, Fortran, pr60322] was: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-03-25 9:43 ` Dominique d'Humières @ 2015-03-25 16:57 ` Andre Vehreschild 2015-03-26 9:27 ` Dominique d'Humières 0 siblings, 1 reply; 18+ messages in thread From: Andre Vehreschild @ 2015-03-25 16:57 UTC (permalink / raw) To: Dominique d'Humières Cc: Paul Richard Thomas, Mikael Morin, GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis [-- Attachment #1: Type: text/plain, Size: 3650 bytes --] Hi Dominique, hi all, you are absolutely right, Dominique: I missed the part of pr60322_base_*. But this time it is there and furthermore does solve the allocate( mold=e) and the loc(e) issue. Paul: I have simplified your patch by only checking whether the arg_expr.ts.type == BT_CLASS. All tests showed, that this enough to produce the correct code. Bootstraps and regtests ok on x86_64-linux-gnu/F20. Comments, please! Regards, Andre On Wed, 25 Mar 2015 10:43:34 +0100 Dominique d'Humières <dominiq@lps.ens.fr> wrote: > Hi Andre, > > > Le 24 mars 2015 à 18:06, Andre Vehreschild <vehre@gmx.de> a écrit : > > > > Hi all, > > > > I have worked on the comments Mikael gave me. I am now checking for > > class_pointer in the way he pointed out. > > > > Furthermore did I *join the two parts* of the patch into this one, because > > keeping both in sync was no benefit but only tedious and did not prove to be > > reviewed faster. > > Are you sure that you attached the right patch? It does not apply on a clean > tree unless I apply the patch at > > https://gcc.gnu.org/ml/fortran/2015-02/msg00105.html > > with minor surgery for gcc/fortran/expr.c. > > > Paul, Dominique: I have addressed the LOC issue that came up lately. Or > > rather the patch addressed it already. I feel like this is not tested very > > well, not the loc() call nor the sizeof() call as given in the 57305 > > second's download. > > The ICE is fixed and the LOC issue seems fixed. > > > Unfortunately, is that download not runable. I would love to see a test > > similar to that download, but couldn't come up with one, that satisfied me. > > Given that the patch's review will last some days, I still have enough time > > to come up with something beautiful which I will add then. > > I have changed the test to > > use iso_c_binding > implicit none > real, target :: e > class(*), allocatable, target :: a(:) > e = 1.0 > call add_element_poly(a,e) > print *, size(a) > call add_element_poly(a,e) > print *, size(a) > select type (a) > type is (real) > print *, a > end select > contains > subroutine add_element_poly(a,e) > use iso_c_binding > class(*),allocatable,intent(inout),target :: a(:) > class(*),intent(in),target :: e > class(*),allocatable,target :: tmp(:) > type(c_ptr) :: dummy > > interface > function memcpy(dest,src,n) bind(C,name="memcpy") result(res) > import > type(c_ptr) :: res > integer(c_intptr_t),value :: dest > integer(c_intptr_t),value :: src > integer(c_size_t),value :: n > end function > end interface > > if (.not.allocated(a)) then > allocate(a(1), source=e) > else > print *, size(a) > allocate(tmp(size(a)),source=a) > print *, size(a), size(tmp) + 1 > print *, loc(a(1)),loc(tmp),sizeof(tmp) > deallocate(a) > ! allocate(a(size(tmp)+1),mold=e) > allocate(a(size(tmp)+1),source=e) > print *, size(a), size(tmp) > dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) > dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) > end if > end subroutine > end > > As pointed by Paul, I get a segfault at run time if I use the commented line, > i.e. ‘mold’ instead of ‘source’. > > > Bootstraps and regtests ok on x86_64-linux-gnu/F20. > > > > Regards, > > Andre > > Thanks for your work. > > Dominique > -- Andre Vehreschild * Email: vehre ad gmx dot de [-- Attachment #2: pr60322_full_5.clog --] [-- Type: application/octet-stream, Size: 2669 bytes --] gcc/testsuite/ChangeLog: 2015-03-25 Andre Vehreschild <vehre@gmx.de> * gfortran.dg/class_allocate_19.f03: New test. * gfortran.dg/class_array_20.f03: New test. * gfortran.dg/finalize_10.f90: Corrected scan-trees. * gfortran.dg/finalize_15.f90: Fixing comparision to model initialization correctly. * gfortran.dg/finalize_29.f08: New test. gcc/fortran/ChangeLog: 2015-03-25 Andre Vehreschild <vehre@gmx.de> * expr.c (gfc_lval_expr_from_sym): Code to select the regular or class array added. * gfortran.h: Add IS_CLASS_ARRAY macro. * trans-array.c (gfc_add_loop_ss_code): Treat class objects to be referenced always. (build_class_array_ref): Adapt retrieval of array descriptor. (build_array_ref): Likewise. (gfc_trans_array_cobounds): Select correct gfc_array_spec for regular and class arrays. (gfc_trans_array_bounds): Likewise. (gfc_trans_dummy_array_bias): Likewise. (gfc_conv_expr_descriptor): Set the array's offset to -1 when lbound in inner most dim is 1 and symbol non-pointer/assoc. * trans-decl.c (gfc_build_qualified_array): Select correct gfc_array_spec for regular and class arrays. (gfc_build_dummy_array_decl): Likewise. (gfc_get_symbol_decl): Get a dummy array for class arrays. (gfc_trans_deferred_vars): Tell conv_expr that the descriptor is desired. * trans-expr.c (gfc_class_vptr_get): Get the class descriptor from the correct location for class arrays. (gfc_class_len_get): Likewise. (gfc_conv_intrinsic_to_class): Add handling of _len component. (gfc_conv_class_to_class): Prevent access to unset array data when the array is an optional argument. Add handling of _len component. (gfc_copy_class_to_class): Check that _def_init is non-NULL when used in _vptr->copy() (gfc_trans_class_init_assign): Ensure that the rank of _def_init is zero. (gfc_conv_variable): Make sure the temp array descriptor is returned for class arrays, too, and that class arrays are dereferenced correctly. (gfc_conv_procedure_call): For polymorphic type initialization the initializer has to be a pointer to _def_init stored in a dummy variable, which then needs to be used by value. * trans-intrinsic.c (gfc_conv_intrinsic_sizeof): Use the temporary array descriptor for class arrays, too. (gfc_conv_intrinsic_storage_size): Likewise. (gfc_conv_intrinsic_loc): Add ref to _data for BT_CLASS expressions. * trans-stmt.c (trans_associate_var): Use a temporary array for the associate variable of class arrays, too, making the array one-based (lbound == 1). * trans-types.c (gfc_is_nodesc_array): Use the correct array data. * trans.c (gfc_build_array_ref): Use the dummy array descriptor when present. [-- Attachment #3: pr60322_full_5.patch --] [-- Type: text/x-patch, Size: 57025 bytes --] diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c index ab6f7a5..7f3a59d 100644 --- a/gcc/fortran/expr.c +++ b/gcc/fortran/expr.c @@ -4052,6 +4052,7 @@ gfc_expr * gfc_lval_expr_from_sym (gfc_symbol *sym) { gfc_expr *lval; + gfc_array_spec *as; lval = gfc_get_expr (); lval->expr_type = EXPR_VARIABLE; lval->where = sym->declared_at; @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name); /* It will always be a full array. */ - lval->rank = sym->as ? sym->as->rank : 0; + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; + lval->rank = as ? as->rank : 0; if (lval->rank) - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? - CLASS_DATA (sym)->as : sym->as); + gfc_add_full_array_ref (lval, as); return lval; } diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 8e6595f..901a1c0 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -3206,6 +3206,11 @@ bool gfc_is_finalizable (gfc_symbol *, gfc_expr **); && CLASS_DATA (sym) \ && CLASS_DATA (sym)->ts.u.derived \ && CLASS_DATA (sym)->ts.u.derived->attr.unlimited_polymorphic) +#define IS_CLASS_ARRAY(sym) \ + (sym->ts.type == BT_CLASS \ + && CLASS_DATA (sym) \ + && CLASS_DATA (sym)->attr.dimension \ + && !CLASS_DATA (sym)->attr.class_pointer) /* frontend-passes.c */ diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 1768974..0804d45 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -2495,11 +2495,14 @@ gfc_add_loop_ss_code (gfc_loopinfo * loop, gfc_ss * ss, bool subscript, case GFC_SS_REFERENCE: /* Scalar argument to elemental procedure. */ gfc_init_se (&se, NULL); - if (ss_info->can_be_null_ref) + if (ss_info->can_be_null_ref || (expr->symtree + && (expr->symtree->n.sym->ts.type == BT_DERIVED + || expr->symtree->n.sym->ts.type == BT_CLASS))) { /* If the actual argument can be absent (in other words, it can be a NULL reference), don't try to evaluate it; pass instead - the reference directly. */ + the reference directly. The reference is also needed when + expr is of type class or derived. */ gfc_conv_expr_reference (&se, expr); } else @@ -3046,7 +3049,14 @@ build_class_array_ref (gfc_se *se, tree base, tree index) return false; } else if (class_ref == NULL) - decl = expr->symtree->n.sym->backend_decl; + { + decl = expr->symtree->n.sym->backend_decl; + /* For class arrays the tree containing the class is stored in + GFC_DECL_SAVED_DESCRIPTOR of the sym's backend_decl. + For all others it's sym's backend_decl directly. */ + if (DECL_LANG_SPECIFIC (decl) && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); + } else { /* Remove everything after the last class reference, convert the @@ -3159,26 +3169,41 @@ build_array_ref (tree desc, tree offset, tree decl) { tree tmp; tree type; + tree cdecl; + bool classarray = false; + + /* For class arrays the class declaration is stored in the saved + descriptor. */ + if (INDIRECT_REF_P (desc) + && DECL_LANG_SPECIFIC (TREE_OPERAND (desc, 0)) + && GFC_DECL_SAVED_DESCRIPTOR (TREE_OPERAND (desc, 0))) + cdecl = gfc_class_data_get (GFC_DECL_SAVED_DESCRIPTOR ( + TREE_OPERAND (desc, 0))); + else + cdecl = desc; /* Class container types do not always have the GFC_CLASS_TYPE_P but the canonical type does. */ - if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)) - && TREE_CODE (desc) == COMPONENT_REF) + if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (cdecl)) + && TREE_CODE (cdecl) == COMPONENT_REF) { - type = TREE_TYPE (TREE_OPERAND (desc, 0)); + type = TREE_TYPE (TREE_OPERAND (cdecl, 0)); if (TYPE_CANONICAL (type) && GFC_CLASS_TYPE_P (TYPE_CANONICAL (type))) - type = TYPE_CANONICAL (type); + { + type = TREE_TYPE (desc); + classarray = true; + } } else type = NULL; /* Class array references need special treatment because the assigned type size needs to be used to point to the element. */ - if (type && GFC_CLASS_TYPE_P (type)) + if (classarray) { - type = gfc_get_element_type (TREE_TYPE (desc)); - tmp = TREE_OPERAND (desc, 0); + type = gfc_get_element_type (type); + tmp = TREE_OPERAND (cdecl, 0); tmp = gfc_get_class_array_ref (offset, tmp); tmp = fold_convert (build_pointer_type (type), tmp); tmp = build_fold_indirect_ref_loc (input_location, tmp); @@ -5570,7 +5595,7 @@ gfc_trans_array_cobounds (tree type, stmtblock_t * pblock, gfc_se se; gfc_array_spec *as; - as = sym->as; + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; for (dim = as->rank; dim < as->rank + as->corank; dim++) { @@ -5613,7 +5638,7 @@ gfc_trans_array_bounds (tree type, gfc_symbol * sym, tree * poffset, int dim; - as = sym->as; + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; size = gfc_index_one_node; offset = gfc_index_zero_node; @@ -5900,12 +5925,17 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, int checkparm; int no_repack; bool optional_arg; + gfc_array_spec *as; + bool is_classarray = IS_CLASS_ARRAY (sym); /* Do nothing for pointer and allocatable arrays. */ - if (sym->attr.pointer || sym->attr.allocatable) + if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) + || sym->attr.allocatable + || (is_classarray && CLASS_DATA (sym)->attr.allocatable)) return; - if (sym->attr.dummy && gfc_is_nodesc_array (sym)) + if (!is_classarray && sym->attr.dummy && gfc_is_nodesc_array (sym)) { gfc_trans_g77_array (sym, block); return; @@ -5918,14 +5948,20 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, type = TREE_TYPE (tmpdesc); gcc_assert (GFC_ARRAY_TYPE_P (type)); dumdesc = GFC_DECL_SAVED_DESCRIPTOR (tmpdesc); - dumdesc = build_fold_indirect_ref_loc (input_location, dumdesc); + if (is_classarray) + /* For a class array the dummy array descriptor is in the _class + component. */ + dumdesc = gfc_class_data_get (dumdesc); + else + dumdesc = build_fold_indirect_ref_loc (input_location, dumdesc); + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; gfc_start_block (&init); if (sym->ts.type == BT_CHARACTER && TREE_CODE (sym->ts.u.cl->backend_decl) == VAR_DECL) gfc_conv_string_length (sym->ts.u.cl, NULL, &init); - checkparm = (sym->as->type == AS_EXPLICIT + checkparm = (as->type == AS_EXPLICIT && (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)); no_repack = !(GFC_DECL_PACKED_ARRAY (tmpdesc) @@ -6001,9 +6037,9 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, size = gfc_index_one_node; /* Evaluate the bounds of the array. */ - for (n = 0; n < sym->as->rank; n++) + for (n = 0; n < as->rank; n++) { - if (checkparm || !sym->as->upper[n]) + if (checkparm || !as->upper[n]) { /* Get the bounds of the actual parameter. */ dubound = gfc_conv_descriptor_ubound_get (dumdesc, gfc_rank_cst[n]); @@ -6019,7 +6055,7 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, if (!INTEGER_CST_P (lbound)) { gfc_init_se (&se, NULL); - gfc_conv_expr_type (&se, sym->as->lower[n], + gfc_conv_expr_type (&se, as->lower[n], gfc_array_index_type); gfc_add_block_to_block (&init, &se.pre); gfc_add_modify (&init, lbound, se.expr); @@ -6027,13 +6063,13 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, ubound = GFC_TYPE_ARRAY_UBOUND (type, n); /* Set the desired upper bound. */ - if (sym->as->upper[n]) + if (as->upper[n]) { /* We know what we want the upper bound to be. */ if (!INTEGER_CST_P (ubound)) { gfc_init_se (&se, NULL); - gfc_conv_expr_type (&se, sym->as->upper[n], + gfc_conv_expr_type (&se, as->upper[n], gfc_array_index_type); gfc_add_block_to_block (&init, &se.pre); gfc_add_modify (&init, ubound, se.expr); @@ -6086,7 +6122,7 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, gfc_array_index_type, offset, tmp); /* The size of this dimension, and the stride of the next. */ - if (n + 1 < sym->as->rank) + if (n + 1 < as->rank) { stride = GFC_TYPE_ARRAY_STRIDE (type, n + 1); @@ -6789,6 +6825,7 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) tree from; tree to; tree base; + bool onebased = false; ndim = info->ref ? info->ref->u.ar.dimen : ss->dimen; @@ -6930,6 +6967,7 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) gfc_array_index_type, to, tmp); from = gfc_index_one_node; } + onebased = integer_onep (from); gfc_conv_descriptor_lbound_set (&loop.pre, parm, gfc_rank_cst[dim], from); @@ -6986,13 +7024,27 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) gfc_get_dataptr_offset (&loop.pre, parm, desc, offset, subref_array_target, expr); - if (((se->direct_byref || GFC_ARRAY_TYPE_P (TREE_TYPE (desc))) - && !se->data_not_needed) - || (se->use_offset && base != NULL_TREE)) + /* Force the offset to be -1, when the lower bound of the highest + dimension is one and the symbol is present and is not a + pointer/allocatable or associated. */ + if (onebased && se->use_offset + && expr->symtree + && !expr->symtree->n.sym->attr.allocatable + && !expr->symtree->n.sym->attr.pointer + && !expr->symtree->n.sym->attr.host_assoc + && !expr->symtree->n.sym->attr.use_assoc) { - /* Set the offset. */ - gfc_conv_descriptor_offset_set (&loop.pre, parm, base); + /* Set the offset to -1. */ + mpz_t minus_one; + mpz_init_set_si (minus_one, -1); + tmp = gfc_conv_mpz_to_tree (minus_one, gfc_index_integer_kind); + gfc_conv_descriptor_offset_set (&loop.pre, parm, tmp); } + else if (((se->direct_byref || GFC_ARRAY_TYPE_P (TREE_TYPE (desc))) + && !se->data_not_needed) + || (se->use_offset && base != NULL_TREE)) + /* Set the offset depending on base. */ + gfc_conv_descriptor_offset_set (&loop.pre, parm, base); else { /* Only the callee knows what the correct offset it, so just set diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c index 769d487..895733b 100644 --- a/gcc/fortran/trans-decl.c +++ b/gcc/fortran/trans-decl.c @@ -812,8 +812,13 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) int dim; int nest; gfc_namespace* procns; + symbol_attribute *array_attr; + gfc_array_spec *as; + bool is_classarray = IS_CLASS_ARRAY (sym); type = TREE_TYPE (decl); + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; /* We just use the descriptor, if there is one. */ if (GFC_DESCRIPTOR_TYPE_P (type)) @@ -824,8 +829,8 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) nest = (procns->proc_name->backend_decl != current_function_decl) && !sym->attr.contained; - if (sym->attr.codimension && flag_coarray == GFC_FCOARRAY_LIB - && sym->as->type != AS_ASSUMED_SHAPE + if (array_attr->codimension && flag_coarray == GFC_FCOARRAY_LIB + && as->type != AS_ASSUMED_SHAPE && GFC_TYPE_ARRAY_CAF_TOKEN (type) == NULL_TREE) { tree token; @@ -878,8 +883,8 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) } /* Don't try to use the unknown bound for assumed shape arrays. */ if (GFC_TYPE_ARRAY_UBOUND (type, dim) == NULL_TREE - && (sym->as->type != AS_ASSUMED_SIZE - || dim < GFC_TYPE_ARRAY_RANK (type) - 1)) + && (as->type != AS_ASSUMED_SIZE + || dim < GFC_TYPE_ARRAY_RANK (type) - 1)) { GFC_TYPE_ARRAY_UBOUND (type, dim) = create_index_var ("ubound", nest); TREE_NO_WARNING (GFC_TYPE_ARRAY_UBOUND (type, dim)) = 1; @@ -920,7 +925,7 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) } if (GFC_TYPE_ARRAY_SIZE (type) == NULL_TREE - && sym->as->type != AS_ASSUMED_SIZE) + && as->type != AS_ASSUMED_SIZE) { GFC_TYPE_ARRAY_SIZE (type) = create_index_var ("size", nest); TREE_NO_WARNING (GFC_TYPE_ARRAY_SIZE (type)) = 1; @@ -947,12 +952,12 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) } if (TYPE_NAME (type) != NULL_TREE - && GFC_TYPE_ARRAY_UBOUND (type, sym->as->rank - 1) != NULL_TREE - && TREE_CODE (GFC_TYPE_ARRAY_UBOUND (type, sym->as->rank - 1)) == VAR_DECL) + && GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1) != NULL_TREE + && TREE_CODE (GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1)) == VAR_DECL) { tree gtype = DECL_ORIGINAL_TYPE (TYPE_NAME (type)); - for (dim = 0; dim < sym->as->rank - 1; dim++) + for (dim = 0; dim < as->rank - 1; dim++) { gcc_assert (TREE_CODE (gtype) == ARRAY_TYPE); gtype = TREE_TYPE (gtype); @@ -966,7 +971,7 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) { tree gtype = TREE_TYPE (type), rtype, type_decl; - for (dim = sym->as->rank - 1; dim >= 0; dim--) + for (dim = as->rank - 1; dim >= 0; dim--) { tree lbound, ubound; lbound = GFC_TYPE_ARRAY_LBOUND (type, dim); @@ -1014,41 +1019,56 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) tree decl; tree type; gfc_array_spec *as; + symbol_attribute *array_attr; char *name; gfc_packed packed; int n; bool known_size; - - if (sym->attr.pointer || sym->attr.allocatable - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) + bool is_classarray = IS_CLASS_ARRAY (sym); + + /* Use the array as and attr. */ + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + + /* The dummy is returned for pointer, allocatable or assumed rank arrays. + The check for pointerness needs to be repeated here (it is done in + IS_CLASS_ARRAY (), too), because for class arrays that are pointers, as + is the one of the sym, which is incorrect here. */ + if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) + || array_attr->allocatable + || (as && as->type == AS_ASSUMED_RANK)) return dummy; - /* Add to list of variables if not a fake result variable. */ + /* Add to list of variables if not a fake result variable. + These symbols are set on the symbol only, not on the class component. */ if (sym->attr.result || sym->attr.dummy) gfc_defer_symbol_init (sym); - type = TREE_TYPE (dummy); + /* For a class array the array descriptor is in the _data component, while + for a regular array the TREE_TYPE of the dummy is a pointer to the + descriptor. */ + type = TREE_TYPE (is_classarray ? gfc_class_data_get (dummy) + : TREE_TYPE (dummy)); + /* type now is the array descriptor w/o any indirection. */ gcc_assert (TREE_CODE (dummy) == PARM_DECL - && POINTER_TYPE_P (type)); + && POINTER_TYPE_P (TREE_TYPE (dummy))); /* Do we know the element size? */ known_size = sym->ts.type != BT_CHARACTER || INTEGER_CST_P (sym->ts.u.cl->backend_decl); - if (known_size && !GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (type))) + if (known_size && !GFC_DESCRIPTOR_TYPE_P (type)) { /* For descriptorless arrays with known element size the actual argument is sufficient. */ - gcc_assert (GFC_ARRAY_TYPE_P (type)); gfc_build_qualified_array (dummy, sym); return dummy; } - type = TREE_TYPE (type); if (GFC_DESCRIPTOR_TYPE_P (type)) { /* Create a descriptorless array pointer. */ - as = sym->as; packed = PACKED_NO; /* Even when -frepack-arrays is used, symbols with TARGET attribute @@ -1079,8 +1099,11 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) packed = PACKED_PARTIAL; } - type = gfc_typenode_for_spec (&sym->ts); - type = gfc_get_nodesc_array_type (type, sym->as, packed, + /* For classarrays the element type is required, but + gfc_typenode_for_spec () returns the array descriptor. */ + type = is_classarray ? gfc_get_element_type (type) + : gfc_typenode_for_spec (&sym->ts); + type = gfc_get_nodesc_array_type (type, as, packed, !sym->attr.target); } else @@ -1110,7 +1133,7 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) /* We should never get deferred shape arrays here. We used to because of frontend bugs. */ - gcc_assert (sym->as->type != AS_DEFERRED); + gcc_assert (as->type != AS_DEFERRED); if (packed == PACKED_PARTIAL) GFC_DECL_PARTIAL_PACKED_ARRAY (decl) = 1; @@ -1429,13 +1452,30 @@ gfc_get_symbol_decl (gfc_symbol * sym) sym->backend_decl = decl; } + /* Returning the descriptor for dummy class arrays is hazardous, because + some caller is expecting an expression to apply the component refs to. + Therefore the descriptor is only created and stored in + sym->backend_decl's GFC_DECL_SAVED_DESCRIPTOR. The caller is then + responsible to extract it from there, when the descriptor is + desired. */ + if (IS_CLASS_ARRAY (sym) + && (!DECL_LANG_SPECIFIC (sym->backend_decl) + || !GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl))) + { + decl = gfc_build_dummy_array_decl (sym, sym->backend_decl); + /* Prevent the dummy from being detected as unused if it is copied. */ + if (sym->backend_decl != NULL && decl != sym->backend_decl) + DECL_ARTIFICIAL (sym->backend_decl) = 1; + sym->backend_decl = decl; + } + TREE_USED (sym->backend_decl) = 1; if (sym->attr.assign && GFC_DECL_ASSIGN (sym->backend_decl) == 0) { gfc_add_assign_aux_vars (sym); } - if (sym->attr.dimension + if ((sym->attr.dimension || IS_CLASS_ARRAY (sym)) && DECL_LANG_SPECIFIC (sym->backend_decl) && GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl) && DECL_CONTEXT (sym->backend_decl) != current_function_decl) @@ -3976,18 +4016,31 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) = gfc_class_set_static_fields (sym->backend_decl, vptr, tmp); TREE_CONSTANT (DECL_INITIAL (sym->backend_decl)) = 1; } - else if (sym->attr.dimension || sym->attr.codimension) + else if (sym->attr.dimension || sym->attr.codimension + || (IS_CLASS_ARRAY (sym) && !CLASS_DATA (sym)->attr.allocatable)) { - /* Assumed-size Cray pointees need to be treated as AS_EXPLICIT. */ - array_type tmp = sym->as->type; - if (tmp == AS_ASSUMED_SIZE && sym->as->cp_was_assumed) - tmp = AS_EXPLICIT; - switch (tmp) + bool is_classarray = IS_CLASS_ARRAY (sym); + symbol_attribute *array_attr; + gfc_array_spec *as; + array_type tmp; + + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; + /* Assumed-size Cray pointees need to be treated as AS_EXPLICIT. */ + tmp = as->type; + if (tmp == AS_ASSUMED_SIZE && as->cp_was_assumed) + tmp = AS_EXPLICIT; + switch (tmp) { case AS_EXPLICIT: if (sym->attr.dummy || sym->attr.result) gfc_trans_dummy_array_bias (sym, sym->backend_decl, block); - else if (sym->attr.pointer || sym->attr.allocatable) + /* Allocatable and pointer arrays need to processed + explicitly. */ + else if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS + && CLASS_DATA (sym)->attr.class_pointer) + || array_attr->allocatable) { if (TREE_STATIC (sym->backend_decl)) { @@ -4002,7 +4055,8 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) gfc_trans_deferred_array (sym, block); } } - else if (sym->attr.codimension && TREE_STATIC (sym->backend_decl)) + else if (sym->attr.codimension + && TREE_STATIC (sym->backend_decl)) { gfc_init_block (&tmpblock); gfc_trans_array_cobounds (TREE_TYPE (sym->backend_decl), @@ -4041,7 +4095,7 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) case AS_ASSUMED_SIZE: /* Must be a dummy parameter. */ - gcc_assert (sym->attr.dummy || sym->as->cp_was_assumed); + gcc_assert (sym->attr.dummy || as->cp_was_assumed); /* We should always pass assumed size arrays the g77 way. */ if (sym->attr.dummy) @@ -4103,6 +4157,7 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) } else { + se.descriptor_only = 1; gfc_conv_expr (&se, e); descriptor = se.expr; se.expr = gfc_conv_descriptor_data_addr (se.expr); diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index 9bf976a..2da647f 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -149,6 +149,11 @@ tree gfc_class_vptr_get (tree decl) { tree vptr; + /* For class arrays decl may be a temporary descriptor handle, the vptr is + then available through the saved descriptor. */ + if (TREE_CODE (decl) == VAR_DECL && DECL_LANG_SPECIFIC (decl) + && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); if (POINTER_TYPE_P (TREE_TYPE (decl))) decl = build_fold_indirect_ref_loc (input_location, decl); vptr = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (decl)), @@ -163,6 +168,11 @@ tree gfc_class_len_get (tree decl) { tree len; + /* For class arrays decl may be a temporary descriptor handle, the len is + then available through the saved descriptor. */ + if (TREE_CODE (decl) == VAR_DECL && DECL_LANG_SPECIFIC (decl) + && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); if (POINTER_TYPE_P (TREE_TYPE (decl))) decl = build_fold_indirect_ref_loc (input_location, decl); len = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (decl)), @@ -766,6 +776,16 @@ gfc_conv_intrinsic_to_class (gfc_se *parmse, gfc_expr *e, } } } + else if (class_ts.type == BT_CLASS + && class_ts.u.derived->components + && class_ts.u.derived->components->ts.u + .derived->attr.unlimited_polymorphic) + { + ctree = gfc_class_len_get (var); + gfc_add_modify (&parmse->pre, ctree, + fold_convert (TREE_TYPE (ctree), + integer_zero_node)); + } /* Pass the address of the class object. */ parmse->expr = gfc_build_addr_expr (NULL_TREE, var); } @@ -792,6 +812,7 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts, tree tmp; tree vptr; tree cond = NULL_TREE; + tree slen = NULL_TREE; gfc_ref *ref; gfc_ref *class_ref; stmtblock_t block; @@ -883,7 +904,12 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts, tmp = NULL_TREE; if (class_ref == NULL && e->symtree && e->symtree->n.sym->ts.type == BT_CLASS) - tmp = e->symtree->n.sym->backend_decl; + { + tmp = e->symtree->n.sym->backend_decl; + if (DECL_LANG_SPECIFIC (tmp) && GFC_DECL_SAVED_DESCRIPTOR (tmp)) + tmp = GFC_DECL_SAVED_DESCRIPTOR (tmp); + slen = integer_zero_node; + } else { /* Remove everything after the last class reference, convert the @@ -895,6 +921,7 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts, gfc_conv_expr (&tmpse, e); class_ref->next = ref; tmp = tmpse.expr; + slen = tmpse.string_length; } gcc_assert (tmp != NULL_TREE); @@ -913,11 +940,38 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts, gfc_add_modify (&parmse->post, vptr, fold_convert (TREE_TYPE (vptr), ctree)); + /* For unlimited polymorphic objects also set the _len component. */ + if (class_ts.type == BT_CLASS + && class_ts.u.derived->components + && class_ts.u.derived->components->ts.u + .derived->attr.unlimited_polymorphic) + { + ctree = gfc_class_len_get (var); + if (UNLIMITED_POLY (e)) + tmp = gfc_class_len_get (tmp); + else if (e->ts.type == BT_CHARACTER) + { + gcc_assert (slen != NULL_TREE); + tmp = slen; + } + else + tmp = integer_zero_node; + gfc_add_modify (&parmse->pre, ctree, + fold_convert (TREE_TYPE (ctree), tmp)); + } + if (optional) { tree tmp2; cond = gfc_conv_expr_present (e->symtree->n.sym); + /* parmse->pre may contain some preparatory instructions for the + temporary array descriptor. Those may only be executed when the + optional argument is set, therefore add parmse->pre's instructions + to block, which is later guarded by an if (optional_arg_given). */ + gfc_add_block_to_block (&parmse->pre, &block); + block.head = parmse->pre.head; + parmse->pre.head = NULL_TREE; tmp = gfc_finish_block (&block); if (optional_alloc_ptr) @@ -1004,7 +1058,7 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems, bool unlimited) fcn_type = TREE_TYPE (TREE_TYPE (fcn)); if (from != NULL_TREE) - from_data = gfc_class_data_get (from); + from_data = gfc_class_data_get (from); else from_data = gfc_class_vtab_def_init_get (to); @@ -1061,7 +1115,8 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems, bool unlimited) gfc_init_block (&ifbody); gfc_add_block_to_block (&ifbody, &loop.pre); stdcopy = gfc_finish_block (&ifbody); - if (unlimited) + /* In initialization mode from_len is a constant zero. */ + if (unlimited && !integer_zerop (from_len)) { vec_safe_push (args, from_len); vec_safe_push (args, to_len); @@ -1103,7 +1158,8 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems, bool unlimited) vec_safe_push (args, to_data); stdcopy = build_call_vec (fcn_type, fcn, args); - if (unlimited) + /* In initialization mode from_len is a constant zero. */ + if (unlimited && !integer_zerop (from_len)) { vec_safe_push (args, from_len); vec_safe_push (args, to_len); @@ -1118,6 +1174,18 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems, bool unlimited) tmp = stdcopy; } + /* Only copy _def_init to to_data, when it is not a NULL-pointer. */ + if (from == NULL_TREE) + { + tree cond; + cond = fold_build2_loc (input_location, NE_EXPR, + boolean_type_node, + from_data, null_pointer_node); + tmp = fold_build3_loc (input_location, COND_EXPR, + void_type_node, cond, + tmp, build_empty_stmt (input_location)); + } + return tmp; } @@ -1191,6 +1259,8 @@ gfc_trans_class_init_assign (gfc_code *code) been referenced. */ gfc_get_derived_type (rhs->ts.u.derived); gfc_add_def_init_component (rhs); + /* The _def_init is always scalar. */ + rhs->rank = 0; if (code->expr1->ts.type == BT_CLASS && CLASS_DATA (code->expr1)->attr.dimension) @@ -2246,8 +2316,11 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) bool return_value; bool alternate_entry; bool entry_master; + bool is_classarray; + bool first_time = true; sym = expr->symtree->n.sym; + is_classarray = IS_CLASS_ARRAY (sym); ss = se->ss; if (ss != NULL) { @@ -2351,9 +2424,24 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) } else if (!sym->attr.value) { + /* Dereference temporaries for class array dummy arguments. */ + if (sym->attr.dummy && is_classarray + && GFC_ARRAY_TYPE_P (TREE_TYPE (se->expr))) + { + if (!se->descriptor_only) + se->expr = GFC_DECL_SAVED_DESCRIPTOR (se->expr); + + se->expr = build_fold_indirect_ref_loc (input_location, + se->expr); + } + /* Dereference non-character scalar dummy arguments. */ if (sym->attr.dummy && !sym->attr.dimension - && !(sym->attr.codimension && sym->attr.allocatable)) + && !(sym->attr.codimension && sym->attr.allocatable) + && (sym->ts.type != BT_CLASS + || (!CLASS_DATA (sym)->attr.dimension + && !(CLASS_DATA (sym)->attr.codimension + && CLASS_DATA (sym)->attr.allocatable)))) se->expr = build_fold_indirect_ref_loc (input_location, se->expr); @@ -2365,11 +2453,12 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) se->expr = build_fold_indirect_ref_loc (input_location, se->expr); - /* Dereference non-character pointer variables. + /* Dereference non-character, non-class pointer variables. These must be dummies, results, or scalars. */ - if ((sym->attr.pointer || sym->attr.allocatable - || gfc_is_associate_pointer (sym) - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) + if (!is_classarray + && (sym->attr.pointer || sym->attr.allocatable + || gfc_is_associate_pointer (sym) + || (sym->as && sym->as->type == AS_ASSUMED_RANK)) && (sym->attr.dummy || sym->attr.function || sym->attr.result @@ -2377,6 +2466,32 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) && (!sym->attr.codimension || !sym->attr.allocatable)))) se->expr = build_fold_indirect_ref_loc (input_location, se->expr); + /* Now treat the class array pointer variables accordingly. */ + else if (sym->ts.type == BT_CLASS + && sym->attr.dummy + && (CLASS_DATA (sym)->attr.dimension + || CLASS_DATA (sym)->attr.codimension) + && ((CLASS_DATA (sym)->as + && CLASS_DATA (sym)->as->type == AS_ASSUMED_RANK) + || CLASS_DATA (sym)->attr.allocatable + || CLASS_DATA (sym)->attr.class_pointer)) + se->expr = build_fold_indirect_ref_loc (input_location, + se->expr); + /* And the case where a non-dummy, non-result, non-function, + non-allotable and non-pointer classarray is present. This case was + previously covered by the first if, but with introducing the + condition !is_classarray there, that case has to be covered + explicitly. */ + else if (sym->ts.type == BT_CLASS + && !sym->attr.dummy + && !sym->attr.function + && !sym->attr.result + && (CLASS_DATA (sym)->attr.dimension + || CLASS_DATA (sym)->attr.codimension) + && !CLASS_DATA (sym)->attr.allocatable + && !CLASS_DATA (sym)->attr.class_pointer) + se->expr = build_fold_indirect_ref_loc (input_location, + se->expr); } ref = expr->ref; @@ -2414,6 +2529,18 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) break; case REF_COMPONENT: + if (first_time && is_classarray && sym->attr.dummy + && se->descriptor_only + && !CLASS_DATA (sym)->attr.allocatable + && !CLASS_DATA (sym)->attr.class_pointer + && CLASS_DATA (sym)->as + && CLASS_DATA (sym)->as->type != AS_ASSUMED_RANK + && strcmp ("_data", ref->u.c.component->name) == 0) + /* Skip the first ref of a _data component, because for class + arrays that one is already done by introducing a temporary + array descriptor. */ + break; + if (ref->u.c.sym->attr.extension) conv_parent_component_references (se, ref); @@ -2433,6 +2560,7 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) gcc_unreachable (); break; } + first_time = false; ref = ref->next; } /* Pointer assignment, allocation or pass by reference. Arrays are handled @@ -4559,7 +4687,19 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, gfc_init_se (&parmse, se); parm_kind = ELEMENTAL; - if (fsym && fsym->attr.value) + /* For all value functions or polymorphic scalar non-pointer + non-allocatable variables use the expression in e directly. This + ensures, that initializers of polymorphic entities are correctly + copied. */ + if (fsym && (fsym->attr.value + || (e->expr_type == EXPR_VARIABLE + && fsym->ts.type == BT_DERIVED + && e->ts.type == BT_DERIVED + && !e->ts.u.derived->attr.dimension + && !e->rank + && (!e->symtree + || (!e->symtree->n.sym->attr.allocatable + && !e->symtree->n.sym->attr.pointer))))) gfc_conv_expr (&parmse, e); else gfc_conv_expr_reference (&parmse, e); diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index c4ccb7b..20e5b37 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -5921,8 +5921,17 @@ gfc_conv_intrinsic_sizeof (gfc_se *se, gfc_expr *expr) } else if (arg->ts.type == BT_CLASS) { - if (arg->rank) + /* For deferred length arrays, conv_expr_descriptor returns an + indirect_ref to the component. */ + if (arg->rank < 0 + || (arg->rank > 0 && !VAR_P (argse.expr) + && GFC_DECL_CLASS (TREE_OPERAND (argse.expr, 0)))) byte_size = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0)); + else if (arg->rank > 0) + /* The scalarizer added an additional temp. To get the class' vptr + one has to look at the original backend_decl. */ + byte_size = gfc_class_vtab_size_get ( + GFC_DECL_SAVED_DESCRIPTOR (arg->symtree->n.sym->backend_decl)); else byte_size = gfc_class_vtab_size_get (argse.expr); } @@ -6053,7 +6062,11 @@ gfc_conv_intrinsic_storage_size (gfc_se *se, gfc_expr *expr) gfc_conv_expr_descriptor (&argse, arg); if (arg->ts.type == BT_CLASS) { - tmp = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0)); + if (arg->rank > 0) + tmp = gfc_class_vtab_size_get ( + GFC_DECL_SAVED_DESCRIPTOR (arg->symtree->n.sym->backend_decl)); + else + tmp = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0)); tmp = fold_convert (result_type, tmp); goto done; } @@ -7080,7 +7093,11 @@ gfc_conv_intrinsic_loc (gfc_se * se, gfc_expr * expr) arg_expr = expr->value.function.actual->expr; if (arg_expr->rank == 0) - gfc_conv_expr_reference (se, arg_expr); + { + if (arg_expr->ts.type == BT_CLASS) + gfc_add_component_ref (arg_expr, "_data"); + gfc_conv_expr_reference (se, arg_expr); + } else gfc_conv_array_parameter (se, arg_expr, true, NULL, NULL, NULL); se->expr = convert (gfc_get_int_type (gfc_index_integer_kind), se->expr); diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c index a6fb52c..6ffae6e79e 100644 --- a/gcc/fortran/trans-stmt.c +++ b/gcc/fortran/trans-stmt.c @@ -1260,12 +1260,29 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) gfc_init_se (&se, NULL); se.descriptor_only = 1; - gfc_conv_expr (&se, e); + /* In a select type the (temporary) associate variable shall point to + a standart fortran array (lower bound == 1), but conv_expr () + just maps to the input array in the class object, whose lbound may + be arbitrary. conv_expr_descriptor solves this by inserting a + temporary array descriptor. */ + gfc_conv_expr_descriptor (&se, e); - gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se.expr))); + gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se.expr)) + || GFC_ARRAY_TYPE_P (TREE_TYPE (se.expr))); gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (sym->backend_decl))); - gfc_add_modify (&se.pre, sym->backend_decl, se.expr); + if (GFC_ARRAY_TYPE_P (TREE_TYPE (se.expr))) + { + if (INDIRECT_REF_P (se.expr)) + tmp = TREE_OPERAND (se.expr, 0); + else + tmp = se.expr; + + gfc_add_modify (&se.pre, sym->backend_decl, + gfc_class_data_get (GFC_DECL_SAVED_DESCRIPTOR (tmp))); + } + else + gfc_add_modify (&se.pre, sym->backend_decl, se.expr); if (unlimited) { @@ -1276,7 +1293,7 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) gfc_get_dtype (TREE_TYPE (sym->backend_decl))); } - gfc_add_init_cleanup (block, gfc_finish_block( &se.pre), + gfc_add_init_cleanup (block, gfc_finish_block (&se.pre), gfc_finish_block (&se.post)); } @@ -1319,9 +1336,18 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) } if (need_len_assign) { - /* Get the _len comp from the target expr by stripping _data - from it and adding component-ref to _len. */ - tmp = gfc_class_len_get (TREE_OPERAND (target_expr, 0)); + if (e->symtree + && DECL_LANG_SPECIFIC (e->symtree->n.sym->backend_decl) + && GFC_DECL_SAVED_DESCRIPTOR (e->symtree->n.sym->backend_decl)) + /* Use the original class descriptor stored in the saved + descriptor to get the target_expr. */ + target_expr = + GFC_DECL_SAVED_DESCRIPTOR (e->symtree->n.sym->backend_decl); + else + /* Strip the _data component from the target_expr. */ + target_expr = TREE_OPERAND (target_expr, 0); + /* Add a reference to the _len comp to the target expr. */ + tmp = gfc_class_len_get (target_expr); /* Get the component-ref for the temp structure's _len comp. */ charlen = gfc_class_len_get (se.expr); /* Add the assign to the beginning of the the block... */ diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c index 708289f..b9f662d 100644 --- a/gcc/fortran/trans-types.c +++ b/gcc/fortran/trans-types.c @@ -1288,25 +1288,35 @@ gfc_get_element_type (tree type) int gfc_is_nodesc_array (gfc_symbol * sym) { - gcc_assert (sym->attr.dimension || sym->attr.codimension); + symbol_attribute *array_attr; + gfc_array_spec *as; + bool is_classarray = IS_CLASS_ARRAY (sym); + + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; + + gcc_assert (array_attr->dimension || array_attr->codimension); /* We only want local arrays. */ - if (sym->attr.pointer || sym->attr.allocatable) + if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) + || array_attr->allocatable) return 0; /* We want a descriptor for associate-name arrays that do not have an - explicitly known shape already. */ - if (sym->assoc && sym->as->type != AS_EXPLICIT) + explicitly known shape already. */ + if (sym->assoc && as->type != AS_EXPLICIT) return 0; + /* The dummy is stored in sym and not in the component. */ if (sym->attr.dummy) - return sym->as->type != AS_ASSUMED_SHAPE - && sym->as->type != AS_ASSUMED_RANK; + return as->type != AS_ASSUMED_SHAPE + && as->type != AS_ASSUMED_RANK; if (sym->attr.result || sym->attr.function) return 0; - gcc_assert (sym->as->type == AS_EXPLICIT || sym->as->cp_was_assumed); + gcc_assert (as->type == AS_EXPLICIT || as->cp_was_assumed); return 1; } diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c index b7ec0e5..394745e 100644 --- a/gcc/fortran/trans.c +++ b/gcc/fortran/trans.c @@ -362,16 +362,23 @@ gfc_build_array_ref (tree base, tree offset, tree decl) { if (GFC_DECL_CLASS (decl)) { - /* Allow for dummy arguments and other good things. */ - if (POINTER_TYPE_P (TREE_TYPE (decl))) - decl = build_fold_indirect_ref_loc (input_location, decl); - - /* Check if '_data' is an array descriptor. If it is not, - the array must be one of the components of the class object, - so return a normal array reference. */ - if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (gfc_class_data_get (decl)))) - return build4_loc (input_location, ARRAY_REF, type, base, - offset, NULL_TREE, NULL_TREE); + /* When a temporary is in place for the class array, then the original + class' declaration is stored in the saved descriptor. */ + if (DECL_LANG_SPECIFIC (decl) && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); + else + { + /* Allow for dummy arguments and other good things. */ + if (POINTER_TYPE_P (TREE_TYPE (decl))) + decl = build_fold_indirect_ref_loc (input_location, decl); + + /* Check if '_data' is an array descriptor. If it is not, + the array must be one of the components of the class object, + so return a normal array reference. */ + if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (gfc_class_data_get (decl)))) + return build4_loc (input_location, ARRAY_REF, type, base, + offset, NULL_TREE, NULL_TREE); + } span = gfc_class_vtab_size_get (decl); } diff --git a/gcc/testsuite/gfortran.dg/class_allocate_19.f03 b/gcc/testsuite/gfortran.dg/class_allocate_19.f03 new file mode 100644 index 0000000..719be3e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/class_allocate_19.f03 @@ -0,0 +1,47 @@ +! { dg-do run } +! +! Contributed by: Vladimir Fuka <vladimir.fuka@gmail.com> + +use iso_c_binding +implicit none +real, target :: e +class(*), allocatable, target :: a(:) +e = 1.0 +call add_element_poly(a,e) +if (size(a) /= 1) call abort() +call add_element_poly(a,e) +if (size(a) /= 2) call abort() +select type (a) + type is (real) + if (any (a /= [ 1, 1])) call abort() +end select +contains + subroutine add_element_poly(a,e) + use iso_c_binding + class(*),allocatable,intent(inout),target :: a(:) + class(*),intent(in),target :: e + class(*),allocatable,target :: tmp(:) + type(c_ptr) :: dummy + + interface + function memcpy(dest,src,n) bind(C,name="memcpy") result(res) + import + type(c_ptr) :: res + integer(c_intptr_t),value :: dest + integer(c_intptr_t),value :: src + integer(c_size_t),value :: n + end function + end interface + + if (.not.allocated(a)) then + allocate(a(1), source=e) + else + allocate(tmp(size(a)),source=a) + deallocate(a) + allocate(a(size(tmp)+1),mold=e) + dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) + dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) + end if + end subroutine +end + diff --git a/gcc/testsuite/gfortran.dg/class_array_20.f03 b/gcc/testsuite/gfortran.dg/class_array_20.f03 new file mode 100644 index 0000000..c49f7d2 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/class_array_20.f03 @@ -0,0 +1,100 @@ +! {dg-do run} +! +! Test contributed by Thomas L. Clune via pr60322 +! and Antony Lewis via pr64692 + +program class_array_20 + implicit none + + type Foo + end type + + type(foo), dimension(2:3) :: arg + integer :: oneDarr(2) + integer :: twoDarr(2,3) + integer :: x, y + double precision :: P(2, 2) + + ! Checking for PR/60322 + call copyFromClassArray([Foo(), Foo()]) + call copyFromClassArray(arg) + call copyFromClassArray(arg(:)) + + x= 3 + y= 4 + oneDarr = [x, y] + call W([x, y]) + call W(oneDarr) + call W([3, 4]) + + twoDarr = reshape([3, 4, 5, 5, 6, 7], [2, 3]) + call WtwoD(twoDarr) + call WtwoD(reshape([3, 4, 5, 5, 6, 7], [2, 3])) + + ! Checking for PR/64692 + P(1:2, 1) = [1.d0, 2.d0] + P(1:2, 2) = [3.d0, 4.d0] + call AddArray(P(1:2, 2)) + +contains + + subroutine copyFromClassArray(classarray) + class (Foo), intent(in) :: classarray(:) + + if (lbound(classarray, 1) .ne. 1) call abort() + if (ubound(classarray, 1) .ne. 2) call abort() + if (size(classarray) .ne. 2) call abort() + end subroutine + + subroutine AddArray(P) + class(*), target, intent(in) :: P(:) + class(*), pointer :: Pt(:) + + allocate(Pt(1:size(P)), source= P) + + select type (P) + type is (double precision) + if (abs(P(1)-3.d0) .gt. 1.d-8) call abort() + if (abs(P(2)-4.d0) .gt. 1.d-8) call abort() + class default + call abort() + end select + + select type (Pt) + type is (double precision) + if (abs(Pt(1)-3.d0) .gt. 1.d-8) call abort() + if (abs(Pt(2)-4.d0) .gt. 1.d-8) call abort() + class default + call abort() + end select + end subroutine + + subroutine W(ar) + class(*), intent(in) :: ar(:) + + if (lbound(ar, 1) /= 1) call abort() + select type (ar) + type is (integer) + ! The indeces 1:2 are essential here, or else one would not + ! note, that the array internally starts at 0, although the + ! check for the lbound above went fine. + if (any (ar(1:2) .ne. [3, 4])) call abort() + class default + call abort() + end select + end subroutine + + subroutine WtwoD(ar) + class(*), intent(in) :: ar(:,:) + + if (any (lbound(ar) /= [1, 1])) call abort() + select type (ar) + type is (integer) + if (any (reshape(ar(1:2,1:3), [6]) .ne. [3, 4, 5, 5, 6, 7])) & + call abort() + class default + call abort() + end select + end subroutine +end program class_array_20 + diff --git a/gcc/testsuite/gfortran.dg/finalize_10.f90 b/gcc/testsuite/gfortran.dg/finalize_10.f90 index e042f11..32386ce 100644 --- a/gcc/testsuite/gfortran.dg/finalize_10.f90 +++ b/gcc/testsuite/gfortran.dg/finalize_10.f90 @@ -27,8 +27,8 @@ end subroutine foo ! Finalize CLASS + set default init ! { dg-final { scan-tree-dump-times "y->_vptr->_final \\(&desc.\[0-9\]+, y->_vptr->_size, 0\\);" 1 "original" } } ! { dg-final { scan-tree-dump "__builtin_memcpy \\(\\(void .\\) y->_data, \\(void .\\) y->_vptr->_def_init, \\((unsigned long|unsigned int|character\\(kind=4\\))\\) y->_vptr->_size\\);" "original" } } -! { dg-final { scan-tree-dump-times "x->_vptr->_final \\(&x->_data, x->_vptr->_size, 0\\);" 1 "original" } } -! { dg-final { scan-tree-dump-times "x->_vptr->_copy \\(x->_vptr->_def_init, &x->_data\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times "x->_vptr->_final \\(&parm.\[0-9\]+, x->_vptr->_size, 0\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times "x->_vptr->_copy \\(" 1 "original" } } ! FINALIZE TYPE: ! { dg-final { scan-tree-dump-times "parm.\[0-9\]+.data = \\(void \\*\\) &\\(\\*aa.\[0-9\]+\\)\\\[0\\\];" 1 "original" } } diff --git a/gcc/testsuite/gfortran.dg/finalize_15.f90 b/gcc/testsuite/gfortran.dg/finalize_15.f90 index 3c18b2a..d5ba28f 100644 --- a/gcc/testsuite/gfortran.dg/finalize_15.f90 +++ b/gcc/testsuite/gfortran.dg/finalize_15.f90 @@ -9,37 +9,37 @@ module m implicit none type t1 - integer :: i + integer :: i = 1 contains final :: fini_elem end type t1 type, extends(t1) :: t1e - integer :: j + integer :: j = 11 contains final :: fini_elem2 end type t1e type t2 - integer :: i + integer :: i = 2 contains final :: fini_shape end type t2 type, extends(t2) :: t2e - integer :: j + integer :: j = 22 contains final :: fini_shape2 end type t2e type t3 - integer :: i + integer :: i = 3 contains final :: fini_explicit end type t3 type, extends(t3) :: t3e - integer :: j + integer :: j = 33 contains final :: fini_explicit2 end type t3e @@ -204,31 +204,31 @@ program test select type(x) type is (t1e) - call check_val(x%i, 1) - call check_val(x%j, 100) + call check_val(x%i, 1, 1) + call check_val(x%j, 100, 11) end select select type(y) type is (t2e) - call check_val(y%i, 1) - call check_val(y%j, 100) + call check_val(y%i, 1, 2) + call check_val(y%j, 100, 22) end select select type(z) type is (t3e) - call check_val(z%i, 1) - call check_val(z%j, 100) + call check_val(z%i, 1, 3) + call check_val(z%j, 100, 33) end select contains - subroutine check_val(x, factor) + subroutine check_val(x, factor, val) integer :: x(:,:) - integer, value :: factor + integer, value :: factor, val integer :: i, j do i = 1, 10 do j = 1, 10 if (mod (j-1, 2) == 0 .and. mod (i-1, 3) == 0) then - if (x(j,i) /= (j + 100*i)*factor*(-13)) call abort () + if (x(j,i) /= val) call abort () else if (x(j,i) /= (j + 100*i)*factor) call abort () end if diff --git a/gcc/testsuite/gfortran.dg/finalize_29.f08 b/gcc/testsuite/gfortran.dg/finalize_29.f08 new file mode 100644 index 0000000..1f5f7424 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/finalize_29.f08 @@ -0,0 +1,289 @@ +! {dg-do run} +! +! Testcase contributed by Andre Vehreschild <vehre@gcc.gnu.org> + +module module_finalize_29 + implicit none + + ! The type name is encoding the state of its finalizer being + ! elemental (second letter 'e'), or non-element (second letter 'n') + ! or array shaped (second letter 'a'), or shape-specific routine + ! (generic; second letter 'g'), + ! and whether the init-routine is elemental or not (third letter + ! either 'e' or 'n'). + type ten + integer :: i = 40 + contains + final :: ten_fin + end type ten + + type tee + integer :: i = 41 + contains + final :: tee_fin + end type tee + + type tne + integer :: i = 42 + contains + final :: tne_fin + end type tne + + type tnn + integer :: i = 43 + contains + final :: tnn_fin + end type tnn + + type tae + integer :: i = 44 + contains + final :: tae_fin + end type tae + + type tan + integer :: i = 45 + contains + final :: tan_fin + end type tan + + type tge + integer :: i = 46 + contains + final :: tge_scalar_fin, tge_array_fin + end type tge + + type tgn + integer :: i = 47 + contains + final :: tgn_scalar_fin, tgn_array_fin + end type tgn + + integer :: ten_fin_counts, tee_fin_counts, tne_fin_counts, tnn_fin_counts + integer :: tae_fin_counts, tan_fin_counts + integer :: tge_scalar_fin_counts, tge_array_fin_counts + integer :: tgn_scalar_fin_counts, tgn_array_fin_counts +contains + impure elemental subroutine ten_fin(x) + type(ten), intent(inout) :: x + x%i = -10 * x%i + ten_fin_counts = ten_fin_counts + 1 + end subroutine ten_fin + + impure elemental subroutine tee_fin(x) + type(tee), intent(inout) :: x + x%i = -11 * x%i + tee_fin_counts = tee_fin_counts + 1 + end subroutine tee_fin + + subroutine tne_fin(x) + type(tne), intent(inout) :: x + x%i = -12 * x%i + tne_fin_counts = tne_fin_counts + 1 + end subroutine tne_fin + + subroutine tnn_fin(x) + type(tnn), intent(inout) :: x + x%i = -13 * x%i + tnn_fin_counts = tnn_fin_counts + 1 + end subroutine tnn_fin + + subroutine tae_fin(x) + type(tae), intent(inout) :: x(:,:) + x%i = -14 * x%i + tae_fin_counts = tae_fin_counts + 1 + end subroutine tae_fin + + subroutine tan_fin(x) + type(tan), intent(inout) :: x(:,:) + x%i = -15 * x%i + tan_fin_counts = tan_fin_counts + 1 + end subroutine tan_fin + + subroutine tge_scalar_fin(x) + type(tge), intent(inout) :: x + x%i = -16 * x%i + tge_scalar_fin_counts = tge_scalar_fin_counts + 1 + end subroutine tge_scalar_fin + + subroutine tge_array_fin(x) + type(tge), intent(inout) :: x(:,:) + x%i = -17 * x%i + tge_array_fin_counts = tge_array_fin_counts + 1 + end subroutine tge_array_fin + + subroutine tgn_scalar_fin(x) + type(tgn), intent(inout) :: x + x%i = -18 * x%i + tgn_scalar_fin_counts = tgn_scalar_fin_counts + 1 + end subroutine tgn_scalar_fin + + subroutine tgn_array_fin(x) + type(tgn), intent(inout) :: x(:,:) + x%i = -19 * x%i + tgn_array_fin_counts = tgn_array_fin_counts + 1 + end subroutine tgn_array_fin + + ! The finalizer/initializer call producer + subroutine ten_init(x) + class(ten), intent(out) :: x(:,:) + end subroutine ten_init + + impure elemental subroutine tee_init(x) + class(tee), intent(out) :: x + end subroutine tee_init + + impure elemental subroutine tne_init(x) + class(tne), intent(out) :: x + end subroutine tne_init + + subroutine tnn_init(x) + class(tnn), intent(out) :: x(:,:) + end subroutine tnn_init + + impure elemental subroutine tae_init(x) + class(tae), intent(out) :: x + end subroutine tae_init + + subroutine tan_init(x) + class(tan), intent(out) :: x(:,:) + end subroutine tan_init + + impure elemental subroutine tge_init(x) + class(tge), intent(out) :: x + end subroutine tge_init + + subroutine tgn_init(x) + class(tgn), intent(out) :: x(:,:) + end subroutine tgn_init +end module module_finalize_29 + +program finalize_29 + use module_finalize_29 + implicit none + + type(ten), allocatable :: x_ten(:,:) + type(tee), allocatable :: x_tee(:,:) + type(tne), allocatable :: x_tne(:,:) + type(tnn), allocatable :: x_tnn(:,:) + type(tae), allocatable :: x_tae(:,:) + type(tan), allocatable :: x_tan(:,:) + type(tge), allocatable :: x_tge(:,:) + type(tgn), allocatable :: x_tgn(:,:) + + ! Set the global counts to zero. + ten_fin_counts = 0 + tee_fin_counts = 0 + tne_fin_counts = 0 + tnn_fin_counts = 0 + tae_fin_counts = 0 + tan_fin_counts = 0 + tge_scalar_fin_counts = 0 + tge_array_fin_counts = 0 + tgn_scalar_fin_counts = 0 + tgn_array_fin_counts = 0 + + allocate(ten :: x_ten(5,5)) + allocate(tee :: x_tee(5,5)) + allocate(tne :: x_tne(5,5)) + allocate(tnn :: x_tnn(5,5)) + allocate(tae :: x_tae(5,5)) + allocate(tan :: x_tan(5,5)) + allocate(tge :: x_tge(5,5)) + allocate(tgn :: x_tgn(5,5)) + + x_ten%i = 1 + x_tee%i = 2 + x_tne%i = 3 + x_tnn%i = 4 + x_tae%i = 5 + x_tan%i = 6 + x_tge%i = 7 + x_tgn%i = 8 + + call ten_init(x_ten(::2, ::3)) + + if (ten_fin_counts /= 6) call abort() + if (tee_fin_counts + tne_fin_counts + tnn_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + ten_fin_counts = 0 + + call tee_init(x_tee(::2, ::3)) + + if (tee_fin_counts /= 6) call abort() + if (ten_fin_counts + tne_fin_counts + tnn_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tee_fin_counts = 0 + + call tne_init(x_tne(::2, ::3)) + + if (tne_fin_counts /= 6) call abort() + if (ten_fin_counts + tee_fin_counts + tnn_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tne_fin_counts = 0 + + call tnn_init(x_tnn(::2, ::3)) + + if (tnn_fin_counts /= 0) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + + call tae_init(x_tae(::2, ::3)) + + if (tae_fin_counts /= 0) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + + call tan_init(x_tan(::2, ::3)) + + if (tan_fin_counts /= 1) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tae_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tan_fin_counts = 0 + + call tge_init(x_tge(::2, ::3)) + + if (tge_scalar_fin_counts /= 6) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tae_fin_counts + tan_fin_counts + tgn_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tge_scalar_fin_counts = 0 + + call tgn_init(x_tgn(::2, ::3)) + + if (tgn_array_fin_counts /= 1) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tae_fin_counts + tan_fin_counts + tge_scalar_fin_counts + & + tge_array_fin_counts + tgn_scalar_fin_counts /= 0) call abort() + tgn_array_fin_counts = 0 + + if (any (reshape (x_ten%i, [25]) /= [[40, 1, 40, 1, 40], [1, 1, 1, 1, 1],& + [1, 1, 1, 1, 1], [40, 1, 40, 1, 40], [1, 1, 1, 1, 1]])) call abort() + + if (any (reshape (x_tee%i, [25]) /= [[41, 2, 41, 2, 41], [2, 2, 2, 2, 2],& + [2, 2, 2, 2, 2], [41, 2, 41, 2, 41], [2, 2, 2, 2, 2]])) call abort() + + if (any (reshape (x_tne%i, [25]) /= [[42, 3, 42, 3, 42], [3, 3, 3, 3, 3],& + [3, 3, 3, 3, 3], [42, 3, 42, 3, 42], [3, 3, 3, 3, 3]])) call abort() + + if (any (reshape (x_tnn%i, [25]) /= [[43, 4, 43, 4, 43], [4, 4, 4, 4, 4],& + [4, 4, 4, 4, 4], [43, 4, 43, 4, 43], [4, 4, 4, 4, 4]])) call abort() + + if (any (reshape (x_tae%i, [25]) /= [[44, 5, 44, 5, 44], [5, 5, 5, 5, 5],& + [5, 5, 5, 5, 5], [44, 5, 44, 5, 44], [5, 5, 5, 5, 5]])) call abort() + + if (any (reshape (x_tan%i, [25]) /= [[45, 6, 45, 6, 45], [6, 6, 6, 6, 6],& + [6, 6, 6, 6, 6], [45, 6, 45, 6, 45], [6, 6, 6, 6, 6]])) call abort() + + if (any (reshape (x_tge%i, [25]) /= [[46, 7, 46, 7, 46], [7, 7, 7, 7, 7],& + [7, 7, 7, 7, 7], [46, 7, 46, 7, 46], [7, 7, 7, 7, 7]])) call abort() + + if (any (reshape (x_tgn%i, [25]) /= [[47, 8, 47, 8, 47], [8, 8, 8, 8, 8],& + [8, 8, 8, 8, 8], [47, 8, 47, 8, 47], [8, 8, 8, 8, 8]])) call abort() +end program finalize_29 ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Patch, Fortran, pr60322] was: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-03-25 16:57 ` Andre Vehreschild @ 2015-03-26 9:27 ` Dominique d'Humières 0 siblings, 0 replies; 18+ messages in thread From: Dominique d'Humières @ 2015-03-26 9:27 UTC (permalink / raw) To: Andre Vehreschild Cc: Paul Richard Thomas, Mikael Morin, GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis Dear Andre, Everything works as expected with your new patch. I have changed the test for pr57305 to use iso_c_binding implicit none integer :: i real, target :: e class(*), allocatable, target :: a(:) do i = 1, 3 e = i call add_element_poly(a,e) select type (a) type is (real) print *, a end select end do contains subroutine add_element_poly(a,e) use iso_c_binding class(*),allocatable,intent(inout),target :: a(:) class(*),intent(in),target :: e class(*),allocatable,target :: tmp(:) type(c_ptr) :: dummy interface function memcpy(dest,src,n) bind(C,name="memcpy") result(res) import type(c_ptr) :: res integer(c_intptr_t),value :: dest integer(c_intptr_t),value :: src integer(c_size_t),value :: n end function end interface if (.not.allocated(a)) then allocate(a(1), source=e) else allocate(tmp(size(a)),source=a) deallocate(a) allocate(a(size(tmp)+1),mold=e) dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) end if end subroutine end and get the expected outputs at run time (it works also if I replace MOLD with SOURCE and remove the second ‘dummy = …’ line). Thanks for your patience, Dominique > Le 25 mars 2015 à 17:56, Andre Vehreschild <vehre@gmx.de> a écrit : > > Hi Dominique, hi all, > > you are absolutely right, Dominique: I missed the part of pr60322_base_*. > > But this time it is there and furthermore does solve the allocate( mold=e) and > the loc(e) issue. > > Paul: I have simplified your patch by only checking whether the > arg_expr.ts.type == BT_CLASS. All tests showed, that this enough to produce the > correct code. > > Bootstraps and regtests ok on x86_64-linux-gnu/F20. > > Comments, please! > > Regards, > Andre > > On Wed, 25 Mar 2015 10:43:34 +0100 > Dominique d'Humières <dominiq@lps.ens.fr> wrote: ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Patch, Fortran, pr60322] was: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-03-24 17:06 ` [Patch, Fortran, pr60322] was: " Andre Vehreschild 2015-03-25 9:43 ` Dominique d'Humières @ 2015-03-27 12:48 ` Paul Richard Thomas 2015-04-05 9:13 ` Paul Richard Thomas 1 sibling, 1 reply; 18+ messages in thread From: Paul Richard Thomas @ 2015-03-27 12:48 UTC (permalink / raw) To: Andre Vehreschild Cc: Mikael Morin, GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis, Dominique Dhumieres Dear Andre, I am in the UK as of last night. Before leaving, I bootstrapped and regtested your patch and all was well. I must drive to Cambridge this afternoon to see my mother and will try to get to it either this evening or tomorrow morning. There is so much of it and it touches many places; so I must give it a very careful looking over before giving the green light. Bear with me please. Great work though! Paul On 24 March 2015 at 18:06, Andre Vehreschild <vehre@gmx.de> wrote: > Hi all, > > I have worked on the comments Mikael gave me. I am now checking for > class_pointer in the way he pointed out. > > Furthermore did I *join the two parts* of the patch into this one, because > keeping both in sync was no benefit but only tedious and did not prove to be > reviewed faster. > > Paul, Dominique: I have addressed the LOC issue that came up lately. Or rather > the patch addressed it already. I feel like this is not tested very well, not > the loc() call nor the sizeof() call as given in the 57305 second's download. > Unfortunately, is that download not runable. I would love to see a test similar > to that download, but couldn't come up with one, that satisfied me. Given that > the patch's review will last some days, I still have enough time to come up > with something beautiful which I will add then. > > Bootstraps and regtests ok on x86_64-linux-gnu/F20. > > Regards, > Andre > > > On Tue, 24 Mar 2015 11:13:27 +0100 > Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: > >> Dear Andre, >> >> Dominique pointed out to me that the 'loc' patch causes a ICE in the >> testsuite. It seems that 'loc' should provide the address of the class >> container in some places and the address of the data in others. I will >> put my thinking cap on tonight :-) >> >> Cheers >> >> Paul >> >> On 23 March 2015 at 13:43, Andre Vehreschild <vehre@gmx.de> wrote: >> > Hi Mikael, >> > >> > thanks for looking at the patch. Please note, that Paul has sent an >> > addendum to the patches for 60322, which I deliberately have attached. >> > >> >> 26/02/2015 18:17, Andre Vehreschild a écrit : >> >> > This first patch is only preparatory and does not change any of the >> >> > semantics of gfortran at all. >> >> Sure? >> > >> > With the counterexample you found below, this of course is a wrong >> > statement. >> > >> >> > diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c >> >> > index ab6f7a5..d28cf77 100644 >> >> > --- a/gcc/fortran/expr.c >> >> > +++ b/gcc/fortran/expr.c >> >> > @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) >> >> > lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name); >> >> > >> >> > /* It will always be a full array. */ >> >> > - lval->rank = sym->as ? sym->as->rank : 0; >> >> > + as = sym->as; >> >> > + lval->rank = as ? as->rank : 0; >> >> > if (lval->rank) >> >> > - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? >> >> > - CLASS_DATA (sym)->as : sym->as); >> >> > + gfc_add_full_array_ref (lval, as); >> >> >> >> This is a change of semantics. Or do you know that sym->ts.type != >> >> BT_CLASS? >> > >> > You are completely right. I have made a mistake here. I have to tell the >> > truth, I never ran a regtest with only part 1 of the patches applied. The >> > second part of the patch will correct this, by setting the variable as >> > depending on whether type == BT_CLASS or not. Sorry for the mistake. >> > >> >> > diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c >> >> > index 3664824..e571a17 100644 >> >> > --- a/gcc/fortran/trans-decl.c >> >> > +++ b/gcc/fortran/trans-decl.c >> >> > @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, >> >> > tree dummy) tree decl; >> >> > tree type; >> >> > gfc_array_spec *as; >> >> > + symbol_attribute *array_attr; >> >> > char *name; >> >> > gfc_packed packed; >> >> > int n; >> >> > bool known_size; >> >> > >> >> > - if (sym->attr.pointer || sym->attr.allocatable >> >> > - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) >> >> > + /* Use the array as and attr. */ >> >> > + as = sym->as; >> >> > + array_attr = &sym->attr; >> >> > + >> >> > + /* The pointer attribute is always set on a _data component, therefore >> >> > check >> >> > + the sym's attribute only. */ >> >> > + if (sym->attr.pointer || array_attr->allocatable >> >> > + || (as && as->type == AS_ASSUMED_RANK)) >> >> > return dummy; >> >> > >> >> Any reason to sometimes use array_attr, sometimes not, like here? >> >> By the way, the comment is misleading: for classes, there is the >> >> class_pointer attribute (and it is a pain, I know). >> > >> > Yes, and a good one. Array_attr is sometimes sym->attr and sometimes >> > CLASS_DATA(sym)->attr aka sym->ts.u.derived->components->attr. In the later >> > case .pointer is always set to 1 in the _data component's attr. I.e., the >> > above if, would always yield true for a class_array, which is not intended, >> > but rather destructive. I know about the class_pointer attribute, but I >> > figured, that it is not relevant here. Any idea how to formulate the >> > comment better, to reflect what I just explained? >> > >> > Regards, >> > Andre >> > -- >> > Andre Vehreschild * Email: vehre ad gmx dot de >> > >> > >> > ---------- Forwarded message ---------- >> > From: Paul Richard Thomas <paul.richard.thomas@gmail.com> >> > To: Andre Vehreschild <vehre@gmx.de>, Dominique Dhumieres >> > <dominiq@lps.ens.fr> Cc: >> > Date: Sun, 22 Mar 2015 21:20:20 +0100 >> > Subject: Bug in intrinsic LOC for scalar class objects >> > Dear Andre and Dominique, >> > >> > I have found that LOC is returning the address of the class container >> > rather than the _data component for class scalars. See the source >> > below, which you will recognise! A fix is attached. >> > >> > Note that the scalar allocate fails with MOLD= and so I substituted SOURCE=. >> > >> > Cheers >> > >> > Paul >> > >> > class(*), allocatable :: a(:), e ! Change 'e' to an array and >> > second memcpy works correctly >> > ! Problem is with loc(e), which >> > returns the address of the >> > ! class container. >> > allocate (e, source = 99.0) >> > allocate (a(2), source = [1.0, 2.0]) >> > call add_element_poly (a,e) >> > select type (a) >> > type is (real) >> > print *, a >> > end select >> > >> > contains >> > >> > subroutine add_element_poly(a,e) >> > use iso_c_binding >> > class(*),allocatable,intent(inout),target :: a(:) >> > class(*),intent(in),target :: e >> > class(*),allocatable,target :: tmp(:) >> > type(c_ptr) :: dummy >> > >> > interface >> > function memcpy(dest,src,n) bind(C,name="memcpy") result(res) >> > import >> > type(c_ptr) :: res >> > integer(c_intptr_t),value :: dest >> > integer(c_intptr_t),value :: src >> > integer(c_size_t),value :: n >> > end function >> > end interface >> > >> > if (.not.allocated(a)) then >> > allocate(a(1), source=e) >> > else >> > allocate(tmp(size(a)),source=a) >> > deallocate(a) >> > allocate(a(size(tmp)+1),source=e) ! mold gives a segfault >> > dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) >> > dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) >> > end if >> > end subroutine >> > end >> > >> >> >> > > > -- > Andre Vehreschild * Email: vehre ad gmx dot de -- Outside of a dog, a book is a man's best friend. Inside of a dog it's too dark to read. Groucho Marx ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Patch, Fortran, pr60322] was: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-03-27 12:48 ` Paul Richard Thomas @ 2015-04-05 9:13 ` Paul Richard Thomas 2015-04-09 12:37 ` Andre Vehreschild 0 siblings, 1 reply; 18+ messages in thread From: Paul Richard Thomas @ 2015-04-05 9:13 UTC (permalink / raw) To: Andre Vehreschild Cc: Mikael Morin, GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis, Dominique Dhumieres Dear Andre, Well, time passed and it didn't get done. Too much going on at the moment! As you say, the patch bootstraps and regtests on x86_64, FC21 in my case. I am now very reluctant to mess around with the gcc-5 release. Thus, I think that this patch must be committed to 5.2 and 6.0, when the are open for business. A few trivial comments: + /* The dummy is returned for pointer, allocatable or assumed rank arrays. + The check for pointerness needs to be repeated here (it is done in + IS_CLASS_ARRAY (), too), because for class arrays that are pointers, as + is the one of the sym, which is incorrect here. */ What does this mean, please? + /* Returning the descriptor for dummy class arrays is hazardous, because + some caller is expecting an expression to apply the component refs to. + Therefore the descriptor is only created and stored in + sym->backend_decl's GFC_DECL_SAVED_DESCRIPTOR. The caller is then + responsible to extract it from there, when the descriptor is + desired. */ + if (IS_CLASS_ARRAY (sym) + && (!DECL_LANG_SPECIFIC (sym->backend_decl) + || !GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl))) + { + decl = gfc_build_dummy_array_decl (sym, sym->backend_decl); + /* Prevent the dummy from being detected as unused if it is copied. */ + if (sym->backend_decl != NULL && decl != sym->backend_decl) + DECL_ARTIFICIAL (sym->backend_decl) = 1; + sym->backend_decl = decl; + } The comments, such as the above are often going well beyond column 72, into the 80's. I know that much of the existing code violates this style requirement but there is no need to do so if clarity is not reduced thereby. In trans-stmt.c s/standart/standard/ Don't forget to put the PR numbers in the ChangeLogs. For this submission, I would have appreciated some a description of what each chunk in the patch is doing, just because there is so much of it. I suppose that it was good for my imortal soul to sort it out for myself but it took a little while :-) Cheers and many thanks for the patch. Paul On 27 March 2015 at 13:48, Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: > Dear Andre, > > I am in the UK as of last night. Before leaving, I bootstrapped and > regtested your patch and all was well. I must drive to Cambridge this > afternoon to see my mother and will try to get to it either this > evening or tomorrow morning. There is so much of it and it touches > many places; so I must give it a very careful looking over before > giving the green light. Bear with me please. > > Great work though! > > Paul > > On 24 March 2015 at 18:06, Andre Vehreschild <vehre@gmx.de> wrote: >> Hi all, >> >> I have worked on the comments Mikael gave me. I am now checking for >> class_pointer in the way he pointed out. >> >> Furthermore did I *join the two parts* of the patch into this one, because >> keeping both in sync was no benefit but only tedious and did not prove to be >> reviewed faster. >> >> Paul, Dominique: I have addressed the LOC issue that came up lately. Or rather >> the patch addressed it already. I feel like this is not tested very well, not >> the loc() call nor the sizeof() call as given in the 57305 second's download. >> Unfortunately, is that download not runable. I would love to see a test similar >> to that download, but couldn't come up with one, that satisfied me. Given that >> the patch's review will last some days, I still have enough time to come up >> with something beautiful which I will add then. >> >> Bootstraps and regtests ok on x86_64-linux-gnu/F20. >> >> Regards, >> Andre >> >> >> On Tue, 24 Mar 2015 11:13:27 +0100 >> Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: >> >>> Dear Andre, >>> >>> Dominique pointed out to me that the 'loc' patch causes a ICE in the >>> testsuite. It seems that 'loc' should provide the address of the class >>> container in some places and the address of the data in others. I will >>> put my thinking cap on tonight :-) >>> >>> Cheers >>> >>> Paul >>> >>> On 23 March 2015 at 13:43, Andre Vehreschild <vehre@gmx.de> wrote: >>> > Hi Mikael, >>> > >>> > thanks for looking at the patch. Please note, that Paul has sent an >>> > addendum to the patches for 60322, which I deliberately have attached. >>> > >>> >> 26/02/2015 18:17, Andre Vehreschild a écrit : >>> >> > This first patch is only preparatory and does not change any of the >>> >> > semantics of gfortran at all. >>> >> Sure? >>> > >>> > With the counterexample you found below, this of course is a wrong >>> > statement. >>> > >>> >> > diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c >>> >> > index ab6f7a5..d28cf77 100644 >>> >> > --- a/gcc/fortran/expr.c >>> >> > +++ b/gcc/fortran/expr.c >>> >> > @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) >>> >> > lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name); >>> >> > >>> >> > /* It will always be a full array. */ >>> >> > - lval->rank = sym->as ? sym->as->rank : 0; >>> >> > + as = sym->as; >>> >> > + lval->rank = as ? as->rank : 0; >>> >> > if (lval->rank) >>> >> > - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? >>> >> > - CLASS_DATA (sym)->as : sym->as); >>> >> > + gfc_add_full_array_ref (lval, as); >>> >> >>> >> This is a change of semantics. Or do you know that sym->ts.type != >>> >> BT_CLASS? >>> > >>> > You are completely right. I have made a mistake here. I have to tell the >>> > truth, I never ran a regtest with only part 1 of the patches applied. The >>> > second part of the patch will correct this, by setting the variable as >>> > depending on whether type == BT_CLASS or not. Sorry for the mistake. >>> > >>> >> > diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c >>> >> > index 3664824..e571a17 100644 >>> >> > --- a/gcc/fortran/trans-decl.c >>> >> > +++ b/gcc/fortran/trans-decl.c >>> >> > @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, >>> >> > tree dummy) tree decl; >>> >> > tree type; >>> >> > gfc_array_spec *as; >>> >> > + symbol_attribute *array_attr; >>> >> > char *name; >>> >> > gfc_packed packed; >>> >> > int n; >>> >> > bool known_size; >>> >> > >>> >> > - if (sym->attr.pointer || sym->attr.allocatable >>> >> > - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) >>> >> > + /* Use the array as and attr. */ >>> >> > + as = sym->as; >>> >> > + array_attr = &sym->attr; >>> >> > + >>> >> > + /* The pointer attribute is always set on a _data component, therefore >>> >> > check >>> >> > + the sym's attribute only. */ >>> >> > + if (sym->attr.pointer || array_attr->allocatable >>> >> > + || (as && as->type == AS_ASSUMED_RANK)) >>> >> > return dummy; >>> >> > >>> >> Any reason to sometimes use array_attr, sometimes not, like here? >>> >> By the way, the comment is misleading: for classes, there is the >>> >> class_pointer attribute (and it is a pain, I know). >>> > >>> > Yes, and a good one. Array_attr is sometimes sym->attr and sometimes >>> > CLASS_DATA(sym)->attr aka sym->ts.u.derived->components->attr. In the later >>> > case .pointer is always set to 1 in the _data component's attr. I.e., the >>> > above if, would always yield true for a class_array, which is not intended, >>> > but rather destructive. I know about the class_pointer attribute, but I >>> > figured, that it is not relevant here. Any idea how to formulate the >>> > comment better, to reflect what I just explained? >>> > >>> > Regards, >>> > Andre >>> > -- >>> > Andre Vehreschild * Email: vehre ad gmx dot de >>> > >>> > >>> > ---------- Forwarded message ---------- >>> > From: Paul Richard Thomas <paul.richard.thomas@gmail.com> >>> > To: Andre Vehreschild <vehre@gmx.de>, Dominique Dhumieres >>> > <dominiq@lps.ens.fr> Cc: >>> > Date: Sun, 22 Mar 2015 21:20:20 +0100 >>> > Subject: Bug in intrinsic LOC for scalar class objects >>> > Dear Andre and Dominique, >>> > >>> > I have found that LOC is returning the address of the class container >>> > rather than the _data component for class scalars. See the source >>> > below, which you will recognise! A fix is attached. >>> > >>> > Note that the scalar allocate fails with MOLD= and so I substituted SOURCE=. >>> > >>> > Cheers >>> > >>> > Paul >>> > >>> > class(*), allocatable :: a(:), e ! Change 'e' to an array and >>> > second memcpy works correctly >>> > ! Problem is with loc(e), which >>> > returns the address of the >>> > ! class container. >>> > allocate (e, source = 99.0) >>> > allocate (a(2), source = [1.0, 2.0]) >>> > call add_element_poly (a,e) >>> > select type (a) >>> > type is (real) >>> > print *, a >>> > end select >>> > >>> > contains >>> > >>> > subroutine add_element_poly(a,e) >>> > use iso_c_binding >>> > class(*),allocatable,intent(inout),target :: a(:) >>> > class(*),intent(in),target :: e >>> > class(*),allocatable,target :: tmp(:) >>> > type(c_ptr) :: dummy >>> > >>> > interface >>> > function memcpy(dest,src,n) bind(C,name="memcpy") result(res) >>> > import >>> > type(c_ptr) :: res >>> > integer(c_intptr_t),value :: dest >>> > integer(c_intptr_t),value :: src >>> > integer(c_size_t),value :: n >>> > end function >>> > end interface >>> > >>> > if (.not.allocated(a)) then >>> > allocate(a(1), source=e) >>> > else >>> > allocate(tmp(size(a)),source=a) >>> > deallocate(a) >>> > allocate(a(size(tmp)+1),source=e) ! mold gives a segfault >>> > dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) >>> > dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) >>> > end if >>> > end subroutine >>> > end >>> > >>> >>> >>> >> >> >> -- >> Andre Vehreschild * Email: vehre ad gmx dot de > > > > -- > Outside of a dog, a book is a man's best friend. Inside of a dog it's > too dark to read. > > Groucho Marx -- Outside of a dog, a book is a man's best friend. Inside of a dog it's too dark to read. Groucho Marx ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Patch, Fortran, pr60322] was: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-04-05 9:13 ` Paul Richard Thomas @ 2015-04-09 12:37 ` Andre Vehreschild 2015-04-14 17:01 ` [Patch, Fortran, pr60322, addendum] " Andre Vehreschild 0 siblings, 1 reply; 18+ messages in thread From: Andre Vehreschild @ 2015-04-09 12:37 UTC (permalink / raw) To: Paul Richard Thomas Cc: Mikael Morin, GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis, Dominique Dhumieres Hi Paul, hi all, Paul, thanks for the review. Answers to your questions are inline below: On Sun, 5 Apr 2015 11:13:05 +0200 Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: <snip> > + /* The dummy is returned for pointer, allocatable or assumed rank arrays. > + The check for pointerness needs to be repeated here (it is done in > + IS_CLASS_ARRAY (), too), because for class arrays that are pointers, as > + is the one of the sym, which is incorrect here. */ > > What does this mean, please? The first sentence is about regular arrays and should be unchanged from the original source. Then I have to check for class (arrays) that are pointers, i.e., independent of whether the sym is a class array or a regular pointer to a class object. (The latter shouldn't make it into the routine anyway.) IS_CLASS_ARRAY () returns false for too many reasons to be of use here. I have to apologize and confess that the comment was a mere note to myself to not return to use is_classarray in the if below. Let me rephrase the comment to be: /* The dummy is returned for pointer, allocatable or assumed rank arrays. For class arrays the information if sym is an allocatable or pointer object needs to be checked explicitly (IS_CLASS_ARRAY can be false for too many reasons to be of use here). */ > + /* Returning the descriptor for dummy class arrays is hazardous, > because > + some caller is expecting an expression to apply the component refs to. > + Therefore the descriptor is only created and stored in > + sym->backend_decl's GFC_DECL_SAVED_DESCRIPTOR. The caller is then > + responsible to extract it from there, when the descriptor is > + desired. */ > + if (IS_CLASS_ARRAY (sym) > + && (!DECL_LANG_SPECIFIC (sym->backend_decl) > + || !GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl))) > + { > + decl = gfc_build_dummy_array_decl (sym, sym->backend_decl); > + /* Prevent the dummy from being detected as unused if it is copied. */ > + if (sym->backend_decl != NULL && decl != sym->backend_decl) > + DECL_ARTIFICIAL (sym->backend_decl) = 1; > + sym->backend_decl = decl; > + } > > The comments, such as the above are often going well beyond column 72, > into the 80's. I know that much of the existing code violates this > style requirement but there is no need to do so if clarity is not > reduced thereby. Er, the document at https://gcc.gnu.org/codingconventions.html#C_Formatting says that line length is 80, or is there another convention, that I am not aware of? > In trans-stmt.c s/standart/standard/ Fixed. > Don't forget to put the PR numbers in the ChangeLogs. I won't anymore, already got told off :-) > For this submission, I would have appreciated some a description of > what each chunk in the patch is doing, just because there is so much > of it. I suppose that it was good for my imortal soul to sort it out > for myself but it took a little while :-) I initially tried to split the submission in two parts to make it more manageable. One part with the brain-dead substitutions of as and array_attr and one with the new code. Albeit I failed to get the brain-dead part right and made some mistakes there already, which Mikael pointed out. I therefore went for the big submission. Now doing a description of what each "chunk" does is quite tedious. I really would like to spend my time more productive. Would you be satisfied, when I write a story about the patch, referring to some parts more explicitly, like "Chunk 4 of file trans-stmt.c is the heart of the patch and does this and that. The remaining chunks are more or less putting the data together." (This is not correct for this patch of course. Just an example.) More elaborate of course, but just to give an idea. Thanks again. I will commit as soon as 5.2/6.0 commit window is open. Regards, Andre > > Cheers and many thanks for the patch. > > Paul > > On 27 March 2015 at 13:48, Paul Richard Thomas > <paul.richard.thomas@gmail.com> wrote: > > Dear Andre, > > > > I am in the UK as of last night. Before leaving, I bootstrapped and > > regtested your patch and all was well. I must drive to Cambridge this > > afternoon to see my mother and will try to get to it either this > > evening or tomorrow morning. There is so much of it and it touches > > many places; so I must give it a very careful looking over before > > giving the green light. Bear with me please. > > > > Great work though! > > > > Paul > > > > On 24 March 2015 at 18:06, Andre Vehreschild <vehre@gmx.de> wrote: > >> Hi all, > >> > >> I have worked on the comments Mikael gave me. I am now checking for > >> class_pointer in the way he pointed out. > >> > >> Furthermore did I *join the two parts* of the patch into this one, because > >> keeping both in sync was no benefit but only tedious and did not prove to > >> be reviewed faster. > >> > >> Paul, Dominique: I have addressed the LOC issue that came up lately. Or > >> rather the patch addressed it already. I feel like this is not tested very > >> well, not the loc() call nor the sizeof() call as given in the 57305 > >> second's download. Unfortunately, is that download not runable. I would > >> love to see a test similar to that download, but couldn't come up with > >> one, that satisfied me. Given that the patch's review will last some days, > >> I still have enough time to come up with something beautiful which I will > >> add then. > >> > >> Bootstraps and regtests ok on x86_64-linux-gnu/F20. > >> > >> Regards, > >> Andre > >> > >> > >> On Tue, 24 Mar 2015 11:13:27 +0100 > >> Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: > >> > >>> Dear Andre, > >>> > >>> Dominique pointed out to me that the 'loc' patch causes a ICE in the > >>> testsuite. It seems that 'loc' should provide the address of the class > >>> container in some places and the address of the data in others. I will > >>> put my thinking cap on tonight :-) > >>> > >>> Cheers > >>> > >>> Paul > >>> > >>> On 23 March 2015 at 13:43, Andre Vehreschild <vehre@gmx.de> wrote: > >>> > Hi Mikael, > >>> > > >>> > thanks for looking at the patch. Please note, that Paul has sent an > >>> > addendum to the patches for 60322, which I deliberately have attached. > >>> > > >>> >> 26/02/2015 18:17, Andre Vehreschild a écrit : > >>> >> > This first patch is only preparatory and does not change any of the > >>> >> > semantics of gfortran at all. > >>> >> Sure? > >>> > > >>> > With the counterexample you found below, this of course is a wrong > >>> > statement. > >>> > > >>> >> > diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c > >>> >> > index ab6f7a5..d28cf77 100644 > >>> >> > --- a/gcc/fortran/expr.c > >>> >> > +++ b/gcc/fortran/expr.c > >>> >> > @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) > >>> >> > lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name); > >>> >> > > >>> >> > /* It will always be a full array. */ > >>> >> > - lval->rank = sym->as ? sym->as->rank : 0; > >>> >> > + as = sym->as; > >>> >> > + lval->rank = as ? as->rank : 0; > >>> >> > if (lval->rank) > >>> >> > - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? > >>> >> > - CLASS_DATA (sym)->as : sym->as); > >>> >> > + gfc_add_full_array_ref (lval, as); > >>> >> > >>> >> This is a change of semantics. Or do you know that sym->ts.type != > >>> >> BT_CLASS? > >>> > > >>> > You are completely right. I have made a mistake here. I have to tell the > >>> > truth, I never ran a regtest with only part 1 of the patches applied. > >>> > The second part of the patch will correct this, by setting the variable > >>> > as depending on whether type == BT_CLASS or not. Sorry for the mistake. > >>> > > >>> >> > diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c > >>> >> > index 3664824..e571a17 100644 > >>> >> > --- a/gcc/fortran/trans-decl.c > >>> >> > +++ b/gcc/fortran/trans-decl.c > >>> >> > @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, > >>> >> > tree dummy) tree decl; > >>> >> > tree type; > >>> >> > gfc_array_spec *as; > >>> >> > + symbol_attribute *array_attr; > >>> >> > char *name; > >>> >> > gfc_packed packed; > >>> >> > int n; > >>> >> > bool known_size; > >>> >> > > >>> >> > - if (sym->attr.pointer || sym->attr.allocatable > >>> >> > - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) > >>> >> > + /* Use the array as and attr. */ > >>> >> > + as = sym->as; > >>> >> > + array_attr = &sym->attr; > >>> >> > + > >>> >> > + /* The pointer attribute is always set on a _data component, > >>> >> > therefore check > >>> >> > + the sym's attribute only. */ > >>> >> > + if (sym->attr.pointer || array_attr->allocatable > >>> >> > + || (as && as->type == AS_ASSUMED_RANK)) > >>> >> > return dummy; > >>> >> > > >>> >> Any reason to sometimes use array_attr, sometimes not, like here? > >>> >> By the way, the comment is misleading: for classes, there is the > >>> >> class_pointer attribute (and it is a pain, I know). > >>> > > >>> > Yes, and a good one. Array_attr is sometimes sym->attr and sometimes > >>> > CLASS_DATA(sym)->attr aka sym->ts.u.derived->components->attr. In the > >>> > later case .pointer is always set to 1 in the _data component's attr. > >>> > I.e., the above if, would always yield true for a class_array, which is > >>> > not intended, but rather destructive. I know about the class_pointer > >>> > attribute, but I figured, that it is not relevant here. Any idea how to > >>> > formulate the comment better, to reflect what I just explained? > >>> > > >>> > Regards, > >>> > Andre > >>> > -- > >>> > Andre Vehreschild * Email: vehre ad gmx dot de > >>> > > >>> > > >>> > ---------- Forwarded message ---------- > >>> > From: Paul Richard Thomas <paul.richard.thomas@gmail.com> > >>> > To: Andre Vehreschild <vehre@gmx.de>, Dominique Dhumieres > >>> > <dominiq@lps.ens.fr> Cc: > >>> > Date: Sun, 22 Mar 2015 21:20:20 +0100 > >>> > Subject: Bug in intrinsic LOC for scalar class objects > >>> > Dear Andre and Dominique, > >>> > > >>> > I have found that LOC is returning the address of the class container > >>> > rather than the _data component for class scalars. See the source > >>> > below, which you will recognise! A fix is attached. > >>> > > >>> > Note that the scalar allocate fails with MOLD= and so I substituted > >>> > SOURCE=. > >>> > > >>> > Cheers > >>> > > >>> > Paul > >>> > > >>> > class(*), allocatable :: a(:), e ! Change 'e' to an array and > >>> > second memcpy works correctly > >>> > ! Problem is with loc(e), which > >>> > returns the address of the > >>> > ! class container. > >>> > allocate (e, source = 99.0) > >>> > allocate (a(2), source = [1.0, 2.0]) > >>> > call add_element_poly (a,e) > >>> > select type (a) > >>> > type is (real) > >>> > print *, a > >>> > end select > >>> > > >>> > contains > >>> > > >>> > subroutine add_element_poly(a,e) > >>> > use iso_c_binding > >>> > class(*),allocatable,intent(inout),target :: a(:) > >>> > class(*),intent(in),target :: e > >>> > class(*),allocatable,target :: tmp(:) > >>> > type(c_ptr) :: dummy > >>> > > >>> > interface > >>> > function memcpy(dest,src,n) bind(C,name="memcpy") result(res) > >>> > import > >>> > type(c_ptr) :: res > >>> > integer(c_intptr_t),value :: dest > >>> > integer(c_intptr_t),value :: src > >>> > integer(c_size_t),value :: n > >>> > end function > >>> > end interface > >>> > > >>> > if (.not.allocated(a)) then > >>> > allocate(a(1), source=e) > >>> > else > >>> > allocate(tmp(size(a)),source=a) > >>> > deallocate(a) > >>> > allocate(a(size(tmp)+1),source=e) ! mold gives a segfault > >>> > dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) > >>> > dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) > >>> > end if > >>> > end subroutine > >>> > end > >>> > > >>> > >>> > >>> > >> > >> > >> -- > >> Andre Vehreschild * Email: vehre ad gmx dot de > > > > > > > > -- > > Outside of a dog, a book is a man's best friend. Inside of a dog it's > > too dark to read. > > > > Groucho Marx > > > -- Andre Vehreschild * Email: vehre ad gmx dot de ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Patch, Fortran, pr60322, addendum] was: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-04-09 12:37 ` Andre Vehreschild @ 2015-04-14 17:01 ` Andre Vehreschild 2015-04-16 19:13 ` Paul Richard Thomas 0 siblings, 1 reply; 18+ messages in thread From: Andre Vehreschild @ 2015-04-14 17:01 UTC (permalink / raw) To: Paul Richard Thomas Cc: Mikael Morin, GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis, Dominique Dhumieres [-- Attachment #1: Type: text/plain, Size: 15798 bytes --] Hi all, during further testing of a big Fortran software I encounter two bugs with class arrays, that are somehow connected to pr60322. I therefore propose an extended patch for pr60322. Because Paul has already reviewed most the extended patch, I give you two patches: 1. a full patch, fixing all the issues connected to pr60322, and 2. a delta patch to get from the reviewed patch to the latest version. With the second patch I hope to get a faster review, because it is significantly shorter. Now what was the issue? To be precise there were two issues: i. a pointer to a class array (CLASS_DATA(sym).attr.class_pointer == 1) was dereferenced, which lead to an ICE (the patch for this in the delta is chunk 5 in gfc_conv_expr_descriptor, and ii. (and this was a severe brain cracker) in chains of references consisting of more then one class-(array)-ref always the _vptr of the first symbol was taken and not the _vptr of the currently dereferenced class object. This occurred when fortran code similiar to this was executed: type innerT integer, allocatable :: arr(:) end type type T class(innerT) :: mat(:,:) end type class(T) :: o allocate(o%mat(2,2)) allocate(o%mat(:,:)%arr(10)) ! This is obviously pseudo code, ! but I think you get what is meant. o%mat(1,1)%arr(1) = 1 In the last line the address to get to arr(1) was computed using the _vptr->size of o and not of o%mat(1,1). To fix this gfc_component_ref () now computes the class' _vptr-ref whenever it does a _data-ref (chunk 1 of trans-expr.c in the delta patch). The _vptr-ref is stored in gfc_se, where I added the new member class_vptr. The gfc_se->class_vptr is then used in array-refs (chunk 2 of trans.c) to get the size of the array elements of the correct level. The other chunks of the delta patch are: - parameter passing fixes, and - documentation fixes as requested for the version 5 of the pr60322 patch. I hope this helps in getting the patch reviewed quickly. Bootstraps and regtests ok on x86_64-linux-gnu/F21. Ok for trunk -> 6.0? Ok, for backport to 5.2, once available? Note, the patches may apply with shifts, as I forgot to update before taking the diffs. Regards, Andre On Thu, 9 Apr 2015 14:37:09 +0200 Andre Vehreschild <vehre@gmx.de> wrote: > Hi Paul, hi all, > > Paul, thanks for the review. Answers to your questions are inline below: > > On Sun, 5 Apr 2015 11:13:05 +0200 > Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: > <snip> > > + /* The dummy is returned for pointer, allocatable or assumed rank arrays. > > + The check for pointerness needs to be repeated here (it is done in > > + IS_CLASS_ARRAY (), too), because for class arrays that are pointers, > > as > > + is the one of the sym, which is incorrect here. */ > > > > What does this mean, please? > > The first sentence is about regular arrays and should be unchanged from the > original source. Then I have to check for class (arrays) that are pointers, > i.e., independent of whether the sym is a class array or a regular pointer to > a class object. (The latter shouldn't make it into the routine anyway.) > IS_CLASS_ARRAY () returns false for too many reasons to be of use here. I have > to apologize and confess that the comment was a mere note to myself to not > return to use is_classarray in the if below. Let me rephrase the comment to > be: > > /* The dummy is returned for pointer, allocatable or assumed rank arrays. > For class arrays the information if sym is an allocatable or pointer > object needs to be checked explicitly (IS_CLASS_ARRAY can be false for > too many reasons to be of use here). */ > > > + /* Returning the descriptor for dummy class arrays is hazardous, > > because > > + some caller is expecting an expression to apply the component refs to. > > + Therefore the descriptor is only created and stored in > > + sym->backend_decl's GFC_DECL_SAVED_DESCRIPTOR. The caller is then > > + responsible to extract it from there, when the descriptor is > > + desired. */ > > + if (IS_CLASS_ARRAY (sym) > > + && (!DECL_LANG_SPECIFIC (sym->backend_decl) > > + || !GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl))) > > + { > > + decl = gfc_build_dummy_array_decl (sym, sym->backend_decl); > > + /* Prevent the dummy from being detected as unused if it is copied. > > */ > > + if (sym->backend_decl != NULL && decl != sym->backend_decl) > > + DECL_ARTIFICIAL (sym->backend_decl) = 1; > > + sym->backend_decl = decl; > > + } > > > > The comments, such as the above are often going well beyond column 72, > > into the 80's. I know that much of the existing code violates this > > style requirement but there is no need to do so if clarity is not > > reduced thereby. > > Er, the document at > > https://gcc.gnu.org/codingconventions.html#C_Formatting > > says that line length is 80, or is there another convention, that I am not > aware of? > > > In trans-stmt.c s/standart/standard/ > > Fixed. > > > Don't forget to put the PR numbers in the ChangeLogs. > > I won't anymore, already got told off :-) > > > For this submission, I would have appreciated some a description of > > what each chunk in the patch is doing, just because there is so much > > of it. I suppose that it was good for my imortal soul to sort it out > > for myself but it took a little while :-) > > I initially tried to split the submission in two parts to make it more > manageable. One part with the brain-dead substitutions of as and array_attr > and one with the new code. Albeit I failed to get the brain-dead part right > and made some mistakes there already, which Mikael pointed out. I therefore > went for the big submission. > > Now doing a description of what each "chunk" does is quite tedious. I really > would like to spend my time more productive. Would you be satisfied, when I > write a story about the patch, referring to some parts more explicitly, like > > "Chunk 4 of file trans-stmt.c is the heart of the patch and does this and > that. The remaining chunks are more or less putting the data together." > > (This is not correct for this patch of course. Just an example.) More > elaborate of course, but just to give an idea. > > Thanks again. I will commit as soon as 5.2/6.0 commit window is open. > > Regards, > Andre > > > > > Cheers and many thanks for the patch. > > > > Paul > > > > On 27 March 2015 at 13:48, Paul Richard Thomas > > <paul.richard.thomas@gmail.com> wrote: > > > Dear Andre, > > > > > > I am in the UK as of last night. Before leaving, I bootstrapped and > > > regtested your patch and all was well. I must drive to Cambridge this > > > afternoon to see my mother and will try to get to it either this > > > evening or tomorrow morning. There is so much of it and it touches > > > many places; so I must give it a very careful looking over before > > > giving the green light. Bear with me please. > > > > > > Great work though! > > > > > > Paul > > > > > > On 24 March 2015 at 18:06, Andre Vehreschild <vehre@gmx.de> wrote: > > >> Hi all, > > >> > > >> I have worked on the comments Mikael gave me. I am now checking for > > >> class_pointer in the way he pointed out. > > >> > > >> Furthermore did I *join the two parts* of the patch into this one, > > >> because keeping both in sync was no benefit but only tedious and did not > > >> prove to be reviewed faster. > > >> > > >> Paul, Dominique: I have addressed the LOC issue that came up lately. Or > > >> rather the patch addressed it already. I feel like this is not tested > > >> very well, not the loc() call nor the sizeof() call as given in the 57305 > > >> second's download. Unfortunately, is that download not runable. I would > > >> love to see a test similar to that download, but couldn't come up with > > >> one, that satisfied me. Given that the patch's review will last some > > >> days, I still have enough time to come up with something beautiful which > > >> I will add then. > > >> > > >> Bootstraps and regtests ok on x86_64-linux-gnu/F20. > > >> > > >> Regards, > > >> Andre > > >> > > >> > > >> On Tue, 24 Mar 2015 11:13:27 +0100 > > >> Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: > > >> > > >>> Dear Andre, > > >>> > > >>> Dominique pointed out to me that the 'loc' patch causes a ICE in the > > >>> testsuite. It seems that 'loc' should provide the address of the class > > >>> container in some places and the address of the data in others. I will > > >>> put my thinking cap on tonight :-) > > >>> > > >>> Cheers > > >>> > > >>> Paul > > >>> > > >>> On 23 March 2015 at 13:43, Andre Vehreschild <vehre@gmx.de> wrote: > > >>> > Hi Mikael, > > >>> > > > >>> > thanks for looking at the patch. Please note, that Paul has sent an > > >>> > addendum to the patches for 60322, which I deliberately have attached. > > >>> > > > >>> >> 26/02/2015 18:17, Andre Vehreschild a écrit : > > >>> >> > This first patch is only preparatory and does not change any of the > > >>> >> > semantics of gfortran at all. > > >>> >> Sure? > > >>> > > > >>> > With the counterexample you found below, this of course is a wrong > > >>> > statement. > > >>> > > > >>> >> > diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c > > >>> >> > index ab6f7a5..d28cf77 100644 > > >>> >> > --- a/gcc/fortran/expr.c > > >>> >> > +++ b/gcc/fortran/expr.c > > >>> >> > @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) > > >>> >> > lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name); > > >>> >> > > > >>> >> > /* It will always be a full array. */ > > >>> >> > - lval->rank = sym->as ? sym->as->rank : 0; > > >>> >> > + as = sym->as; > > >>> >> > + lval->rank = as ? as->rank : 0; > > >>> >> > if (lval->rank) > > >>> >> > - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? > > >>> >> > - CLASS_DATA (sym)->as : sym->as); > > >>> >> > + gfc_add_full_array_ref (lval, as); > > >>> >> > > >>> >> This is a change of semantics. Or do you know that sym->ts.type != > > >>> >> BT_CLASS? > > >>> > > > >>> > You are completely right. I have made a mistake here. I have to tell > > >>> > the truth, I never ran a regtest with only part 1 of the patches > > >>> > applied. The second part of the patch will correct this, by setting > > >>> > the variable as depending on whether type == BT_CLASS or not. Sorry > > >>> > for the mistake. > > >>> > > > >>> >> > diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c > > >>> >> > index 3664824..e571a17 100644 > > >>> >> > --- a/gcc/fortran/trans-decl.c > > >>> >> > +++ b/gcc/fortran/trans-decl.c > > >>> >> > @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * > > >>> >> > sym, tree dummy) tree decl; > > >>> >> > tree type; > > >>> >> > gfc_array_spec *as; > > >>> >> > + symbol_attribute *array_attr; > > >>> >> > char *name; > > >>> >> > gfc_packed packed; > > >>> >> > int n; > > >>> >> > bool known_size; > > >>> >> > > > >>> >> > - if (sym->attr.pointer || sym->attr.allocatable > > >>> >> > - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) > > >>> >> > + /* Use the array as and attr. */ > > >>> >> > + as = sym->as; > > >>> >> > + array_attr = &sym->attr; > > >>> >> > + > > >>> >> > + /* The pointer attribute is always set on a _data component, > > >>> >> > therefore check > > >>> >> > + the sym's attribute only. */ > > >>> >> > + if (sym->attr.pointer || array_attr->allocatable > > >>> >> > + || (as && as->type == AS_ASSUMED_RANK)) > > >>> >> > return dummy; > > >>> >> > > > >>> >> Any reason to sometimes use array_attr, sometimes not, like here? > > >>> >> By the way, the comment is misleading: for classes, there is the > > >>> >> class_pointer attribute (and it is a pain, I know). > > >>> > > > >>> > Yes, and a good one. Array_attr is sometimes sym->attr and sometimes > > >>> > CLASS_DATA(sym)->attr aka sym->ts.u.derived->components->attr. In the > > >>> > later case .pointer is always set to 1 in the _data component's attr. > > >>> > I.e., the above if, would always yield true for a class_array, which > > >>> > is not intended, but rather destructive. I know about the > > >>> > class_pointer attribute, but I figured, that it is not relevant here. > > >>> > Any idea how to formulate the comment better, to reflect what I just > > >>> > explained? > > >>> > > > >>> > Regards, > > >>> > Andre > > >>> > -- > > >>> > Andre Vehreschild * Email: vehre ad gmx dot de > > >>> > > > >>> > > > >>> > ---------- Forwarded message ---------- > > >>> > From: Paul Richard Thomas <paul.richard.thomas@gmail.com> > > >>> > To: Andre Vehreschild <vehre@gmx.de>, Dominique Dhumieres > > >>> > <dominiq@lps.ens.fr> Cc: > > >>> > Date: Sun, 22 Mar 2015 21:20:20 +0100 > > >>> > Subject: Bug in intrinsic LOC for scalar class objects > > >>> > Dear Andre and Dominique, > > >>> > > > >>> > I have found that LOC is returning the address of the class container > > >>> > rather than the _data component for class scalars. See the source > > >>> > below, which you will recognise! A fix is attached. > > >>> > > > >>> > Note that the scalar allocate fails with MOLD= and so I substituted > > >>> > SOURCE=. > > >>> > > > >>> > Cheers > > >>> > > > >>> > Paul > > >>> > > > >>> > class(*), allocatable :: a(:), e ! Change 'e' to an array and > > >>> > second memcpy works correctly > > >>> > ! Problem is with loc(e), which > > >>> > returns the address of the > > >>> > ! class container. > > >>> > allocate (e, source = 99.0) > > >>> > allocate (a(2), source = [1.0, 2.0]) > > >>> > call add_element_poly (a,e) > > >>> > select type (a) > > >>> > type is (real) > > >>> > print *, a > > >>> > end select > > >>> > > > >>> > contains > > >>> > > > >>> > subroutine add_element_poly(a,e) > > >>> > use iso_c_binding > > >>> > class(*),allocatable,intent(inout),target :: a(:) > > >>> > class(*),intent(in),target :: e > > >>> > class(*),allocatable,target :: tmp(:) > > >>> > type(c_ptr) :: dummy > > >>> > > > >>> > interface > > >>> > function memcpy(dest,src,n) bind(C,name="memcpy") result(res) > > >>> > import > > >>> > type(c_ptr) :: res > > >>> > integer(c_intptr_t),value :: dest > > >>> > integer(c_intptr_t),value :: src > > >>> > integer(c_size_t),value :: n > > >>> > end function > > >>> > end interface > > >>> > > > >>> > if (.not.allocated(a)) then > > >>> > allocate(a(1), source=e) > > >>> > else > > >>> > allocate(tmp(size(a)),source=a) > > >>> > deallocate(a) > > >>> > allocate(a(size(tmp)+1),source=e) ! mold gives a segfault > > >>> > dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) > > >>> > dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) > > >>> > end if > > >>> > end subroutine > > >>> > end > > >>> > > > >>> > > >>> > > >>> > > >> > > >> > > >> -- > > >> Andre Vehreschild * Email: vehre ad gmx dot de > > > > > > > > > > > > -- > > > Outside of a dog, a book is a man's best friend. Inside of a dog it's > > > too dark to read. > > > > > > Groucho Marx > > > > > > > > -- Andre Vehreschild * Email: vehre ad gmx dot de [-- Attachment #2: pr60322_full_6.clog --] [-- Type: application/octet-stream, Size: 3049 bytes --] gcc/testsuite/ChangeLog: 2015-04-14 Andre Vehreschild <vehre@gmx.de> * gfortran.dg/class_allocate_19.f03: New test. * gfortran.dg/class_array_20.f03: New test. * gfortran.dg/class_array_21.f03: New test. * gfortran.dg/finalize_10.f90: Corrected scan-trees. * gfortran.dg/finalize_15.f90: Fixing comparision to model initialization correctly. * gfortran.dg/finalize_29.f08: New test. gcc/fortran/ChangeLog: 2015-04-14 Andre Vehreschild <vehre@gmx.de> PR fortran/60322 * expr.c (gfc_lval_expr_from_sym): Code to select the regular or class array added. * gfortran.h: Add IS_CLASS_ARRAY macro. * trans-array.c (gfc_add_loop_ss_code): Treat class objects to be referenced always. (build_class_array_ref): Adapt retrieval of array descriptor. (build_array_ref): Likewise. (gfc_conv_array_ref): Hand the vptr or the descriptor to build_array_ref depending whether the sym is class or not. (gfc_trans_array_cobounds): Select correct gfc_array_spec for regular and class arrays. (gfc_trans_array_bounds): Likewise. (gfc_trans_dummy_array_bias): Likewise. (gfc_get_dataptr_offset): Correcting call of build_array_ref. (gfc_conv_expr_descriptor): Set the array's offset to -1 when lbound in inner most dim is 1 and symbol non-pointer/assoc. * trans-decl.c (gfc_build_qualified_array): Select correct gfc_array_spec for regular and class arrays. (gfc_build_dummy_array_decl): Likewise. (gfc_get_symbol_decl): Get a dummy array for class arrays. (gfc_trans_deferred_vars): Tell conv_expr that the descriptor is desired. * trans-expr.c (gfc_class_vptr_get): Get the class descriptor from the correct location for class arrays. (gfc_class_len_get): Likewise. (gfc_conv_intrinsic_to_class): Add handling of _len component. (gfc_conv_class_to_class): Prevent access to unset array data when the array is an optional argument. Add handling of _len component. (gfc_copy_class_to_class): Check that _def_init is non-NULL when used in _vptr->copy() (gfc_trans_class_init_assign): Ensure that the rank of _def_init is zero. (gfc_conv_component_ref): Get the _vptr along with _data refs. (gfc_conv_variable): Make sure the temp array descriptor is returned for class arrays, too, and that class arrays are dereferenced correctly. (gfc_conv_procedure_call): For polymorphic type initialization the initializer has to be a pointer to _def_init stored in a dummy variable, which then needs to be used by value. * trans-intrinsic.c (gfc_conv_intrinsic_sizeof): Use the temporary array descriptor for class arrays, too. (gfc_conv_intrinsic_storage_size): Likewise. (gfc_conv_intrinsic_loc): Add ref to _data for BT_CLASS expressions. * trans-stmt.c (trans_associate_var): Use a temporary array for the associate variable of class arrays, too, making the array one-based (lbound == 1). * trans-types.c (gfc_is_nodesc_array): Use the correct array data. * trans.c (gfc_build_array_ref): Use the dummy array descriptor when present. * trans.h: Add class_vptr to gfc_se for storing a class ref's vptr. [-- Attachment #3: pr60322_full_6.patch --] [-- Type: text/x-patch, Size: 63647 bytes --] diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c index ab6f7a5..7f3a59d 100644 --- a/gcc/fortran/expr.c +++ b/gcc/fortran/expr.c @@ -4052,6 +4052,7 @@ gfc_expr * gfc_lval_expr_from_sym (gfc_symbol *sym) { gfc_expr *lval; + gfc_array_spec *as; lval = gfc_get_expr (); lval->expr_type = EXPR_VARIABLE; lval->where = sym->declared_at; @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name); /* It will always be a full array. */ - lval->rank = sym->as ? sym->as->rank : 0; + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; + lval->rank = as ? as->rank : 0; if (lval->rank) - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? - CLASS_DATA (sym)->as : sym->as); + gfc_add_full_array_ref (lval, as); return lval; } diff --git a/gcc/fortran/gfortran.h b/gcc/fortran/gfortran.h index 24d56c0..643cd6a 100644 --- a/gcc/fortran/gfortran.h +++ b/gcc/fortran/gfortran.h @@ -3209,6 +3209,11 @@ bool gfc_is_finalizable (gfc_symbol *, gfc_expr **); && CLASS_DATA (sym) \ && CLASS_DATA (sym)->ts.u.derived \ && CLASS_DATA (sym)->ts.u.derived->attr.unlimited_polymorphic) +#define IS_CLASS_ARRAY(sym) \ + (sym->ts.type == BT_CLASS \ + && CLASS_DATA (sym) \ + && CLASS_DATA (sym)->attr.dimension \ + && !CLASS_DATA (sym)->attr.class_pointer) /* frontend-passes.c */ diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 1768974..3803cf8 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -2495,11 +2495,14 @@ gfc_add_loop_ss_code (gfc_loopinfo * loop, gfc_ss * ss, bool subscript, case GFC_SS_REFERENCE: /* Scalar argument to elemental procedure. */ gfc_init_se (&se, NULL); - if (ss_info->can_be_null_ref) + if (ss_info->can_be_null_ref || (expr->symtree + && (expr->symtree->n.sym->ts.type == BT_DERIVED + || expr->symtree->n.sym->ts.type == BT_CLASS))) { /* If the actual argument can be absent (in other words, it can be a NULL reference), don't try to evaluate it; pass instead - the reference directly. */ + the reference directly. The reference is also needed when + expr is of type class or derived. */ gfc_conv_expr_reference (&se, expr); } else @@ -3046,7 +3049,14 @@ build_class_array_ref (gfc_se *se, tree base, tree index) return false; } else if (class_ref == NULL) - decl = expr->symtree->n.sym->backend_decl; + { + decl = expr->symtree->n.sym->backend_decl; + /* For class arrays the tree containing the class is stored in + GFC_DECL_SAVED_DESCRIPTOR of the sym's backend_decl. + For all others it's sym's backend_decl directly. */ + if (DECL_LANG_SPECIFIC (decl) && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); + } else { /* Remove everything after the last class reference, convert the @@ -3155,30 +3165,45 @@ add_to_offset (tree *cst_offset, tree *offset, tree t) static tree -build_array_ref (tree desc, tree offset, tree decl) +build_array_ref (tree desc, tree offset, tree decl, tree vptr) { tree tmp; tree type; + tree cdecl; + bool classarray = false; + + /* For class arrays the class declaration is stored in the saved + descriptor. */ + if (INDIRECT_REF_P (desc) + && DECL_LANG_SPECIFIC (TREE_OPERAND (desc, 0)) + && GFC_DECL_SAVED_DESCRIPTOR (TREE_OPERAND (desc, 0))) + cdecl = gfc_class_data_get (GFC_DECL_SAVED_DESCRIPTOR ( + TREE_OPERAND (desc, 0))); + else + cdecl = desc; /* Class container types do not always have the GFC_CLASS_TYPE_P but the canonical type does. */ - if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)) - && TREE_CODE (desc) == COMPONENT_REF) + if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (cdecl)) + && TREE_CODE (cdecl) == COMPONENT_REF) { - type = TREE_TYPE (TREE_OPERAND (desc, 0)); + type = TREE_TYPE (TREE_OPERAND (cdecl, 0)); if (TYPE_CANONICAL (type) && GFC_CLASS_TYPE_P (TYPE_CANONICAL (type))) - type = TYPE_CANONICAL (type); + { + type = TREE_TYPE (desc); + classarray = true; + } } else type = NULL; /* Class array references need special treatment because the assigned type size needs to be used to point to the element. */ - if (type && GFC_CLASS_TYPE_P (type)) + if (classarray) { - type = gfc_get_element_type (TREE_TYPE (desc)); - tmp = TREE_OPERAND (desc, 0); + type = gfc_get_element_type (type); + tmp = TREE_OPERAND (cdecl, 0); tmp = gfc_get_class_array_ref (offset, tmp); tmp = fold_convert (build_pointer_type (type), tmp); tmp = build_fold_indirect_ref_loc (input_location, tmp); @@ -3187,7 +3212,7 @@ build_array_ref (tree desc, tree offset, tree decl) tmp = gfc_conv_array_data (desc); tmp = build_fold_indirect_ref_loc (input_location, tmp); - tmp = gfc_build_array_ref (tmp, offset, decl); + tmp = gfc_build_array_ref (tmp, offset, decl, vptr); return tmp; } @@ -3350,7 +3375,8 @@ gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar, gfc_expr *expr, offset = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type, offset, cst_offset); - se->expr = build_array_ref (se->expr, offset, sym->backend_decl); + se->expr = build_array_ref (se->expr, offset, sym->ts.type == BT_CLASS ? + NULL_TREE : sym->backend_decl, se->class_vptr); } @@ -5570,7 +5596,7 @@ gfc_trans_array_cobounds (tree type, stmtblock_t * pblock, gfc_se se; gfc_array_spec *as; - as = sym->as; + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; for (dim = as->rank; dim < as->rank + as->corank; dim++) { @@ -5613,7 +5639,7 @@ gfc_trans_array_bounds (tree type, gfc_symbol * sym, tree * poffset, int dim; - as = sym->as; + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; size = gfc_index_one_node; offset = gfc_index_zero_node; @@ -5900,12 +5926,17 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, int checkparm; int no_repack; bool optional_arg; + gfc_array_spec *as; + bool is_classarray = IS_CLASS_ARRAY (sym); /* Do nothing for pointer and allocatable arrays. */ - if (sym->attr.pointer || sym->attr.allocatable) + if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) + || sym->attr.allocatable + || (is_classarray && CLASS_DATA (sym)->attr.allocatable)) return; - if (sym->attr.dummy && gfc_is_nodesc_array (sym)) + if (!is_classarray && sym->attr.dummy && gfc_is_nodesc_array (sym)) { gfc_trans_g77_array (sym, block); return; @@ -5918,14 +5949,20 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, type = TREE_TYPE (tmpdesc); gcc_assert (GFC_ARRAY_TYPE_P (type)); dumdesc = GFC_DECL_SAVED_DESCRIPTOR (tmpdesc); - dumdesc = build_fold_indirect_ref_loc (input_location, dumdesc); + if (is_classarray) + /* For a class array the dummy array descriptor is in the _class + component. */ + dumdesc = gfc_class_data_get (dumdesc); + else + dumdesc = build_fold_indirect_ref_loc (input_location, dumdesc); + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; gfc_start_block (&init); if (sym->ts.type == BT_CHARACTER && TREE_CODE (sym->ts.u.cl->backend_decl) == VAR_DECL) gfc_conv_string_length (sym->ts.u.cl, NULL, &init); - checkparm = (sym->as->type == AS_EXPLICIT + checkparm = (as->type == AS_EXPLICIT && (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)); no_repack = !(GFC_DECL_PACKED_ARRAY (tmpdesc) @@ -6001,9 +6038,9 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, size = gfc_index_one_node; /* Evaluate the bounds of the array. */ - for (n = 0; n < sym->as->rank; n++) + for (n = 0; n < as->rank; n++) { - if (checkparm || !sym->as->upper[n]) + if (checkparm || !as->upper[n]) { /* Get the bounds of the actual parameter. */ dubound = gfc_conv_descriptor_ubound_get (dumdesc, gfc_rank_cst[n]); @@ -6019,7 +6056,7 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, if (!INTEGER_CST_P (lbound)) { gfc_init_se (&se, NULL); - gfc_conv_expr_type (&se, sym->as->lower[n], + gfc_conv_expr_type (&se, as->lower[n], gfc_array_index_type); gfc_add_block_to_block (&init, &se.pre); gfc_add_modify (&init, lbound, se.expr); @@ -6027,13 +6064,13 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, ubound = GFC_TYPE_ARRAY_UBOUND (type, n); /* Set the desired upper bound. */ - if (sym->as->upper[n]) + if (as->upper[n]) { /* We know what we want the upper bound to be. */ if (!INTEGER_CST_P (ubound)) { gfc_init_se (&se, NULL); - gfc_conv_expr_type (&se, sym->as->upper[n], + gfc_conv_expr_type (&se, as->upper[n], gfc_array_index_type); gfc_add_block_to_block (&init, &se.pre); gfc_add_modify (&init, ubound, se.expr); @@ -6086,7 +6123,7 @@ gfc_trans_dummy_array_bias (gfc_symbol * sym, tree tmpdesc, gfc_array_index_type, offset, tmp); /* The size of this dimension, and the stride of the next. */ - if (n + 1 < sym->as->rank) + if (n + 1 < as->rank) { stride = GFC_TYPE_ARRAY_STRIDE (type, n + 1); @@ -6234,7 +6271,7 @@ gfc_get_dataptr_offset (stmtblock_t *block, tree parm, tree desc, tree offset, return; } - tmp = build_array_ref (desc, offset, NULL); + tmp = build_array_ref (desc, offset, NULL, NULL); /* Offset the data pointer for pointer assignments from arrays with subreferences; e.g. my_integer => my_type(:)%integer_component. */ @@ -6789,6 +6826,7 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) tree from; tree to; tree base; + bool onebased = false; ndim = info->ref ? info->ref->u.ar.dimen : ss->dimen; @@ -6930,6 +6968,7 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) gfc_array_index_type, to, tmp); from = gfc_index_one_node; } + onebased = integer_onep (from); gfc_conv_descriptor_lbound_set (&loop.pre, parm, gfc_rank_cst[dim], from); @@ -6986,13 +7025,29 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) gfc_get_dataptr_offset (&loop.pre, parm, desc, offset, subref_array_target, expr); - if (((se->direct_byref || GFC_ARRAY_TYPE_P (TREE_TYPE (desc))) - && !se->data_not_needed) - || (se->use_offset && base != NULL_TREE)) + /* Force the offset to be -1, when the lower bound of the highest + dimension is one and the symbol is present and is not a + pointer/allocatable or associated. */ + if (onebased && se->use_offset + && expr->symtree + && !(expr->symtree->n.sym && expr->symtree->n.sym->ts.type == BT_CLASS + && !CLASS_DATA (expr->symtree->n.sym)->attr.class_pointer) + && !expr->symtree->n.sym->attr.allocatable + && !expr->symtree->n.sym->attr.pointer + && !expr->symtree->n.sym->attr.host_assoc + && !expr->symtree->n.sym->attr.use_assoc) { - /* Set the offset. */ - gfc_conv_descriptor_offset_set (&loop.pre, parm, base); + /* Set the offset to -1. */ + mpz_t minus_one; + mpz_init_set_si (minus_one, -1); + tmp = gfc_conv_mpz_to_tree (minus_one, gfc_index_integer_kind); + gfc_conv_descriptor_offset_set (&loop.pre, parm, tmp); } + else if (((se->direct_byref || GFC_ARRAY_TYPE_P (TREE_TYPE (desc))) + && !se->data_not_needed) + || (se->use_offset && base != NULL_TREE)) + /* Set the offset depending on base. */ + gfc_conv_descriptor_offset_set (&loop.pre, parm, base); else { /* Only the callee knows what the correct offset it, so just set diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c index 769d487..4c18920 100644 --- a/gcc/fortran/trans-decl.c +++ b/gcc/fortran/trans-decl.c @@ -812,8 +812,13 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) int dim; int nest; gfc_namespace* procns; + symbol_attribute *array_attr; + gfc_array_spec *as; + bool is_classarray = IS_CLASS_ARRAY (sym); type = TREE_TYPE (decl); + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; /* We just use the descriptor, if there is one. */ if (GFC_DESCRIPTOR_TYPE_P (type)) @@ -824,8 +829,8 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) nest = (procns->proc_name->backend_decl != current_function_decl) && !sym->attr.contained; - if (sym->attr.codimension && flag_coarray == GFC_FCOARRAY_LIB - && sym->as->type != AS_ASSUMED_SHAPE + if (array_attr->codimension && flag_coarray == GFC_FCOARRAY_LIB + && as->type != AS_ASSUMED_SHAPE && GFC_TYPE_ARRAY_CAF_TOKEN (type) == NULL_TREE) { tree token; @@ -878,8 +883,8 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) } /* Don't try to use the unknown bound for assumed shape arrays. */ if (GFC_TYPE_ARRAY_UBOUND (type, dim) == NULL_TREE - && (sym->as->type != AS_ASSUMED_SIZE - || dim < GFC_TYPE_ARRAY_RANK (type) - 1)) + && (as->type != AS_ASSUMED_SIZE + || dim < GFC_TYPE_ARRAY_RANK (type) - 1)) { GFC_TYPE_ARRAY_UBOUND (type, dim) = create_index_var ("ubound", nest); TREE_NO_WARNING (GFC_TYPE_ARRAY_UBOUND (type, dim)) = 1; @@ -920,7 +925,7 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) } if (GFC_TYPE_ARRAY_SIZE (type) == NULL_TREE - && sym->as->type != AS_ASSUMED_SIZE) + && as->type != AS_ASSUMED_SIZE) { GFC_TYPE_ARRAY_SIZE (type) = create_index_var ("size", nest); TREE_NO_WARNING (GFC_TYPE_ARRAY_SIZE (type)) = 1; @@ -947,12 +952,12 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) } if (TYPE_NAME (type) != NULL_TREE - && GFC_TYPE_ARRAY_UBOUND (type, sym->as->rank - 1) != NULL_TREE - && TREE_CODE (GFC_TYPE_ARRAY_UBOUND (type, sym->as->rank - 1)) == VAR_DECL) + && GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1) != NULL_TREE + && TREE_CODE (GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1)) == VAR_DECL) { tree gtype = DECL_ORIGINAL_TYPE (TYPE_NAME (type)); - for (dim = 0; dim < sym->as->rank - 1; dim++) + for (dim = 0; dim < as->rank - 1; dim++) { gcc_assert (TREE_CODE (gtype) == ARRAY_TYPE); gtype = TREE_TYPE (gtype); @@ -966,7 +971,7 @@ gfc_build_qualified_array (tree decl, gfc_symbol * sym) { tree gtype = TREE_TYPE (type), rtype, type_decl; - for (dim = sym->as->rank - 1; dim >= 0; dim--) + for (dim = as->rank - 1; dim >= 0; dim--) { tree lbound, ubound; lbound = GFC_TYPE_ARRAY_LBOUND (type, dim); @@ -1014,41 +1019,56 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) tree decl; tree type; gfc_array_spec *as; + symbol_attribute *array_attr; char *name; gfc_packed packed; int n; bool known_size; - - if (sym->attr.pointer || sym->attr.allocatable - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) + bool is_classarray = IS_CLASS_ARRAY (sym); + + /* Use the array as and attr. */ + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + + /* The dummy is returned for pointer, allocatable or assumed rank arrays. + For class arrays the information if sym is an allocatable or pointer + object needs to be checked explicitly (IS_CLASS_ARRAY can be false for + too many reasons to be of use here). */ + if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) + || array_attr->allocatable + || (as && as->type == AS_ASSUMED_RANK)) return dummy; - /* Add to list of variables if not a fake result variable. */ + /* Add to list of variables if not a fake result variable. + These symbols are set on the symbol only, not on the class component. */ if (sym->attr.result || sym->attr.dummy) gfc_defer_symbol_init (sym); - type = TREE_TYPE (dummy); + /* For a class array the array descriptor is in the _data component, while + for a regular array the TREE_TYPE of the dummy is a pointer to the + descriptor. */ + type = TREE_TYPE (is_classarray ? gfc_class_data_get (dummy) + : TREE_TYPE (dummy)); + /* type now is the array descriptor w/o any indirection. */ gcc_assert (TREE_CODE (dummy) == PARM_DECL - && POINTER_TYPE_P (type)); + && POINTER_TYPE_P (TREE_TYPE (dummy))); /* Do we know the element size? */ known_size = sym->ts.type != BT_CHARACTER || INTEGER_CST_P (sym->ts.u.cl->backend_decl); - if (known_size && !GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (type))) + if (known_size && !GFC_DESCRIPTOR_TYPE_P (type)) { /* For descriptorless arrays with known element size the actual argument is sufficient. */ - gcc_assert (GFC_ARRAY_TYPE_P (type)); gfc_build_qualified_array (dummy, sym); return dummy; } - type = TREE_TYPE (type); if (GFC_DESCRIPTOR_TYPE_P (type)) { /* Create a descriptorless array pointer. */ - as = sym->as; packed = PACKED_NO; /* Even when -frepack-arrays is used, symbols with TARGET attribute @@ -1079,8 +1099,11 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) packed = PACKED_PARTIAL; } - type = gfc_typenode_for_spec (&sym->ts); - type = gfc_get_nodesc_array_type (type, sym->as, packed, + /* For classarrays the element type is required, but + gfc_typenode_for_spec () returns the array descriptor. */ + type = is_classarray ? gfc_get_element_type (type) + : gfc_typenode_for_spec (&sym->ts); + type = gfc_get_nodesc_array_type (type, as, packed, !sym->attr.target); } else @@ -1110,7 +1133,7 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) /* We should never get deferred shape arrays here. We used to because of frontend bugs. */ - gcc_assert (sym->as->type != AS_DEFERRED); + gcc_assert (as->type != AS_DEFERRED); if (packed == PACKED_PARTIAL) GFC_DECL_PARTIAL_PACKED_ARRAY (decl) = 1; @@ -1429,13 +1452,30 @@ gfc_get_symbol_decl (gfc_symbol * sym) sym->backend_decl = decl; } + /* Returning the descriptor for dummy class arrays is hazardous, because + some caller is expecting an expression to apply the component refs to. + Therefore the descriptor is only created and stored in + sym->backend_decl's GFC_DECL_SAVED_DESCRIPTOR. The caller is then + responsible to extract it from there, when the descriptor is + desired. */ + if (IS_CLASS_ARRAY (sym) + && (!DECL_LANG_SPECIFIC (sym->backend_decl) + || !GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl))) + { + decl = gfc_build_dummy_array_decl (sym, sym->backend_decl); + /* Prevent the dummy from being detected as unused if it is copied. */ + if (sym->backend_decl != NULL && decl != sym->backend_decl) + DECL_ARTIFICIAL (sym->backend_decl) = 1; + sym->backend_decl = decl; + } + TREE_USED (sym->backend_decl) = 1; if (sym->attr.assign && GFC_DECL_ASSIGN (sym->backend_decl) == 0) { gfc_add_assign_aux_vars (sym); } - if (sym->attr.dimension + if ((sym->attr.dimension || IS_CLASS_ARRAY (sym)) && DECL_LANG_SPECIFIC (sym->backend_decl) && GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl) && DECL_CONTEXT (sym->backend_decl) != current_function_decl) @@ -3976,18 +4016,31 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) = gfc_class_set_static_fields (sym->backend_decl, vptr, tmp); TREE_CONSTANT (DECL_INITIAL (sym->backend_decl)) = 1; } - else if (sym->attr.dimension || sym->attr.codimension) + else if (sym->attr.dimension || sym->attr.codimension + || (IS_CLASS_ARRAY (sym) && !CLASS_DATA (sym)->attr.allocatable)) { - /* Assumed-size Cray pointees need to be treated as AS_EXPLICIT. */ - array_type tmp = sym->as->type; - if (tmp == AS_ASSUMED_SIZE && sym->as->cp_was_assumed) - tmp = AS_EXPLICIT; - switch (tmp) + bool is_classarray = IS_CLASS_ARRAY (sym); + symbol_attribute *array_attr; + gfc_array_spec *as; + array_type tmp; + + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; + /* Assumed-size Cray pointees need to be treated as AS_EXPLICIT. */ + tmp = as->type; + if (tmp == AS_ASSUMED_SIZE && as->cp_was_assumed) + tmp = AS_EXPLICIT; + switch (tmp) { case AS_EXPLICIT: if (sym->attr.dummy || sym->attr.result) gfc_trans_dummy_array_bias (sym, sym->backend_decl, block); - else if (sym->attr.pointer || sym->attr.allocatable) + /* Allocatable and pointer arrays need to processed + explicitly. */ + else if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS + && CLASS_DATA (sym)->attr.class_pointer) + || array_attr->allocatable) { if (TREE_STATIC (sym->backend_decl)) { @@ -4002,7 +4055,8 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) gfc_trans_deferred_array (sym, block); } } - else if (sym->attr.codimension && TREE_STATIC (sym->backend_decl)) + else if (sym->attr.codimension + && TREE_STATIC (sym->backend_decl)) { gfc_init_block (&tmpblock); gfc_trans_array_cobounds (TREE_TYPE (sym->backend_decl), @@ -4041,7 +4095,7 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) case AS_ASSUMED_SIZE: /* Must be a dummy parameter. */ - gcc_assert (sym->attr.dummy || sym->as->cp_was_assumed); + gcc_assert (sym->attr.dummy || as->cp_was_assumed); /* We should always pass assumed size arrays the g77 way. */ if (sym->attr.dummy) @@ -4103,6 +4157,7 @@ gfc_trans_deferred_vars (gfc_symbol * proc_sym, gfc_wrapped_block * block) } else { + se.descriptor_only = 1; gfc_conv_expr (&se, e); descriptor = se.expr; se.expr = gfc_conv_descriptor_data_addr (se.expr); diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index 88f1af8..81b72273 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -149,6 +149,11 @@ tree gfc_class_vptr_get (tree decl) { tree vptr; + /* For class arrays decl may be a temporary descriptor handle, the vptr is + then available through the saved descriptor. */ + if (TREE_CODE (decl) == VAR_DECL && DECL_LANG_SPECIFIC (decl) + && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); if (POINTER_TYPE_P (TREE_TYPE (decl))) decl = build_fold_indirect_ref_loc (input_location, decl); vptr = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (decl)), @@ -163,6 +168,11 @@ tree gfc_class_len_get (tree decl) { tree len; + /* For class arrays decl may be a temporary descriptor handle, the len is + then available through the saved descriptor. */ + if (TREE_CODE (decl) == VAR_DECL && DECL_LANG_SPECIFIC (decl) + && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); if (POINTER_TYPE_P (TREE_TYPE (decl))) decl = build_fold_indirect_ref_loc (input_location, decl); len = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (decl)), @@ -804,6 +814,16 @@ gfc_conv_intrinsic_to_class (gfc_se *parmse, gfc_expr *e, gfc_add_modify (&parmse->pre, ctree, tmp); } + else if (class_ts.type == BT_CLASS + && class_ts.u.derived->components + && class_ts.u.derived->components->ts.u + .derived->attr.unlimited_polymorphic) + { + ctree = gfc_class_len_get (var); + gfc_add_modify (&parmse->pre, ctree, + fold_convert (TREE_TYPE (ctree), + integer_zero_node)); + } /* Pass the address of the class object. */ parmse->expr = gfc_build_addr_expr (NULL_TREE, var); } @@ -830,6 +850,7 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts, tree tmp; tree vptr; tree cond = NULL_TREE; + tree slen = NULL_TREE; gfc_ref *ref; gfc_ref *class_ref; stmtblock_t block; @@ -921,7 +942,12 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts, tmp = NULL_TREE; if (class_ref == NULL && e->symtree && e->symtree->n.sym->ts.type == BT_CLASS) - tmp = e->symtree->n.sym->backend_decl; + { + tmp = e->symtree->n.sym->backend_decl; + if (DECL_LANG_SPECIFIC (tmp) && GFC_DECL_SAVED_DESCRIPTOR (tmp)) + tmp = GFC_DECL_SAVED_DESCRIPTOR (tmp); + slen = integer_zero_node; + } else { /* Remove everything after the last class reference, convert the @@ -933,6 +959,7 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts, gfc_conv_expr (&tmpse, e); class_ref->next = ref; tmp = tmpse.expr; + slen = tmpse.string_length; } gcc_assert (tmp != NULL_TREE); @@ -951,11 +978,38 @@ gfc_conv_class_to_class (gfc_se *parmse, gfc_expr *e, gfc_typespec class_ts, gfc_add_modify (&parmse->post, vptr, fold_convert (TREE_TYPE (vptr), ctree)); + /* For unlimited polymorphic objects also set the _len component. */ + if (class_ts.type == BT_CLASS + && class_ts.u.derived->components + && class_ts.u.derived->components->ts.u + .derived->attr.unlimited_polymorphic) + { + ctree = gfc_class_len_get (var); + if (UNLIMITED_POLY (e)) + tmp = gfc_class_len_get (tmp); + else if (e->ts.type == BT_CHARACTER) + { + gcc_assert (slen != NULL_TREE); + tmp = slen; + } + else + tmp = integer_zero_node; + gfc_add_modify (&parmse->pre, ctree, + fold_convert (TREE_TYPE (ctree), tmp)); + } + if (optional) { tree tmp2; cond = gfc_conv_expr_present (e->symtree->n.sym); + /* parmse->pre may contain some preparatory instructions for the + temporary array descriptor. Those may only be executed when the + optional argument is set, therefore add parmse->pre's instructions + to block, which is later guarded by an if (optional_arg_given). */ + gfc_add_block_to_block (&parmse->pre, &block); + block.head = parmse->pre.head; + parmse->pre.head = NULL_TREE; tmp = gfc_finish_block (&block); if (optional_alloc_ptr) @@ -1042,7 +1096,7 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems, bool unlimited) fcn_type = TREE_TYPE (TREE_TYPE (fcn)); if (from != NULL_TREE) - from_data = gfc_class_data_get (from); + from_data = gfc_class_data_get (from); else from_data = gfc_class_vtab_def_init_get (to); @@ -1099,7 +1153,8 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems, bool unlimited) gfc_init_block (&ifbody); gfc_add_block_to_block (&ifbody, &loop.pre); stdcopy = gfc_finish_block (&ifbody); - if (unlimited) + /* In initialization mode from_len is a constant zero. */ + if (unlimited && !integer_zerop (from_len)) { vec_safe_push (args, from_len); vec_safe_push (args, to_len); @@ -1141,7 +1196,8 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems, bool unlimited) vec_safe_push (args, to_data); stdcopy = build_call_vec (fcn_type, fcn, args); - if (unlimited) + /* In initialization mode from_len is a constant zero. */ + if (unlimited && !integer_zerop (from_len)) { vec_safe_push (args, from_len); vec_safe_push (args, to_len); @@ -1156,6 +1212,18 @@ gfc_copy_class_to_class (tree from, tree to, tree nelems, bool unlimited) tmp = stdcopy; } + /* Only copy _def_init to to_data, when it is not a NULL-pointer. */ + if (from == NULL_TREE) + { + tree cond; + cond = fold_build2_loc (input_location, NE_EXPR, + boolean_type_node, + from_data, null_pointer_node); + tmp = fold_build3_loc (input_location, COND_EXPR, + void_type_node, cond, + tmp, build_empty_stmt (input_location)); + } + return tmp; } @@ -1229,6 +1297,8 @@ gfc_trans_class_init_assign (gfc_code *code) been referenced. */ gfc_get_derived_type (rhs->ts.u.derived); gfc_add_def_init_component (rhs); + /* The _def_init is always scalar. */ + rhs->rank = 0; if (code->expr1->ts.type == BT_CLASS && CLASS_DATA (code->expr1)->attr.dimension) @@ -2203,6 +2273,16 @@ gfc_conv_component_ref (gfc_se * se, gfc_ref * ref) field = f2; } + if (ref->u.c.sym && ref->u.c.sym->ts.type == BT_CLASS + && strcmp ("_data", c->name) == 0) + { + /* Found a ref to the _data component. Store the associated ref to + the vptr in se->class_vptr. */ + se->class_vptr = gfc_class_vptr_get (decl); + } + else + se->class_vptr = NULL_TREE; + tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field), decl, field, NULL_TREE); @@ -2284,8 +2364,11 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) bool return_value; bool alternate_entry; bool entry_master; + bool is_classarray; + bool first_time = true; sym = expr->symtree->n.sym; + is_classarray = IS_CLASS_ARRAY (sym); ss = se->ss; if (ss != NULL) { @@ -2389,9 +2472,24 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) } else if (!sym->attr.value) { + /* Dereference temporaries for class array dummy arguments. */ + if (sym->attr.dummy && is_classarray + && GFC_ARRAY_TYPE_P (TREE_TYPE (se->expr))) + { + if (!se->descriptor_only) + se->expr = GFC_DECL_SAVED_DESCRIPTOR (se->expr); + + se->expr = build_fold_indirect_ref_loc (input_location, + se->expr); + } + /* Dereference non-character scalar dummy arguments. */ if (sym->attr.dummy && !sym->attr.dimension - && !(sym->attr.codimension && sym->attr.allocatable)) + && !(sym->attr.codimension && sym->attr.allocatable) + && (sym->ts.type != BT_CLASS + || (!CLASS_DATA (sym)->attr.dimension + && !(CLASS_DATA (sym)->attr.codimension + && CLASS_DATA (sym)->attr.allocatable)))) se->expr = build_fold_indirect_ref_loc (input_location, se->expr); @@ -2403,11 +2501,12 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) se->expr = build_fold_indirect_ref_loc (input_location, se->expr); - /* Dereference non-character pointer variables. + /* Dereference non-character, non-class pointer variables. These must be dummies, results, or scalars. */ - if ((sym->attr.pointer || sym->attr.allocatable - || gfc_is_associate_pointer (sym) - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) + if (!is_classarray + && (sym->attr.pointer || sym->attr.allocatable + || gfc_is_associate_pointer (sym) + || (sym->as && sym->as->type == AS_ASSUMED_RANK)) && (sym->attr.dummy || sym->attr.function || sym->attr.result @@ -2415,6 +2514,32 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) && (!sym->attr.codimension || !sym->attr.allocatable)))) se->expr = build_fold_indirect_ref_loc (input_location, se->expr); + /* Now treat the class array pointer variables accordingly. */ + else if (sym->ts.type == BT_CLASS + && sym->attr.dummy + && (CLASS_DATA (sym)->attr.dimension + || CLASS_DATA (sym)->attr.codimension) + && ((CLASS_DATA (sym)->as + && CLASS_DATA (sym)->as->type == AS_ASSUMED_RANK) + || CLASS_DATA (sym)->attr.allocatable + || CLASS_DATA (sym)->attr.class_pointer)) + se->expr = build_fold_indirect_ref_loc (input_location, + se->expr); + /* And the case where a non-dummy, non-result, non-function, + non-allotable and non-pointer classarray is present. This case was + previously covered by the first if, but with introducing the + condition !is_classarray there, that case has to be covered + explicitly. */ + else if (sym->ts.type == BT_CLASS + && !sym->attr.dummy + && !sym->attr.function + && !sym->attr.result + && (CLASS_DATA (sym)->attr.dimension + || CLASS_DATA (sym)->attr.codimension) + && !CLASS_DATA (sym)->attr.allocatable + && !CLASS_DATA (sym)->attr.class_pointer) + se->expr = build_fold_indirect_ref_loc (input_location, + se->expr); } ref = expr->ref; @@ -2452,6 +2577,18 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) break; case REF_COMPONENT: + if (first_time && is_classarray && sym->attr.dummy + && se->descriptor_only + && !CLASS_DATA (sym)->attr.allocatable + && !CLASS_DATA (sym)->attr.class_pointer + && CLASS_DATA (sym)->as + && CLASS_DATA (sym)->as->type != AS_ASSUMED_RANK + && strcmp ("_data", ref->u.c.component->name) == 0) + /* Skip the first ref of a _data component, because for class + arrays that one is already done by introducing a temporary + array descriptor. */ + break; + if (ref->u.c.sym->attr.extension) conv_parent_component_references (se, ref); @@ -2471,6 +2608,7 @@ gfc_conv_variable (gfc_se * se, gfc_expr * expr) gcc_unreachable (); break; } + first_time = false; ref = ref->next; } /* Pointer assignment, allocation or pass by reference. Arrays are handled @@ -4597,7 +4735,19 @@ gfc_conv_procedure_call (gfc_se * se, gfc_symbol * sym, gfc_init_se (&parmse, se); parm_kind = ELEMENTAL; - if (fsym && fsym->attr.value) + /* For all value functions or polymorphic scalar non-pointer + non-allocatable variables use the expression in e directly. This + ensures, that initializers of polymorphic entities are correctly + copied. */ + if (fsym && (fsym->attr.value + || (e->expr_type == EXPR_VARIABLE + && fsym->ts.type == BT_DERIVED + && e->ts.type == BT_DERIVED + && !e->ts.u.derived->attr.dimension + && !e->rank + && (!e->symtree + || (!e->symtree->n.sym->attr.allocatable + && !e->symtree->n.sym->attr.pointer))))) gfc_conv_expr (&parmse, e); else gfc_conv_expr_reference (&parmse, e); diff --git a/gcc/fortran/trans-intrinsic.c b/gcc/fortran/trans-intrinsic.c index c4ccb7b..20e5b37 100644 --- a/gcc/fortran/trans-intrinsic.c +++ b/gcc/fortran/trans-intrinsic.c @@ -5921,8 +5921,17 @@ gfc_conv_intrinsic_sizeof (gfc_se *se, gfc_expr *expr) } else if (arg->ts.type == BT_CLASS) { - if (arg->rank) + /* For deferred length arrays, conv_expr_descriptor returns an + indirect_ref to the component. */ + if (arg->rank < 0 + || (arg->rank > 0 && !VAR_P (argse.expr) + && GFC_DECL_CLASS (TREE_OPERAND (argse.expr, 0)))) byte_size = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0)); + else if (arg->rank > 0) + /* The scalarizer added an additional temp. To get the class' vptr + one has to look at the original backend_decl. */ + byte_size = gfc_class_vtab_size_get ( + GFC_DECL_SAVED_DESCRIPTOR (arg->symtree->n.sym->backend_decl)); else byte_size = gfc_class_vtab_size_get (argse.expr); } @@ -6053,7 +6062,11 @@ gfc_conv_intrinsic_storage_size (gfc_se *se, gfc_expr *expr) gfc_conv_expr_descriptor (&argse, arg); if (arg->ts.type == BT_CLASS) { - tmp = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0)); + if (arg->rank > 0) + tmp = gfc_class_vtab_size_get ( + GFC_DECL_SAVED_DESCRIPTOR (arg->symtree->n.sym->backend_decl)); + else + tmp = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0)); tmp = fold_convert (result_type, tmp); goto done; } @@ -7080,7 +7093,11 @@ gfc_conv_intrinsic_loc (gfc_se * se, gfc_expr * expr) arg_expr = expr->value.function.actual->expr; if (arg_expr->rank == 0) - gfc_conv_expr_reference (se, arg_expr); + { + if (arg_expr->ts.type == BT_CLASS) + gfc_add_component_ref (arg_expr, "_data"); + gfc_conv_expr_reference (se, arg_expr); + } else gfc_conv_array_parameter (se, arg_expr, true, NULL, NULL, NULL); se->expr = convert (gfc_get_int_type (gfc_index_integer_kind), se->expr); diff --git a/gcc/fortran/trans-stmt.c b/gcc/fortran/trans-stmt.c index 619564b..88dd31f 100644 --- a/gcc/fortran/trans-stmt.c +++ b/gcc/fortran/trans-stmt.c @@ -1260,12 +1260,29 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) gfc_init_se (&se, NULL); se.descriptor_only = 1; - gfc_conv_expr (&se, e); + /* In a select type the (temporary) associate variable shall point to + a standard fortran array (lower bound == 1), but conv_expr () + just maps to the input array in the class object, whose lbound may + be arbitrary. conv_expr_descriptor solves this by inserting a + temporary array descriptor. */ + gfc_conv_expr_descriptor (&se, e); - gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se.expr))); + gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se.expr)) + || GFC_ARRAY_TYPE_P (TREE_TYPE (se.expr))); gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (sym->backend_decl))); - gfc_add_modify (&se.pre, sym->backend_decl, se.expr); + if (GFC_ARRAY_TYPE_P (TREE_TYPE (se.expr))) + { + if (INDIRECT_REF_P (se.expr)) + tmp = TREE_OPERAND (se.expr, 0); + else + tmp = se.expr; + + gfc_add_modify (&se.pre, sym->backend_decl, + gfc_class_data_get (GFC_DECL_SAVED_DESCRIPTOR (tmp))); + } + else + gfc_add_modify (&se.pre, sym->backend_decl, se.expr); if (unlimited) { @@ -1276,7 +1293,7 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) gfc_get_dtype (TREE_TYPE (sym->backend_decl))); } - gfc_add_init_cleanup (block, gfc_finish_block( &se.pre), + gfc_add_init_cleanup (block, gfc_finish_block (&se.pre), gfc_finish_block (&se.post)); } @@ -1319,9 +1336,18 @@ trans_associate_var (gfc_symbol *sym, gfc_wrapped_block *block) } if (need_len_assign) { - /* Get the _len comp from the target expr by stripping _data - from it and adding component-ref to _len. */ - tmp = gfc_class_len_get (TREE_OPERAND (target_expr, 0)); + if (e->symtree + && DECL_LANG_SPECIFIC (e->symtree->n.sym->backend_decl) + && GFC_DECL_SAVED_DESCRIPTOR (e->symtree->n.sym->backend_decl)) + /* Use the original class descriptor stored in the saved + descriptor to get the target_expr. */ + target_expr = + GFC_DECL_SAVED_DESCRIPTOR (e->symtree->n.sym->backend_decl); + else + /* Strip the _data component from the target_expr. */ + target_expr = TREE_OPERAND (target_expr, 0); + /* Add a reference to the _len comp to the target expr. */ + tmp = gfc_class_len_get (target_expr); /* Get the component-ref for the temp structure's _len comp. */ charlen = gfc_class_len_get (se.expr); /* Add the assign to the beginning of the the block... */ diff --git a/gcc/fortran/trans-types.c b/gcc/fortran/trans-types.c index 708289f..b9f662d 100644 --- a/gcc/fortran/trans-types.c +++ b/gcc/fortran/trans-types.c @@ -1288,25 +1288,35 @@ gfc_get_element_type (tree type) int gfc_is_nodesc_array (gfc_symbol * sym) { - gcc_assert (sym->attr.dimension || sym->attr.codimension); + symbol_attribute *array_attr; + gfc_array_spec *as; + bool is_classarray = IS_CLASS_ARRAY (sym); + + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; + + gcc_assert (array_attr->dimension || array_attr->codimension); /* We only want local arrays. */ - if (sym->attr.pointer || sym->attr.allocatable) + if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) + || array_attr->allocatable) return 0; /* We want a descriptor for associate-name arrays that do not have an - explicitly known shape already. */ - if (sym->assoc && sym->as->type != AS_EXPLICIT) + explicitly known shape already. */ + if (sym->assoc && as->type != AS_EXPLICIT) return 0; + /* The dummy is stored in sym and not in the component. */ if (sym->attr.dummy) - return sym->as->type != AS_ASSUMED_SHAPE - && sym->as->type != AS_ASSUMED_RANK; + return as->type != AS_ASSUMED_SHAPE + && as->type != AS_ASSUMED_RANK; if (sym->attr.result || sym->attr.function) return 0; - gcc_assert (sym->as->type == AS_EXPLICIT || sym->as->cp_was_assumed); + gcc_assert (as->type == AS_EXPLICIT || as->cp_was_assumed); return 1; } diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c index b7ec0e5..6da464a 100644 --- a/gcc/fortran/trans.c +++ b/gcc/fortran/trans.c @@ -321,7 +321,7 @@ gfc_build_addr_expr (tree type, tree t) /* Build an ARRAY_REF with its natural type. */ tree -gfc_build_array_ref (tree base, tree offset, tree decl) +gfc_build_array_ref (tree base, tree offset, tree decl, tree vptr) { tree type = TREE_TYPE (base); tree tmp; @@ -353,30 +353,47 @@ gfc_build_array_ref (tree base, tree offset, tree decl) /* If the array reference is to a pointer, whose target contains a subreference, use the span that is stored with the backend decl and reference the element with pointer arithmetic. */ - if (decl && (TREE_CODE (decl) == FIELD_DECL - || TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == PARM_DECL) - && ((GFC_DECL_SUBREF_ARRAY_P (decl) - && !integer_zerop (GFC_DECL_SPAN(decl))) + if ((decl && (TREE_CODE (decl) == FIELD_DECL + || TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == PARM_DECL) + && ((GFC_DECL_SUBREF_ARRAY_P (decl) + && !integer_zerop (GFC_DECL_SPAN (decl))) || GFC_DECL_CLASS (decl))) + || vptr) { - if (GFC_DECL_CLASS (decl)) + if (decl) { - /* Allow for dummy arguments and other good things. */ - if (POINTER_TYPE_P (TREE_TYPE (decl))) - decl = build_fold_indirect_ref_loc (input_location, decl); - - /* Check if '_data' is an array descriptor. If it is not, - the array must be one of the components of the class object, - so return a normal array reference. */ - if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (gfc_class_data_get (decl)))) - return build4_loc (input_location, ARRAY_REF, type, base, - offset, NULL_TREE, NULL_TREE); - - span = gfc_class_vtab_size_get (decl); + if (GFC_DECL_CLASS (decl)) + { + /* When a temporary is in place for the class array, then the + original class' declaration is stored in the saved + descriptor. */ + if (DECL_LANG_SPECIFIC (decl) && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); + else + { + /* Allow for dummy arguments and other good things. */ + if (POINTER_TYPE_P (TREE_TYPE (decl))) + decl = build_fold_indirect_ref_loc (input_location, decl); + + /* Check if '_data' is an array descriptor. If it is not, + the array must be one of the components of the class + object, so return a normal array reference. */ + if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE ( + gfc_class_data_get (decl)))) + return build4_loc (input_location, ARRAY_REF, type, base, + offset, NULL_TREE, NULL_TREE); + } + + span = gfc_class_vtab_size_get (decl); + } + else if (GFC_DECL_SUBREF_ARRAY_P (decl)) + span = GFC_DECL_SPAN (decl); + else + gcc_unreachable (); } - else if (GFC_DECL_SUBREF_ARRAY_P (decl)) - span = GFC_DECL_SPAN(decl); + else if (vptr) + span = gfc_vptr_size_get (vptr); else gcc_unreachable (); diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h index 1998358..e2a1fea 100644 --- a/gcc/fortran/trans.h +++ b/gcc/fortran/trans.h @@ -49,6 +49,10 @@ typedef struct gfc_se /* The length of a character string value. */ tree string_length; + /* When expr is a reference to a class object, store its vptr access + here. */ + tree class_vptr; + /* If set gfc_conv_variable will return an expression for the array descriptor. When set, want_pointer should also be set. If not set scalarizing variables will be substituted. */ @@ -528,7 +532,7 @@ tree gfc_get_function_decl (gfc_symbol *); tree gfc_build_addr_expr (tree, tree); /* Build an ARRAY_REF. */ -tree gfc_build_array_ref (tree, tree, tree); +tree gfc_build_array_ref (tree, tree, tree, tree vptr = NULL_TREE); /* Creates a label. Decl is artificial if label_id == NULL_TREE. */ tree gfc_build_label_decl (tree); diff --git a/gcc/testsuite/gfortran.dg/class_allocate_19.f03 b/gcc/testsuite/gfortran.dg/class_allocate_19.f03 new file mode 100644 index 0000000..719be3e --- /dev/null +++ b/gcc/testsuite/gfortran.dg/class_allocate_19.f03 @@ -0,0 +1,47 @@ +! { dg-do run } +! +! Contributed by: Vladimir Fuka <vladimir.fuka@gmail.com> + +use iso_c_binding +implicit none +real, target :: e +class(*), allocatable, target :: a(:) +e = 1.0 +call add_element_poly(a,e) +if (size(a) /= 1) call abort() +call add_element_poly(a,e) +if (size(a) /= 2) call abort() +select type (a) + type is (real) + if (any (a /= [ 1, 1])) call abort() +end select +contains + subroutine add_element_poly(a,e) + use iso_c_binding + class(*),allocatable,intent(inout),target :: a(:) + class(*),intent(in),target :: e + class(*),allocatable,target :: tmp(:) + type(c_ptr) :: dummy + + interface + function memcpy(dest,src,n) bind(C,name="memcpy") result(res) + import + type(c_ptr) :: res + integer(c_intptr_t),value :: dest + integer(c_intptr_t),value :: src + integer(c_size_t),value :: n + end function + end interface + + if (.not.allocated(a)) then + allocate(a(1), source=e) + else + allocate(tmp(size(a)),source=a) + deallocate(a) + allocate(a(size(tmp)+1),mold=e) + dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) + dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) + end if + end subroutine +end + diff --git a/gcc/testsuite/gfortran.dg/class_array_20.f03 b/gcc/testsuite/gfortran.dg/class_array_20.f03 new file mode 100644 index 0000000..c49f7d2 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/class_array_20.f03 @@ -0,0 +1,100 @@ +! {dg-do run} +! +! Test contributed by Thomas L. Clune via pr60322 +! and Antony Lewis via pr64692 + +program class_array_20 + implicit none + + type Foo + end type + + type(foo), dimension(2:3) :: arg + integer :: oneDarr(2) + integer :: twoDarr(2,3) + integer :: x, y + double precision :: P(2, 2) + + ! Checking for PR/60322 + call copyFromClassArray([Foo(), Foo()]) + call copyFromClassArray(arg) + call copyFromClassArray(arg(:)) + + x= 3 + y= 4 + oneDarr = [x, y] + call W([x, y]) + call W(oneDarr) + call W([3, 4]) + + twoDarr = reshape([3, 4, 5, 5, 6, 7], [2, 3]) + call WtwoD(twoDarr) + call WtwoD(reshape([3, 4, 5, 5, 6, 7], [2, 3])) + + ! Checking for PR/64692 + P(1:2, 1) = [1.d0, 2.d0] + P(1:2, 2) = [3.d0, 4.d0] + call AddArray(P(1:2, 2)) + +contains + + subroutine copyFromClassArray(classarray) + class (Foo), intent(in) :: classarray(:) + + if (lbound(classarray, 1) .ne. 1) call abort() + if (ubound(classarray, 1) .ne. 2) call abort() + if (size(classarray) .ne. 2) call abort() + end subroutine + + subroutine AddArray(P) + class(*), target, intent(in) :: P(:) + class(*), pointer :: Pt(:) + + allocate(Pt(1:size(P)), source= P) + + select type (P) + type is (double precision) + if (abs(P(1)-3.d0) .gt. 1.d-8) call abort() + if (abs(P(2)-4.d0) .gt. 1.d-8) call abort() + class default + call abort() + end select + + select type (Pt) + type is (double precision) + if (abs(Pt(1)-3.d0) .gt. 1.d-8) call abort() + if (abs(Pt(2)-4.d0) .gt. 1.d-8) call abort() + class default + call abort() + end select + end subroutine + + subroutine W(ar) + class(*), intent(in) :: ar(:) + + if (lbound(ar, 1) /= 1) call abort() + select type (ar) + type is (integer) + ! The indeces 1:2 are essential here, or else one would not + ! note, that the array internally starts at 0, although the + ! check for the lbound above went fine. + if (any (ar(1:2) .ne. [3, 4])) call abort() + class default + call abort() + end select + end subroutine + + subroutine WtwoD(ar) + class(*), intent(in) :: ar(:,:) + + if (any (lbound(ar) /= [1, 1])) call abort() + select type (ar) + type is (integer) + if (any (reshape(ar(1:2,1:3), [6]) .ne. [3, 4, 5, 5, 6, 7])) & + call abort() + class default + call abort() + end select + end subroutine +end program class_array_20 + diff --git a/gcc/testsuite/gfortran.dg/class_array_21.f03 b/gcc/testsuite/gfortran.dg/class_array_21.f03 new file mode 100644 index 0000000..1e89d38 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/class_array_21.f03 @@ -0,0 +1,97 @@ +! {dg-do run} +! +! Contributed by Andre Vehreschild +! Check more elaborate class array addressing. + +module m1 + + type InnerBaseT + integer, allocatable :: a(:) + end type InnerBaseT + + type, extends(InnerBaseT) :: InnerT + integer :: i + end type InnerT + + type BaseT + class(InnerT), allocatable :: arr(:,:) + contains + procedure P + end type BaseT + +contains + + subroutine indir(this, mat) + class(BaseT) :: this + class(InnerT), intent(inout) :: mat(:,:) + + call this%P(mat) + end subroutine indir + + subroutine P(this, mat) + class(BaseT) :: this + class(InnerT), intent(inout) :: mat(:,:) + integer :: i,j + + mat%i = 42 + do i= 1, ubound(mat, 1) + do j= 1, ubound(mat, 2) + if (.not. allocated(mat(i,j)%a)) then + allocate(mat(i,j)%a(10), source = 72) + end if + end do + end do + mat(1,1)%i = 9 + mat(1,1)%a(5) = 1 + end subroutine + +end module m1 + +program test + use m1 + + class(BaseT), allocatable, target :: o + class(InnerT), pointer :: i_p(:,:) + class(InnerBaseT), allocatable :: i_a(:,:) + integer i,j,l + + allocate(o) + allocate(o%arr(2,2)) + allocate(InnerT::i_a(2,2)) + o%arr%i = 1 + + i_p => o%arr + call o%P(i_p) + if (any(o%arr%i /= reshape([9,42,42,42],[2,2]))) call abort() + do l= 1, 10 + do i= 1, 2 + do j= 1,2 + if ((i == 1 .and. j == 1 .and. l == 5 .and. & + o%arr(i,j)%a(5) /= 1) & + .or. (.not. (i == 1 .and. j == 1 .and. l == 5) & + .and. o%arr(i,j)%a(l) /= 72)) call abort() + end do + end do + end do + + select type (i_a) + type is (InnerT) + call o%P(i_a) + do l= 1, 10 + do i= 1, 2 + do j= 1,2 + if ((i == 1 .and. j == 1 .and. l == 5 .and. & + i_a(i,j)%a(5) /= 1) & + .or. (.not. (i == 1 .and. j == 1 .and. l == 5) & + .and. i_a(i,j)%a(l) /= 72)) call abort() + end do + end do + end do + end select + + i_p%i = 4 + call indir(o, i_p) + if (any(o%arr%i /= reshape([9,42,42,42],[2,2]))) call abort() +end program test + +! vim:ts=2:sts=2:cindent:sw=2:tw=80: diff --git a/gcc/testsuite/gfortran.dg/finalize_10.f90 b/gcc/testsuite/gfortran.dg/finalize_10.f90 index e042f11..32386ce 100644 --- a/gcc/testsuite/gfortran.dg/finalize_10.f90 +++ b/gcc/testsuite/gfortran.dg/finalize_10.f90 @@ -27,8 +27,8 @@ end subroutine foo ! Finalize CLASS + set default init ! { dg-final { scan-tree-dump-times "y->_vptr->_final \\(&desc.\[0-9\]+, y->_vptr->_size, 0\\);" 1 "original" } } ! { dg-final { scan-tree-dump "__builtin_memcpy \\(\\(void .\\) y->_data, \\(void .\\) y->_vptr->_def_init, \\((unsigned long|unsigned int|character\\(kind=4\\))\\) y->_vptr->_size\\);" "original" } } -! { dg-final { scan-tree-dump-times "x->_vptr->_final \\(&x->_data, x->_vptr->_size, 0\\);" 1 "original" } } -! { dg-final { scan-tree-dump-times "x->_vptr->_copy \\(x->_vptr->_def_init, &x->_data\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times "x->_vptr->_final \\(&parm.\[0-9\]+, x->_vptr->_size, 0\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times "x->_vptr->_copy \\(" 1 "original" } } ! FINALIZE TYPE: ! { dg-final { scan-tree-dump-times "parm.\[0-9\]+.data = \\(void \\*\\) &\\(\\*aa.\[0-9\]+\\)\\\[0\\\];" 1 "original" } } diff --git a/gcc/testsuite/gfortran.dg/finalize_15.f90 b/gcc/testsuite/gfortran.dg/finalize_15.f90 index 3c18b2a..d5ba28f 100644 --- a/gcc/testsuite/gfortran.dg/finalize_15.f90 +++ b/gcc/testsuite/gfortran.dg/finalize_15.f90 @@ -9,37 +9,37 @@ module m implicit none type t1 - integer :: i + integer :: i = 1 contains final :: fini_elem end type t1 type, extends(t1) :: t1e - integer :: j + integer :: j = 11 contains final :: fini_elem2 end type t1e type t2 - integer :: i + integer :: i = 2 contains final :: fini_shape end type t2 type, extends(t2) :: t2e - integer :: j + integer :: j = 22 contains final :: fini_shape2 end type t2e type t3 - integer :: i + integer :: i = 3 contains final :: fini_explicit end type t3 type, extends(t3) :: t3e - integer :: j + integer :: j = 33 contains final :: fini_explicit2 end type t3e @@ -204,31 +204,31 @@ program test select type(x) type is (t1e) - call check_val(x%i, 1) - call check_val(x%j, 100) + call check_val(x%i, 1, 1) + call check_val(x%j, 100, 11) end select select type(y) type is (t2e) - call check_val(y%i, 1) - call check_val(y%j, 100) + call check_val(y%i, 1, 2) + call check_val(y%j, 100, 22) end select select type(z) type is (t3e) - call check_val(z%i, 1) - call check_val(z%j, 100) + call check_val(z%i, 1, 3) + call check_val(z%j, 100, 33) end select contains - subroutine check_val(x, factor) + subroutine check_val(x, factor, val) integer :: x(:,:) - integer, value :: factor + integer, value :: factor, val integer :: i, j do i = 1, 10 do j = 1, 10 if (mod (j-1, 2) == 0 .and. mod (i-1, 3) == 0) then - if (x(j,i) /= (j + 100*i)*factor*(-13)) call abort () + if (x(j,i) /= val) call abort () else if (x(j,i) /= (j + 100*i)*factor) call abort () end if diff --git a/gcc/testsuite/gfortran.dg/finalize_29.f08 b/gcc/testsuite/gfortran.dg/finalize_29.f08 new file mode 100644 index 0000000..1f5f7424 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/finalize_29.f08 @@ -0,0 +1,289 @@ +! {dg-do run} +! +! Testcase contributed by Andre Vehreschild <vehre@gcc.gnu.org> + +module module_finalize_29 + implicit none + + ! The type name is encoding the state of its finalizer being + ! elemental (second letter 'e'), or non-element (second letter 'n') + ! or array shaped (second letter 'a'), or shape-specific routine + ! (generic; second letter 'g'), + ! and whether the init-routine is elemental or not (third letter + ! either 'e' or 'n'). + type ten + integer :: i = 40 + contains + final :: ten_fin + end type ten + + type tee + integer :: i = 41 + contains + final :: tee_fin + end type tee + + type tne + integer :: i = 42 + contains + final :: tne_fin + end type tne + + type tnn + integer :: i = 43 + contains + final :: tnn_fin + end type tnn + + type tae + integer :: i = 44 + contains + final :: tae_fin + end type tae + + type tan + integer :: i = 45 + contains + final :: tan_fin + end type tan + + type tge + integer :: i = 46 + contains + final :: tge_scalar_fin, tge_array_fin + end type tge + + type tgn + integer :: i = 47 + contains + final :: tgn_scalar_fin, tgn_array_fin + end type tgn + + integer :: ten_fin_counts, tee_fin_counts, tne_fin_counts, tnn_fin_counts + integer :: tae_fin_counts, tan_fin_counts + integer :: tge_scalar_fin_counts, tge_array_fin_counts + integer :: tgn_scalar_fin_counts, tgn_array_fin_counts +contains + impure elemental subroutine ten_fin(x) + type(ten), intent(inout) :: x + x%i = -10 * x%i + ten_fin_counts = ten_fin_counts + 1 + end subroutine ten_fin + + impure elemental subroutine tee_fin(x) + type(tee), intent(inout) :: x + x%i = -11 * x%i + tee_fin_counts = tee_fin_counts + 1 + end subroutine tee_fin + + subroutine tne_fin(x) + type(tne), intent(inout) :: x + x%i = -12 * x%i + tne_fin_counts = tne_fin_counts + 1 + end subroutine tne_fin + + subroutine tnn_fin(x) + type(tnn), intent(inout) :: x + x%i = -13 * x%i + tnn_fin_counts = tnn_fin_counts + 1 + end subroutine tnn_fin + + subroutine tae_fin(x) + type(tae), intent(inout) :: x(:,:) + x%i = -14 * x%i + tae_fin_counts = tae_fin_counts + 1 + end subroutine tae_fin + + subroutine tan_fin(x) + type(tan), intent(inout) :: x(:,:) + x%i = -15 * x%i + tan_fin_counts = tan_fin_counts + 1 + end subroutine tan_fin + + subroutine tge_scalar_fin(x) + type(tge), intent(inout) :: x + x%i = -16 * x%i + tge_scalar_fin_counts = tge_scalar_fin_counts + 1 + end subroutine tge_scalar_fin + + subroutine tge_array_fin(x) + type(tge), intent(inout) :: x(:,:) + x%i = -17 * x%i + tge_array_fin_counts = tge_array_fin_counts + 1 + end subroutine tge_array_fin + + subroutine tgn_scalar_fin(x) + type(tgn), intent(inout) :: x + x%i = -18 * x%i + tgn_scalar_fin_counts = tgn_scalar_fin_counts + 1 + end subroutine tgn_scalar_fin + + subroutine tgn_array_fin(x) + type(tgn), intent(inout) :: x(:,:) + x%i = -19 * x%i + tgn_array_fin_counts = tgn_array_fin_counts + 1 + end subroutine tgn_array_fin + + ! The finalizer/initializer call producer + subroutine ten_init(x) + class(ten), intent(out) :: x(:,:) + end subroutine ten_init + + impure elemental subroutine tee_init(x) + class(tee), intent(out) :: x + end subroutine tee_init + + impure elemental subroutine tne_init(x) + class(tne), intent(out) :: x + end subroutine tne_init + + subroutine tnn_init(x) + class(tnn), intent(out) :: x(:,:) + end subroutine tnn_init + + impure elemental subroutine tae_init(x) + class(tae), intent(out) :: x + end subroutine tae_init + + subroutine tan_init(x) + class(tan), intent(out) :: x(:,:) + end subroutine tan_init + + impure elemental subroutine tge_init(x) + class(tge), intent(out) :: x + end subroutine tge_init + + subroutine tgn_init(x) + class(tgn), intent(out) :: x(:,:) + end subroutine tgn_init +end module module_finalize_29 + +program finalize_29 + use module_finalize_29 + implicit none + + type(ten), allocatable :: x_ten(:,:) + type(tee), allocatable :: x_tee(:,:) + type(tne), allocatable :: x_tne(:,:) + type(tnn), allocatable :: x_tnn(:,:) + type(tae), allocatable :: x_tae(:,:) + type(tan), allocatable :: x_tan(:,:) + type(tge), allocatable :: x_tge(:,:) + type(tgn), allocatable :: x_tgn(:,:) + + ! Set the global counts to zero. + ten_fin_counts = 0 + tee_fin_counts = 0 + tne_fin_counts = 0 + tnn_fin_counts = 0 + tae_fin_counts = 0 + tan_fin_counts = 0 + tge_scalar_fin_counts = 0 + tge_array_fin_counts = 0 + tgn_scalar_fin_counts = 0 + tgn_array_fin_counts = 0 + + allocate(ten :: x_ten(5,5)) + allocate(tee :: x_tee(5,5)) + allocate(tne :: x_tne(5,5)) + allocate(tnn :: x_tnn(5,5)) + allocate(tae :: x_tae(5,5)) + allocate(tan :: x_tan(5,5)) + allocate(tge :: x_tge(5,5)) + allocate(tgn :: x_tgn(5,5)) + + x_ten%i = 1 + x_tee%i = 2 + x_tne%i = 3 + x_tnn%i = 4 + x_tae%i = 5 + x_tan%i = 6 + x_tge%i = 7 + x_tgn%i = 8 + + call ten_init(x_ten(::2, ::3)) + + if (ten_fin_counts /= 6) call abort() + if (tee_fin_counts + tne_fin_counts + tnn_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + ten_fin_counts = 0 + + call tee_init(x_tee(::2, ::3)) + + if (tee_fin_counts /= 6) call abort() + if (ten_fin_counts + tne_fin_counts + tnn_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tee_fin_counts = 0 + + call tne_init(x_tne(::2, ::3)) + + if (tne_fin_counts /= 6) call abort() + if (ten_fin_counts + tee_fin_counts + tnn_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tne_fin_counts = 0 + + call tnn_init(x_tnn(::2, ::3)) + + if (tnn_fin_counts /= 0) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + + call tae_init(x_tae(::2, ::3)) + + if (tae_fin_counts /= 0) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + + call tan_init(x_tan(::2, ::3)) + + if (tan_fin_counts /= 1) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tae_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tan_fin_counts = 0 + + call tge_init(x_tge(::2, ::3)) + + if (tge_scalar_fin_counts /= 6) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tae_fin_counts + tan_fin_counts + tgn_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tge_scalar_fin_counts = 0 + + call tgn_init(x_tgn(::2, ::3)) + + if (tgn_array_fin_counts /= 1) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tae_fin_counts + tan_fin_counts + tge_scalar_fin_counts + & + tge_array_fin_counts + tgn_scalar_fin_counts /= 0) call abort() + tgn_array_fin_counts = 0 + + if (any (reshape (x_ten%i, [25]) /= [[40, 1, 40, 1, 40], [1, 1, 1, 1, 1],& + [1, 1, 1, 1, 1], [40, 1, 40, 1, 40], [1, 1, 1, 1, 1]])) call abort() + + if (any (reshape (x_tee%i, [25]) /= [[41, 2, 41, 2, 41], [2, 2, 2, 2, 2],& + [2, 2, 2, 2, 2], [41, 2, 41, 2, 41], [2, 2, 2, 2, 2]])) call abort() + + if (any (reshape (x_tne%i, [25]) /= [[42, 3, 42, 3, 42], [3, 3, 3, 3, 3],& + [3, 3, 3, 3, 3], [42, 3, 42, 3, 42], [3, 3, 3, 3, 3]])) call abort() + + if (any (reshape (x_tnn%i, [25]) /= [[43, 4, 43, 4, 43], [4, 4, 4, 4, 4],& + [4, 4, 4, 4, 4], [43, 4, 43, 4, 43], [4, 4, 4, 4, 4]])) call abort() + + if (any (reshape (x_tae%i, [25]) /= [[44, 5, 44, 5, 44], [5, 5, 5, 5, 5],& + [5, 5, 5, 5, 5], [44, 5, 44, 5, 44], [5, 5, 5, 5, 5]])) call abort() + + if (any (reshape (x_tan%i, [25]) /= [[45, 6, 45, 6, 45], [6, 6, 6, 6, 6],& + [6, 6, 6, 6, 6], [45, 6, 45, 6, 45], [6, 6, 6, 6, 6]])) call abort() + + if (any (reshape (x_tge%i, [25]) /= [[46, 7, 46, 7, 46], [7, 7, 7, 7, 7],& + [7, 7, 7, 7, 7], [46, 7, 46, 7, 46], [7, 7, 7, 7, 7]])) call abort() + + if (any (reshape (x_tgn%i, [25]) /= [[47, 8, 47, 8, 47], [8, 8, 8, 8, 8],& + [8, 8, 8, 8, 8], [47, 8, 47, 8, 47], [8, 8, 8, 8, 8]])) call abort() +end program finalize_29 [-- Attachment #4: pr60322_full_delta_5_to_6.patch --] [-- Type: text/x-patch, Size: 10203 bytes --] diff --git a/gcc/fortran/trans-array.c b/gcc/fortran/trans-array.c index 0804d45..3803cf8 100644 --- a/gcc/fortran/trans-array.c +++ b/gcc/fortran/trans-array.c @@ -3165,7 +3165,7 @@ add_to_offset (tree *cst_offset, tree *offset, tree t) static tree -build_array_ref (tree desc, tree offset, tree decl) +build_array_ref (tree desc, tree offset, tree decl, tree vptr) { tree tmp; tree type; @@ -3212,7 +3212,7 @@ build_array_ref (tree desc, tree offset, tree decl) tmp = gfc_conv_array_data (desc); tmp = build_fold_indirect_ref_loc (input_location, tmp); - tmp = gfc_build_array_ref (tmp, offset, decl); + tmp = gfc_build_array_ref (tmp, offset, decl, vptr); return tmp; } @@ -3375,7 +3375,8 @@ gfc_conv_array_ref (gfc_se * se, gfc_array_ref * ar, gfc_expr *expr, offset = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type, offset, cst_offset); - se->expr = build_array_ref (se->expr, offset, sym->backend_decl); + se->expr = build_array_ref (se->expr, offset, sym->ts.type == BT_CLASS ? + NULL_TREE : sym->backend_decl, se->class_vptr); } @@ -6270,7 +6271,7 @@ gfc_get_dataptr_offset (stmtblock_t *block, tree parm, tree desc, tree offset, return; } - tmp = build_array_ref (desc, offset, NULL); + tmp = build_array_ref (desc, offset, NULL, NULL); /* Offset the data pointer for pointer assignments from arrays with subreferences; e.g. my_integer => my_type(:)%integer_component. */ @@ -7029,6 +7030,8 @@ gfc_conv_expr_descriptor (gfc_se *se, gfc_expr *expr) pointer/allocatable or associated. */ if (onebased && se->use_offset && expr->symtree + && !(expr->symtree->n.sym && expr->symtree->n.sym->ts.type == BT_CLASS + && !CLASS_DATA (expr->symtree->n.sym)->attr.class_pointer) && !expr->symtree->n.sym->attr.allocatable && !expr->symtree->n.sym->attr.pointer && !expr->symtree->n.sym->attr.host_assoc diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c index 895733b..4c18920 100644 --- a/gcc/fortran/trans-decl.c +++ b/gcc/fortran/trans-decl.c @@ -1031,9 +1031,9 @@ gfc_build_dummy_array_decl (gfc_symbol * sym, tree dummy) array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; /* The dummy is returned for pointer, allocatable or assumed rank arrays. - The check for pointerness needs to be repeated here (it is done in - IS_CLASS_ARRAY (), too), because for class arrays that are pointers, as - is the one of the sym, which is incorrect here. */ + For class arrays the information if sym is an allocatable or pointer + object needs to be checked explicitly (IS_CLASS_ARRAY can be false for + too many reasons to be of use here). */ if ((sym->ts.type != BT_CLASS && sym->attr.pointer) || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) || array_attr->allocatable diff --git a/gcc/fortran/trans-expr.c b/gcc/fortran/trans-expr.c index 790d537..81b72273 100644 --- a/gcc/fortran/trans-expr.c +++ b/gcc/fortran/trans-expr.c @@ -2273,6 +2273,16 @@ gfc_conv_component_ref (gfc_se * se, gfc_ref * ref) field = f2; } + if (ref->u.c.sym && ref->u.c.sym->ts.type == BT_CLASS + && strcmp ("_data", c->name) == 0) + { + /* Found a ref to the _data component. Store the associated ref to + the vptr in se->class_vptr. */ + se->class_vptr = gfc_class_vptr_get (decl); + } + else + se->class_vptr = NULL_TREE; + tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field), decl, field, NULL_TREE); diff --git a/gcc/fortran/trans.c b/gcc/fortran/trans.c index 394745e..6da464a 100644 --- a/gcc/fortran/trans.c +++ b/gcc/fortran/trans.c @@ -321,7 +321,7 @@ gfc_build_addr_expr (tree type, tree t) /* Build an ARRAY_REF with its natural type. */ tree -gfc_build_array_ref (tree base, tree offset, tree decl) +gfc_build_array_ref (tree base, tree offset, tree decl, tree vptr) { tree type = TREE_TYPE (base); tree tmp; @@ -353,37 +353,47 @@ gfc_build_array_ref (tree base, tree offset, tree decl) /* If the array reference is to a pointer, whose target contains a subreference, use the span that is stored with the backend decl and reference the element with pointer arithmetic. */ - if (decl && (TREE_CODE (decl) == FIELD_DECL - || TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == PARM_DECL) - && ((GFC_DECL_SUBREF_ARRAY_P (decl) - && !integer_zerop (GFC_DECL_SPAN(decl))) + if ((decl && (TREE_CODE (decl) == FIELD_DECL + || TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == PARM_DECL) + && ((GFC_DECL_SUBREF_ARRAY_P (decl) + && !integer_zerop (GFC_DECL_SPAN (decl))) || GFC_DECL_CLASS (decl))) + || vptr) { - if (GFC_DECL_CLASS (decl)) + if (decl) { - /* When a temporary is in place for the class array, then the original - class' declaration is stored in the saved descriptor. */ - if (DECL_LANG_SPECIFIC (decl) && GFC_DECL_SAVED_DESCRIPTOR (decl)) - decl = GFC_DECL_SAVED_DESCRIPTOR (decl); - else + if (GFC_DECL_CLASS (decl)) { - /* Allow for dummy arguments and other good things. */ - if (POINTER_TYPE_P (TREE_TYPE (decl))) - decl = build_fold_indirect_ref_loc (input_location, decl); - - /* Check if '_data' is an array descriptor. If it is not, - the array must be one of the components of the class object, - so return a normal array reference. */ - if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (gfc_class_data_get (decl)))) - return build4_loc (input_location, ARRAY_REF, type, base, - offset, NULL_TREE, NULL_TREE); + /* When a temporary is in place for the class array, then the + original class' declaration is stored in the saved + descriptor. */ + if (DECL_LANG_SPECIFIC (decl) && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); + else + { + /* Allow for dummy arguments and other good things. */ + if (POINTER_TYPE_P (TREE_TYPE (decl))) + decl = build_fold_indirect_ref_loc (input_location, decl); + + /* Check if '_data' is an array descriptor. If it is not, + the array must be one of the components of the class + object, so return a normal array reference. */ + if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE ( + gfc_class_data_get (decl)))) + return build4_loc (input_location, ARRAY_REF, type, base, + offset, NULL_TREE, NULL_TREE); + } + + span = gfc_class_vtab_size_get (decl); } - - span = gfc_class_vtab_size_get (decl); + else if (GFC_DECL_SUBREF_ARRAY_P (decl)) + span = GFC_DECL_SPAN (decl); + else + gcc_unreachable (); } - else if (GFC_DECL_SUBREF_ARRAY_P (decl)) - span = GFC_DECL_SPAN(decl); + else if (vptr) + span = gfc_vptr_size_get (vptr); else gcc_unreachable (); diff --git a/gcc/fortran/trans.h b/gcc/fortran/trans.h index 1998358..e2a1fea 100644 --- a/gcc/fortran/trans.h +++ b/gcc/fortran/trans.h @@ -49,6 +49,10 @@ typedef struct gfc_se /* The length of a character string value. */ tree string_length; + /* When expr is a reference to a class object, store its vptr access + here. */ + tree class_vptr; + /* If set gfc_conv_variable will return an expression for the array descriptor. When set, want_pointer should also be set. If not set scalarizing variables will be substituted. */ @@ -528,7 +532,7 @@ tree gfc_get_function_decl (gfc_symbol *); tree gfc_build_addr_expr (tree, tree); /* Build an ARRAY_REF. */ -tree gfc_build_array_ref (tree, tree, tree); +tree gfc_build_array_ref (tree, tree, tree, tree vptr = NULL_TREE); /* Creates a label. Decl is artificial if label_id == NULL_TREE. */ tree gfc_build_label_decl (tree); diff --git a/gcc/testsuite/gfortran.dg/class_array_21.f03 b/gcc/testsuite/gfortran.dg/class_array_21.f03 new file mode 100644 index 0000000..1e89d38 --- /dev/null +++ b/gcc/testsuite/gfortran.dg/class_array_21.f03 @@ -0,0 +1,97 @@ +! {dg-do run} +! +! Contributed by Andre Vehreschild +! Check more elaborate class array addressing. + +module m1 + + type InnerBaseT + integer, allocatable :: a(:) + end type InnerBaseT + + type, extends(InnerBaseT) :: InnerT + integer :: i + end type InnerT + + type BaseT + class(InnerT), allocatable :: arr(:,:) + contains + procedure P + end type BaseT + +contains + + subroutine indir(this, mat) + class(BaseT) :: this + class(InnerT), intent(inout) :: mat(:,:) + + call this%P(mat) + end subroutine indir + + subroutine P(this, mat) + class(BaseT) :: this + class(InnerT), intent(inout) :: mat(:,:) + integer :: i,j + + mat%i = 42 + do i= 1, ubound(mat, 1) + do j= 1, ubound(mat, 2) + if (.not. allocated(mat(i,j)%a)) then + allocate(mat(i,j)%a(10), source = 72) + end if + end do + end do + mat(1,1)%i = 9 + mat(1,1)%a(5) = 1 + end subroutine + +end module m1 + +program test + use m1 + + class(BaseT), allocatable, target :: o + class(InnerT), pointer :: i_p(:,:) + class(InnerBaseT), allocatable :: i_a(:,:) + integer i,j,l + + allocate(o) + allocate(o%arr(2,2)) + allocate(InnerT::i_a(2,2)) + o%arr%i = 1 + + i_p => o%arr + call o%P(i_p) + if (any(o%arr%i /= reshape([9,42,42,42],[2,2]))) call abort() + do l= 1, 10 + do i= 1, 2 + do j= 1,2 + if ((i == 1 .and. j == 1 .and. l == 5 .and. & + o%arr(i,j)%a(5) /= 1) & + .or. (.not. (i == 1 .and. j == 1 .and. l == 5) & + .and. o%arr(i,j)%a(l) /= 72)) call abort() + end do + end do + end do + + select type (i_a) + type is (InnerT) + call o%P(i_a) + do l= 1, 10 + do i= 1, 2 + do j= 1,2 + if ((i == 1 .and. j == 1 .and. l == 5 .and. & + i_a(i,j)%a(5) /= 1) & + .or. (.not. (i == 1 .and. j == 1 .and. l == 5) & + .and. i_a(i,j)%a(l) /= 72)) call abort() + end do + end do + end do + end select + + i_p%i = 4 + call indir(o, i_p) + if (any(o%arr%i /= reshape([9,42,42,42],[2,2]))) call abort() +end program test + +! vim:ts=2:sts=2:cindent:sw=2:tw=80: ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [Patch, Fortran, pr60322, addendum] was: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-04-14 17:01 ` [Patch, Fortran, pr60322, addendum] " Andre Vehreschild @ 2015-04-16 19:13 ` Paul Richard Thomas 2015-04-23 11:34 ` [commited, Patch, " Andre Vehreschild 0 siblings, 1 reply; 18+ messages in thread From: Paul Richard Thomas @ 2015-04-16 19:13 UTC (permalink / raw) To: Andre Vehreschild Cc: Mikael Morin, GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis, Dominique Dhumieres Hi Andre, The delta patch is OK for trunk and eventual backport to 5.2. Thanks for all the hard work Paul On 14 April 2015 at 19:00, Andre Vehreschild <vehre@gmx.de> wrote: > Hi all, > > during further testing of a big Fortran software I encounter two bugs with > class arrays, that are somehow connected to pr60322. I therefore propose an > extended patch for pr60322. Because Paul has already reviewed most the extended > patch, I give you two patches: > > 1. a full patch, fixing all the issues connected to pr60322, and > 2. a delta patch to get from the reviewed patch to the latest version. > > With the second patch I hope to get a faster review, because it is > significantly shorter. > > Now what was the issue? To be precise there were two issues: > > i. a pointer to a class array (CLASS_DATA(sym).attr.class_pointer == 1) was > dereferenced, which lead to an ICE (the patch for this in the delta is chunk 5 > in gfc_conv_expr_descriptor, and > > ii. (and this was a severe brain cracker) in chains of references consisting of > more then one class-(array)-ref always the _vptr of the first symbol was taken > and not the _vptr of the currently dereferenced class object. This occurred > when fortran code similiar to this was executed: > > type innerT > integer, allocatable :: arr(:) > end type > > type T > class(innerT) :: mat(:,:) > end type > > class(T) :: o > > allocate(o%mat(2,2)) > allocate(o%mat(:,:)%arr(10)) ! This is obviously pseudo code, > ! but I think you get what is meant. > > o%mat(1,1)%arr(1) = 1 > > In the last line the address to get to arr(1) was computed using the > _vptr->size of o and not of o%mat(1,1). To fix this gfc_component_ref () now > computes the class' _vptr-ref whenever it does a _data-ref (chunk 1 of > trans-expr.c in the delta patch). The _vptr-ref is stored in gfc_se, where I > added the new member class_vptr. The gfc_se->class_vptr is then used in > array-refs (chunk 2 of trans.c) to get the size of the array elements of the > correct level. > > The other chunks of the delta patch are: > - parameter passing fixes, and > - documentation fixes as requested for the version 5 of the pr60322 patch. > > I hope this helps in getting the patch reviewed quickly. > > Bootstraps and regtests ok on x86_64-linux-gnu/F21. > > Ok for trunk -> 6.0? > Ok, for backport to 5.2, once available? > > Note, the patches may apply with shifts, as I forgot to update before taking > the diffs. > > Regards, > Andre > > On Thu, 9 Apr 2015 14:37:09 +0200 > Andre Vehreschild <vehre@gmx.de> wrote: > >> Hi Paul, hi all, >> >> Paul, thanks for the review. Answers to your questions are inline below: >> >> On Sun, 5 Apr 2015 11:13:05 +0200 >> Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: >> <snip> >> > + /* The dummy is returned for pointer, allocatable or assumed rank arrays. >> > + The check for pointerness needs to be repeated here (it is done in >> > + IS_CLASS_ARRAY (), too), because for class arrays that are pointers, >> > as >> > + is the one of the sym, which is incorrect here. */ >> > >> > What does this mean, please? >> >> The first sentence is about regular arrays and should be unchanged from the >> original source. Then I have to check for class (arrays) that are pointers, >> i.e., independent of whether the sym is a class array or a regular pointer to >> a class object. (The latter shouldn't make it into the routine anyway.) >> IS_CLASS_ARRAY () returns false for too many reasons to be of use here. I have >> to apologize and confess that the comment was a mere note to myself to not >> return to use is_classarray in the if below. Let me rephrase the comment to >> be: >> >> /* The dummy is returned for pointer, allocatable or assumed rank arrays. >> For class arrays the information if sym is an allocatable or pointer >> object needs to be checked explicitly (IS_CLASS_ARRAY can be false for >> too many reasons to be of use here). */ >> >> > + /* Returning the descriptor for dummy class arrays is hazardous, >> > because >> > + some caller is expecting an expression to apply the component refs to. >> > + Therefore the descriptor is only created and stored in >> > + sym->backend_decl's GFC_DECL_SAVED_DESCRIPTOR. The caller is then >> > + responsible to extract it from there, when the descriptor is >> > + desired. */ >> > + if (IS_CLASS_ARRAY (sym) >> > + && (!DECL_LANG_SPECIFIC (sym->backend_decl) >> > + || !GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl))) >> > + { >> > + decl = gfc_build_dummy_array_decl (sym, sym->backend_decl); >> > + /* Prevent the dummy from being detected as unused if it is copied. >> > */ >> > + if (sym->backend_decl != NULL && decl != sym->backend_decl) >> > + DECL_ARTIFICIAL (sym->backend_decl) = 1; >> > + sym->backend_decl = decl; >> > + } >> > >> > The comments, such as the above are often going well beyond column 72, >> > into the 80's. I know that much of the existing code violates this >> > style requirement but there is no need to do so if clarity is not >> > reduced thereby. >> >> Er, the document at >> >> https://gcc.gnu.org/codingconventions.html#C_Formatting >> >> says that line length is 80, or is there another convention, that I am not >> aware of? >> >> > In trans-stmt.c s/standart/standard/ >> >> Fixed. >> >> > Don't forget to put the PR numbers in the ChangeLogs. >> >> I won't anymore, already got told off :-) >> >> > For this submission, I would have appreciated some a description of >> > what each chunk in the patch is doing, just because there is so much >> > of it. I suppose that it was good for my imortal soul to sort it out >> > for myself but it took a little while :-) >> >> I initially tried to split the submission in two parts to make it more >> manageable. One part with the brain-dead substitutions of as and array_attr >> and one with the new code. Albeit I failed to get the brain-dead part right >> and made some mistakes there already, which Mikael pointed out. I therefore >> went for the big submission. >> >> Now doing a description of what each "chunk" does is quite tedious. I really >> would like to spend my time more productive. Would you be satisfied, when I >> write a story about the patch, referring to some parts more explicitly, like >> >> "Chunk 4 of file trans-stmt.c is the heart of the patch and does this and >> that. The remaining chunks are more or less putting the data together." >> >> (This is not correct for this patch of course. Just an example.) More >> elaborate of course, but just to give an idea. >> >> Thanks again. I will commit as soon as 5.2/6.0 commit window is open. >> >> Regards, >> Andre >> >> > >> > Cheers and many thanks for the patch. >> > >> > Paul >> > >> > On 27 March 2015 at 13:48, Paul Richard Thomas >> > <paul.richard.thomas@gmail.com> wrote: >> > > Dear Andre, >> > > >> > > I am in the UK as of last night. Before leaving, I bootstrapped and >> > > regtested your patch and all was well. I must drive to Cambridge this >> > > afternoon to see my mother and will try to get to it either this >> > > evening or tomorrow morning. There is so much of it and it touches >> > > many places; so I must give it a very careful looking over before >> > > giving the green light. Bear with me please. >> > > >> > > Great work though! >> > > >> > > Paul >> > > >> > > On 24 March 2015 at 18:06, Andre Vehreschild <vehre@gmx.de> wrote: >> > >> Hi all, >> > >> >> > >> I have worked on the comments Mikael gave me. I am now checking for >> > >> class_pointer in the way he pointed out. >> > >> >> > >> Furthermore did I *join the two parts* of the patch into this one, >> > >> because keeping both in sync was no benefit but only tedious and did not >> > >> prove to be reviewed faster. >> > >> >> > >> Paul, Dominique: I have addressed the LOC issue that came up lately. Or >> > >> rather the patch addressed it already. I feel like this is not tested >> > >> very well, not the loc() call nor the sizeof() call as given in the 57305 >> > >> second's download. Unfortunately, is that download not runable. I would >> > >> love to see a test similar to that download, but couldn't come up with >> > >> one, that satisfied me. Given that the patch's review will last some >> > >> days, I still have enough time to come up with something beautiful which >> > >> I will add then. >> > >> >> > >> Bootstraps and regtests ok on x86_64-linux-gnu/F20. >> > >> >> > >> Regards, >> > >> Andre >> > >> >> > >> >> > >> On Tue, 24 Mar 2015 11:13:27 +0100 >> > >> Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: >> > >> >> > >>> Dear Andre, >> > >>> >> > >>> Dominique pointed out to me that the 'loc' patch causes a ICE in the >> > >>> testsuite. It seems that 'loc' should provide the address of the class >> > >>> container in some places and the address of the data in others. I will >> > >>> put my thinking cap on tonight :-) >> > >>> >> > >>> Cheers >> > >>> >> > >>> Paul >> > >>> >> > >>> On 23 March 2015 at 13:43, Andre Vehreschild <vehre@gmx.de> wrote: >> > >>> > Hi Mikael, >> > >>> > >> > >>> > thanks for looking at the patch. Please note, that Paul has sent an >> > >>> > addendum to the patches for 60322, which I deliberately have attached. >> > >>> > >> > >>> >> 26/02/2015 18:17, Andre Vehreschild a écrit : >> > >>> >> > This first patch is only preparatory and does not change any of the >> > >>> >> > semantics of gfortran at all. >> > >>> >> Sure? >> > >>> > >> > >>> > With the counterexample you found below, this of course is a wrong >> > >>> > statement. >> > >>> > >> > >>> >> > diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c >> > >>> >> > index ab6f7a5..d28cf77 100644 >> > >>> >> > --- a/gcc/fortran/expr.c >> > >>> >> > +++ b/gcc/fortran/expr.c >> > >>> >> > @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) >> > >>> >> > lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name); >> > >>> >> > >> > >>> >> > /* It will always be a full array. */ >> > >>> >> > - lval->rank = sym->as ? sym->as->rank : 0; >> > >>> >> > + as = sym->as; >> > >>> >> > + lval->rank = as ? as->rank : 0; >> > >>> >> > if (lval->rank) >> > >>> >> > - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? >> > >>> >> > - CLASS_DATA (sym)->as : sym->as); >> > >>> >> > + gfc_add_full_array_ref (lval, as); >> > >>> >> >> > >>> >> This is a change of semantics. Or do you know that sym->ts.type != >> > >>> >> BT_CLASS? >> > >>> > >> > >>> > You are completely right. I have made a mistake here. I have to tell >> > >>> > the truth, I never ran a regtest with only part 1 of the patches >> > >>> > applied. The second part of the patch will correct this, by setting >> > >>> > the variable as depending on whether type == BT_CLASS or not. Sorry >> > >>> > for the mistake. >> > >>> > >> > >>> >> > diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c >> > >>> >> > index 3664824..e571a17 100644 >> > >>> >> > --- a/gcc/fortran/trans-decl.c >> > >>> >> > +++ b/gcc/fortran/trans-decl.c >> > >>> >> > @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * >> > >>> >> > sym, tree dummy) tree decl; >> > >>> >> > tree type; >> > >>> >> > gfc_array_spec *as; >> > >>> >> > + symbol_attribute *array_attr; >> > >>> >> > char *name; >> > >>> >> > gfc_packed packed; >> > >>> >> > int n; >> > >>> >> > bool known_size; >> > >>> >> > >> > >>> >> > - if (sym->attr.pointer || sym->attr.allocatable >> > >>> >> > - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) >> > >>> >> > + /* Use the array as and attr. */ >> > >>> >> > + as = sym->as; >> > >>> >> > + array_attr = &sym->attr; >> > >>> >> > + >> > >>> >> > + /* The pointer attribute is always set on a _data component, >> > >>> >> > therefore check >> > >>> >> > + the sym's attribute only. */ >> > >>> >> > + if (sym->attr.pointer || array_attr->allocatable >> > >>> >> > + || (as && as->type == AS_ASSUMED_RANK)) >> > >>> >> > return dummy; >> > >>> >> > >> > >>> >> Any reason to sometimes use array_attr, sometimes not, like here? >> > >>> >> By the way, the comment is misleading: for classes, there is the >> > >>> >> class_pointer attribute (and it is a pain, I know). >> > >>> > >> > >>> > Yes, and a good one. Array_attr is sometimes sym->attr and sometimes >> > >>> > CLASS_DATA(sym)->attr aka sym->ts.u.derived->components->attr. In the >> > >>> > later case .pointer is always set to 1 in the _data component's attr. >> > >>> > I.e., the above if, would always yield true for a class_array, which >> > >>> > is not intended, but rather destructive. I know about the >> > >>> > class_pointer attribute, but I figured, that it is not relevant here. >> > >>> > Any idea how to formulate the comment better, to reflect what I just >> > >>> > explained? >> > >>> > >> > >>> > Regards, >> > >>> > Andre >> > >>> > -- >> > >>> > Andre Vehreschild * Email: vehre ad gmx dot de >> > >>> > >> > >>> > >> > >>> > ---------- Forwarded message ---------- >> > >>> > From: Paul Richard Thomas <paul.richard.thomas@gmail.com> >> > >>> > To: Andre Vehreschild <vehre@gmx.de>, Dominique Dhumieres >> > >>> > <dominiq@lps.ens.fr> Cc: >> > >>> > Date: Sun, 22 Mar 2015 21:20:20 +0100 >> > >>> > Subject: Bug in intrinsic LOC for scalar class objects >> > >>> > Dear Andre and Dominique, >> > >>> > >> > >>> > I have found that LOC is returning the address of the class container >> > >>> > rather than the _data component for class scalars. See the source >> > >>> > below, which you will recognise! A fix is attached. >> > >>> > >> > >>> > Note that the scalar allocate fails with MOLD= and so I substituted >> > >>> > SOURCE=. >> > >>> > >> > >>> > Cheers >> > >>> > >> > >>> > Paul >> > >>> > >> > >>> > class(*), allocatable :: a(:), e ! Change 'e' to an array and >> > >>> > second memcpy works correctly >> > >>> > ! Problem is with loc(e), which >> > >>> > returns the address of the >> > >>> > ! class container. >> > >>> > allocate (e, source = 99.0) >> > >>> > allocate (a(2), source = [1.0, 2.0]) >> > >>> > call add_element_poly (a,e) >> > >>> > select type (a) >> > >>> > type is (real) >> > >>> > print *, a >> > >>> > end select >> > >>> > >> > >>> > contains >> > >>> > >> > >>> > subroutine add_element_poly(a,e) >> > >>> > use iso_c_binding >> > >>> > class(*),allocatable,intent(inout),target :: a(:) >> > >>> > class(*),intent(in),target :: e >> > >>> > class(*),allocatable,target :: tmp(:) >> > >>> > type(c_ptr) :: dummy >> > >>> > >> > >>> > interface >> > >>> > function memcpy(dest,src,n) bind(C,name="memcpy") result(res) >> > >>> > import >> > >>> > type(c_ptr) :: res >> > >>> > integer(c_intptr_t),value :: dest >> > >>> > integer(c_intptr_t),value :: src >> > >>> > integer(c_size_t),value :: n >> > >>> > end function >> > >>> > end interface >> > >>> > >> > >>> > if (.not.allocated(a)) then >> > >>> > allocate(a(1), source=e) >> > >>> > else >> > >>> > allocate(tmp(size(a)),source=a) >> > >>> > deallocate(a) >> > >>> > allocate(a(size(tmp)+1),source=e) ! mold gives a segfault >> > >>> > dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) >> > >>> > dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) >> > >>> > end if >> > >>> > end subroutine >> > >>> > end >> > >>> > >> > >>> >> > >>> >> > >>> >> > >> >> > >> >> > >> -- >> > >> Andre Vehreschild * Email: vehre ad gmx dot de >> > > >> > > >> > > >> > > -- >> > > Outside of a dog, a book is a man's best friend. Inside of a dog it's >> > > too dark to read. >> > > >> > > Groucho Marx >> > >> > >> > >> >> > > > -- > Andre Vehreschild * Email: vehre ad gmx dot de -- Outside of a dog, a book is a man's best friend. Inside of a dog it's too dark to read. Groucho Marx ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [commited, Patch, Fortran, pr60322, addendum] was: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-04-16 19:13 ` Paul Richard Thomas @ 2015-04-23 11:34 ` Andre Vehreschild 2015-04-27 17:43 ` Andre Vehreschild 0 siblings, 1 reply; 18+ messages in thread From: Andre Vehreschild @ 2015-04-23 11:34 UTC (permalink / raw) To: Paul Richard Thomas Cc: Mikael Morin, GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis, Dominique Dhumieres [-- Attachment #1: Type: text/plain, Size: 17524 bytes --] Hi Paul, hi all, Paul, thanks for the review. I have commited this as r222361. Regards, Andre On Thu, 16 Apr 2015 21:13:31 +0200 Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: > Hi Andre, > > The delta patch is OK for trunk and eventual backport to 5.2. > > Thanks for all the hard work > > Paul > > On 14 April 2015 at 19:00, Andre Vehreschild <vehre@gmx.de> wrote: > > Hi all, > > > > during further testing of a big Fortran software I encounter two bugs with > > class arrays, that are somehow connected to pr60322. I therefore propose an > > extended patch for pr60322. Because Paul has already reviewed most the > > extended patch, I give you two patches: > > > > 1. a full patch, fixing all the issues connected to pr60322, and > > 2. a delta patch to get from the reviewed patch to the latest version. > > > > With the second patch I hope to get a faster review, because it is > > significantly shorter. > > > > Now what was the issue? To be precise there were two issues: > > > > i. a pointer to a class array (CLASS_DATA(sym).attr.class_pointer == 1) was > > dereferenced, which lead to an ICE (the patch for this in the delta is > > chunk 5 in gfc_conv_expr_descriptor, and > > > > ii. (and this was a severe brain cracker) in chains of references > > consisting of more then one class-(array)-ref always the _vptr of the first > > symbol was taken and not the _vptr of the currently dereferenced class > > object. This occurred when fortran code similiar to this was executed: > > > > type innerT > > integer, allocatable :: arr(:) > > end type > > > > type T > > class(innerT) :: mat(:,:) > > end type > > > > class(T) :: o > > > > allocate(o%mat(2,2)) > > allocate(o%mat(:,:)%arr(10)) ! This is obviously pseudo code, > > ! but I think you get what is meant. > > > > o%mat(1,1)%arr(1) = 1 > > > > In the last line the address to get to arr(1) was computed using the > > _vptr->size of o and not of o%mat(1,1). To fix this gfc_component_ref () now > > computes the class' _vptr-ref whenever it does a _data-ref (chunk 1 of > > trans-expr.c in the delta patch). The _vptr-ref is stored in gfc_se, where I > > added the new member class_vptr. The gfc_se->class_vptr is then used in > > array-refs (chunk 2 of trans.c) to get the size of the array elements of the > > correct level. > > > > The other chunks of the delta patch are: > > - parameter passing fixes, and > > - documentation fixes as requested for the version 5 of the pr60322 patch. > > > > I hope this helps in getting the patch reviewed quickly. > > > > Bootstraps and regtests ok on x86_64-linux-gnu/F21. > > > > Ok for trunk -> 6.0? > > Ok, for backport to 5.2, once available? > > > > Note, the patches may apply with shifts, as I forgot to update before taking > > the diffs. > > > > Regards, > > Andre > > > > On Thu, 9 Apr 2015 14:37:09 +0200 > > Andre Vehreschild <vehre@gmx.de> wrote: > > > >> Hi Paul, hi all, > >> > >> Paul, thanks for the review. Answers to your questions are inline below: > >> > >> On Sun, 5 Apr 2015 11:13:05 +0200 > >> Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: > >> <snip> > >> > + /* The dummy is returned for pointer, allocatable or assumed rank > >> > arrays. > >> > + The check for pointerness needs to be repeated here (it is done in > >> > + IS_CLASS_ARRAY (), too), because for class arrays that are > >> > pointers, as > >> > + is the one of the sym, which is incorrect here. */ > >> > > >> > What does this mean, please? > >> > >> The first sentence is about regular arrays and should be unchanged from the > >> original source. Then I have to check for class (arrays) that are pointers, > >> i.e., independent of whether the sym is a class array or a regular pointer > >> to a class object. (The latter shouldn't make it into the routine anyway.) > >> IS_CLASS_ARRAY () returns false for too many reasons to be of use here. I > >> have to apologize and confess that the comment was a mere note to myself > >> to not return to use is_classarray in the if below. Let me rephrase the > >> comment to be: > >> > >> /* The dummy is returned for pointer, allocatable or assumed rank arrays. > >> For class arrays the information if sym is an allocatable or pointer > >> object needs to be checked explicitly (IS_CLASS_ARRAY can be false for > >> too many reasons to be of use here). */ > >> > >> > + /* Returning the descriptor for dummy class arrays is hazardous, > >> > because > >> > + some caller is expecting an expression to apply the component refs > >> > to. > >> > + Therefore the descriptor is only created and stored in > >> > + sym->backend_decl's GFC_DECL_SAVED_DESCRIPTOR. The caller is then > >> > + responsible to extract it from there, when the descriptor is > >> > + desired. */ > >> > + if (IS_CLASS_ARRAY (sym) > >> > + && (!DECL_LANG_SPECIFIC (sym->backend_decl) > >> > + || !GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl))) > >> > + { > >> > + decl = gfc_build_dummy_array_decl (sym, sym->backend_decl); > >> > + /* Prevent the dummy from being detected as unused if it is > >> > copied. */ > >> > + if (sym->backend_decl != NULL && decl != sym->backend_decl) > >> > + DECL_ARTIFICIAL (sym->backend_decl) = 1; > >> > + sym->backend_decl = decl; > >> > + } > >> > > >> > The comments, such as the above are often going well beyond column 72, > >> > into the 80's. I know that much of the existing code violates this > >> > style requirement but there is no need to do so if clarity is not > >> > reduced thereby. > >> > >> Er, the document at > >> > >> https://gcc.gnu.org/codingconventions.html#C_Formatting > >> > >> says that line length is 80, or is there another convention, that I am not > >> aware of? > >> > >> > In trans-stmt.c s/standart/standard/ > >> > >> Fixed. > >> > >> > Don't forget to put the PR numbers in the ChangeLogs. > >> > >> I won't anymore, already got told off :-) > >> > >> > For this submission, I would have appreciated some a description of > >> > what each chunk in the patch is doing, just because there is so much > >> > of it. I suppose that it was good for my imortal soul to sort it out > >> > for myself but it took a little while :-) > >> > >> I initially tried to split the submission in two parts to make it more > >> manageable. One part with the brain-dead substitutions of as and array_attr > >> and one with the new code. Albeit I failed to get the brain-dead part right > >> and made some mistakes there already, which Mikael pointed out. I therefore > >> went for the big submission. > >> > >> Now doing a description of what each "chunk" does is quite tedious. I > >> really would like to spend my time more productive. Would you be > >> satisfied, when I write a story about the patch, referring to some parts > >> more explicitly, like > >> > >> "Chunk 4 of file trans-stmt.c is the heart of the patch and does this and > >> that. The remaining chunks are more or less putting the data together." > >> > >> (This is not correct for this patch of course. Just an example.) More > >> elaborate of course, but just to give an idea. > >> > >> Thanks again. I will commit as soon as 5.2/6.0 commit window is open. > >> > >> Regards, > >> Andre > >> > >> > > >> > Cheers and many thanks for the patch. > >> > > >> > Paul > >> > > >> > On 27 March 2015 at 13:48, Paul Richard Thomas > >> > <paul.richard.thomas@gmail.com> wrote: > >> > > Dear Andre, > >> > > > >> > > I am in the UK as of last night. Before leaving, I bootstrapped and > >> > > regtested your patch and all was well. I must drive to Cambridge this > >> > > afternoon to see my mother and will try to get to it either this > >> > > evening or tomorrow morning. There is so much of it and it touches > >> > > many places; so I must give it a very careful looking over before > >> > > giving the green light. Bear with me please. > >> > > > >> > > Great work though! > >> > > > >> > > Paul > >> > > > >> > > On 24 March 2015 at 18:06, Andre Vehreschild <vehre@gmx.de> wrote: > >> > >> Hi all, > >> > >> > >> > >> I have worked on the comments Mikael gave me. I am now checking for > >> > >> class_pointer in the way he pointed out. > >> > >> > >> > >> Furthermore did I *join the two parts* of the patch into this one, > >> > >> because keeping both in sync was no benefit but only tedious and did > >> > >> not prove to be reviewed faster. > >> > >> > >> > >> Paul, Dominique: I have addressed the LOC issue that came up lately. > >> > >> Or rather the patch addressed it already. I feel like this is not > >> > >> tested very well, not the loc() call nor the sizeof() call as given > >> > >> in the 57305 second's download. Unfortunately, is that download not > >> > >> runable. I would love to see a test similar to that download, but > >> > >> couldn't come up with one, that satisfied me. Given that the patch's > >> > >> review will last some days, I still have enough time to come up with > >> > >> something beautiful which I will add then. > >> > >> > >> > >> Bootstraps and regtests ok on x86_64-linux-gnu/F20. > >> > >> > >> > >> Regards, > >> > >> Andre > >> > >> > >> > >> > >> > >> On Tue, 24 Mar 2015 11:13:27 +0100 > >> > >> Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: > >> > >> > >> > >>> Dear Andre, > >> > >>> > >> > >>> Dominique pointed out to me that the 'loc' patch causes a ICE in the > >> > >>> testsuite. It seems that 'loc' should provide the address of the > >> > >>> class container in some places and the address of the data in > >> > >>> others. I will put my thinking cap on tonight :-) > >> > >>> > >> > >>> Cheers > >> > >>> > >> > >>> Paul > >> > >>> > >> > >>> On 23 March 2015 at 13:43, Andre Vehreschild <vehre@gmx.de> wrote: > >> > >>> > Hi Mikael, > >> > >>> > > >> > >>> > thanks for looking at the patch. Please note, that Paul has sent an > >> > >>> > addendum to the patches for 60322, which I deliberately have > >> > >>> > attached. > >> > >>> > > >> > >>> >> 26/02/2015 18:17, Andre Vehreschild a écrit : > >> > >>> >> > This first patch is only preparatory and does not change any of > >> > >>> >> > the semantics of gfortran at all. > >> > >>> >> Sure? > >> > >>> > > >> > >>> > With the counterexample you found below, this of course is a wrong > >> > >>> > statement. > >> > >>> > > >> > >>> >> > diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c > >> > >>> >> > index ab6f7a5..d28cf77 100644 > >> > >>> >> > --- a/gcc/fortran/expr.c > >> > >>> >> > +++ b/gcc/fortran/expr.c > >> > >>> >> > @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) > >> > >>> >> > lval->symtree = gfc_find_symtree (sym->ns->sym_root, > >> > >>> >> > sym->name); > >> > >>> >> > > >> > >>> >> > /* It will always be a full array. */ > >> > >>> >> > - lval->rank = sym->as ? sym->as->rank : 0; > >> > >>> >> > + as = sym->as; > >> > >>> >> > + lval->rank = as ? as->rank : 0; > >> > >>> >> > if (lval->rank) > >> > >>> >> > - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? > >> > >>> >> > - CLASS_DATA (sym)->as : sym->as); > >> > >>> >> > + gfc_add_full_array_ref (lval, as); > >> > >>> >> > >> > >>> >> This is a change of semantics. Or do you know that > >> > >>> >> sym->ts.type != BT_CLASS? > >> > >>> > > >> > >>> > You are completely right. I have made a mistake here. I have to > >> > >>> > tell the truth, I never ran a regtest with only part 1 of the > >> > >>> > patches applied. The second part of the patch will correct this, > >> > >>> > by setting the variable as depending on whether type == BT_CLASS > >> > >>> > or not. Sorry for the mistake. > >> > >>> > > >> > >>> >> > diff --git a/gcc/fortran/trans-decl.c b/gcc/fortran/trans-decl.c > >> > >>> >> > index 3664824..e571a17 100644 > >> > >>> >> > --- a/gcc/fortran/trans-decl.c > >> > >>> >> > +++ b/gcc/fortran/trans-decl.c > >> > >>> >> > @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl (gfc_symbol * > >> > >>> >> > sym, tree dummy) tree decl; > >> > >>> >> > tree type; > >> > >>> >> > gfc_array_spec *as; > >> > >>> >> > + symbol_attribute *array_attr; > >> > >>> >> > char *name; > >> > >>> >> > gfc_packed packed; > >> > >>> >> > int n; > >> > >>> >> > bool known_size; > >> > >>> >> > > >> > >>> >> > - if (sym->attr.pointer || sym->attr.allocatable > >> > >>> >> > - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) > >> > >>> >> > + /* Use the array as and attr. */ > >> > >>> >> > + as = sym->as; > >> > >>> >> > + array_attr = &sym->attr; > >> > >>> >> > + > >> > >>> >> > + /* The pointer attribute is always set on a _data component, > >> > >>> >> > therefore check > >> > >>> >> > + the sym's attribute only. */ > >> > >>> >> > + if (sym->attr.pointer || array_attr->allocatable > >> > >>> >> > + || (as && as->type == AS_ASSUMED_RANK)) > >> > >>> >> > return dummy; > >> > >>> >> > > >> > >>> >> Any reason to sometimes use array_attr, sometimes not, like here? > >> > >>> >> By the way, the comment is misleading: for classes, there is the > >> > >>> >> class_pointer attribute (and it is a pain, I know). > >> > >>> > > >> > >>> > Yes, and a good one. Array_attr is sometimes sym->attr and > >> > >>> > sometimes CLASS_DATA(sym)->attr aka > >> > >>> > sym->ts.u.derived->components->attr. In the later case .pointer is > >> > >>> > always set to 1 in the _data component's attr. I.e., the above if, > >> > >>> > would always yield true for a class_array, which is not intended, > >> > >>> > but rather destructive. I know about the class_pointer attribute, > >> > >>> > but I figured, that it is not relevant here. Any idea how to > >> > >>> > formulate the comment better, to reflect what I just explained? > >> > >>> > > >> > >>> > Regards, > >> > >>> > Andre > >> > >>> > -- > >> > >>> > Andre Vehreschild * Email: vehre ad gmx dot de > >> > >>> > > >> > >>> > > >> > >>> > ---------- Forwarded message ---------- > >> > >>> > From: Paul Richard Thomas <paul.richard.thomas@gmail.com> > >> > >>> > To: Andre Vehreschild <vehre@gmx.de>, Dominique Dhumieres > >> > >>> > <dominiq@lps.ens.fr> Cc: > >> > >>> > Date: Sun, 22 Mar 2015 21:20:20 +0100 > >> > >>> > Subject: Bug in intrinsic LOC for scalar class objects > >> > >>> > Dear Andre and Dominique, > >> > >>> > > >> > >>> > I have found that LOC is returning the address of the class > >> > >>> > container rather than the _data component for class scalars. See > >> > >>> > the source below, which you will recognise! A fix is attached. > >> > >>> > > >> > >>> > Note that the scalar allocate fails with MOLD= and so I substituted > >> > >>> > SOURCE=. > >> > >>> > > >> > >>> > Cheers > >> > >>> > > >> > >>> > Paul > >> > >>> > > >> > >>> > class(*), allocatable :: a(:), e ! Change 'e' to an array and > >> > >>> > second memcpy works correctly > >> > >>> > ! Problem is with loc(e), > >> > >>> > which returns the address of the > >> > >>> > ! class container. > >> > >>> > allocate (e, source = 99.0) > >> > >>> > allocate (a(2), source = [1.0, 2.0]) > >> > >>> > call add_element_poly (a,e) > >> > >>> > select type (a) > >> > >>> > type is (real) > >> > >>> > print *, a > >> > >>> > end select > >> > >>> > > >> > >>> > contains > >> > >>> > > >> > >>> > subroutine add_element_poly(a,e) > >> > >>> > use iso_c_binding > >> > >>> > class(*),allocatable,intent(inout),target :: a(:) > >> > >>> > class(*),intent(in),target :: e > >> > >>> > class(*),allocatable,target :: tmp(:) > >> > >>> > type(c_ptr) :: dummy > >> > >>> > > >> > >>> > interface > >> > >>> > function memcpy(dest,src,n) bind(C,name="memcpy") > >> > >>> > result(res) import > >> > >>> > type(c_ptr) :: res > >> > >>> > integer(c_intptr_t),value :: dest > >> > >>> > integer(c_intptr_t),value :: src > >> > >>> > integer(c_size_t),value :: n > >> > >>> > end function > >> > >>> > end interface > >> > >>> > > >> > >>> > if (.not.allocated(a)) then > >> > >>> > allocate(a(1), source=e) > >> > >>> > else > >> > >>> > allocate(tmp(size(a)),source=a) > >> > >>> > deallocate(a) > >> > >>> > allocate(a(size(tmp)+1),source=e) ! mold gives a segfault > >> > >>> > dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) > >> > >>> > dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) > >> > >>> > end if > >> > >>> > end subroutine > >> > >>> > end > >> > >>> > > >> > >>> > >> > >>> > >> > >>> > >> > >> > >> > >> > >> > >> -- > >> > >> Andre Vehreschild * Email: vehre ad gmx dot de > >> > > > >> > > > >> > > > >> > > -- > >> > > Outside of a dog, a book is a man's best friend. Inside of a dog it's > >> > > too dark to read. > >> > > > >> > > Groucho Marx > >> > > >> > > >> > > >> > >> > > > > > > -- > > Andre Vehreschild * Email: vehre ad gmx dot de > > > -- Andre Vehreschild * Email: vehre ad gmx dot de [-- Attachment #2: submit.diff --] [-- Type: text/x-patch, Size: 48306 bytes --] Index: gcc/fortran/trans-expr.c =================================================================== --- gcc/fortran/trans-expr.c (Revision 222360) +++ gcc/fortran/trans-expr.c (Arbeitskopie) @@ -149,6 +149,11 @@ gfc_class_vptr_get (tree decl) { tree vptr; + /* For class arrays decl may be a temporary descriptor handle, the vptr is + then available through the saved descriptor. */ + if (TREE_CODE (decl) == VAR_DECL && DECL_LANG_SPECIFIC (decl) + && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); if (POINTER_TYPE_P (TREE_TYPE (decl))) decl = build_fold_indirect_ref_loc (input_location, decl); vptr = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (decl)), @@ -163,6 +168,11 @@ gfc_class_len_get (tree decl) { tree len; + /* For class arrays decl may be a temporary descriptor handle, the len is + then available through the saved descriptor. */ + if (TREE_CODE (decl) == VAR_DECL && DECL_LANG_SPECIFIC (decl) + && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); if (POINTER_TYPE_P (TREE_TYPE (decl))) decl = build_fold_indirect_ref_loc (input_location, decl); len = gfc_advance_chain (TYPE_FIELDS (TREE_TYPE (decl)), @@ -804,6 +814,16 @@ gfc_add_modify (&parmse->pre, ctree, tmp); } + else if (class_ts.type == BT_CLASS + && class_ts.u.derived->components + && class_ts.u.derived->components->ts.u + .derived->attr.unlimited_polymorphic) + { + ctree = gfc_class_len_get (var); + gfc_add_modify (&parmse->pre, ctree, + fold_convert (TREE_TYPE (ctree), + integer_zero_node)); + } /* Pass the address of the class object. */ parmse->expr = gfc_build_addr_expr (NULL_TREE, var); } @@ -830,6 +850,7 @@ tree tmp; tree vptr; tree cond = NULL_TREE; + tree slen = NULL_TREE; gfc_ref *ref; gfc_ref *class_ref; stmtblock_t block; @@ -921,7 +942,12 @@ tmp = NULL_TREE; if (class_ref == NULL && e->symtree && e->symtree->n.sym->ts.type == BT_CLASS) - tmp = e->symtree->n.sym->backend_decl; + { + tmp = e->symtree->n.sym->backend_decl; + if (DECL_LANG_SPECIFIC (tmp) && GFC_DECL_SAVED_DESCRIPTOR (tmp)) + tmp = GFC_DECL_SAVED_DESCRIPTOR (tmp); + slen = integer_zero_node; + } else { /* Remove everything after the last class reference, convert the @@ -933,6 +959,7 @@ gfc_conv_expr (&tmpse, e); class_ref->next = ref; tmp = tmpse.expr; + slen = tmpse.string_length; } gcc_assert (tmp != NULL_TREE); @@ -951,11 +978,38 @@ gfc_add_modify (&parmse->post, vptr, fold_convert (TREE_TYPE (vptr), ctree)); + /* For unlimited polymorphic objects also set the _len component. */ + if (class_ts.type == BT_CLASS + && class_ts.u.derived->components + && class_ts.u.derived->components->ts.u + .derived->attr.unlimited_polymorphic) + { + ctree = gfc_class_len_get (var); + if (UNLIMITED_POLY (e)) + tmp = gfc_class_len_get (tmp); + else if (e->ts.type == BT_CHARACTER) + { + gcc_assert (slen != NULL_TREE); + tmp = slen; + } + else + tmp = integer_zero_node; + gfc_add_modify (&parmse->pre, ctree, + fold_convert (TREE_TYPE (ctree), tmp)); + } + if (optional) { tree tmp2; cond = gfc_conv_expr_present (e->symtree->n.sym); + /* parmse->pre may contain some preparatory instructions for the + temporary array descriptor. Those may only be executed when the + optional argument is set, therefore add parmse->pre's instructions + to block, which is later guarded by an if (optional_arg_given). */ + gfc_add_block_to_block (&parmse->pre, &block); + block.head = parmse->pre.head; + parmse->pre.head = NULL_TREE; tmp = gfc_finish_block (&block); if (optional_alloc_ptr) @@ -1042,7 +1096,7 @@ fcn_type = TREE_TYPE (TREE_TYPE (fcn)); if (from != NULL_TREE) - from_data = gfc_class_data_get (from); + from_data = gfc_class_data_get (from); else from_data = gfc_class_vtab_def_init_get (to); @@ -1099,7 +1153,8 @@ gfc_init_block (&ifbody); gfc_add_block_to_block (&ifbody, &loop.pre); stdcopy = gfc_finish_block (&ifbody); - if (unlimited) + /* In initialization mode from_len is a constant zero. */ + if (unlimited && !integer_zerop (from_len)) { vec_safe_push (args, from_len); vec_safe_push (args, to_len); @@ -1141,7 +1196,8 @@ vec_safe_push (args, to_data); stdcopy = build_call_vec (fcn_type, fcn, args); - if (unlimited) + /* In initialization mode from_len is a constant zero. */ + if (unlimited && !integer_zerop (from_len)) { vec_safe_push (args, from_len); vec_safe_push (args, to_len); @@ -1156,6 +1212,18 @@ tmp = stdcopy; } + /* Only copy _def_init to to_data, when it is not a NULL-pointer. */ + if (from == NULL_TREE) + { + tree cond; + cond = fold_build2_loc (input_location, NE_EXPR, + boolean_type_node, + from_data, null_pointer_node); + tmp = fold_build3_loc (input_location, COND_EXPR, + void_type_node, cond, + tmp, build_empty_stmt (input_location)); + } + return tmp; } @@ -1229,6 +1297,8 @@ been referenced. */ gfc_get_derived_type (rhs->ts.u.derived); gfc_add_def_init_component (rhs); + /* The _def_init is always scalar. */ + rhs->rank = 0; if (code->expr1->ts.type == BT_CLASS && CLASS_DATA (code->expr1)->attr.dimension) @@ -2203,6 +2273,16 @@ field = f2; } + if (ref->u.c.sym && ref->u.c.sym->ts.type == BT_CLASS + && strcmp ("_data", c->name) == 0) + { + /* Found a ref to the _data component. Store the associated ref to + the vptr in se->class_vptr. */ + se->class_vptr = gfc_class_vptr_get (decl); + } + else + se->class_vptr = NULL_TREE; + tmp = fold_build3_loc (input_location, COMPONENT_REF, TREE_TYPE (field), decl, field, NULL_TREE); @@ -2284,8 +2364,11 @@ bool return_value; bool alternate_entry; bool entry_master; + bool is_classarray; + bool first_time = true; sym = expr->symtree->n.sym; + is_classarray = IS_CLASS_ARRAY (sym); ss = se->ss; if (ss != NULL) { @@ -2389,9 +2472,24 @@ } else if (!sym->attr.value) { + /* Dereference temporaries for class array dummy arguments. */ + if (sym->attr.dummy && is_classarray + && GFC_ARRAY_TYPE_P (TREE_TYPE (se->expr))) + { + if (!se->descriptor_only) + se->expr = GFC_DECL_SAVED_DESCRIPTOR (se->expr); + + se->expr = build_fold_indirect_ref_loc (input_location, + se->expr); + } + /* Dereference non-character scalar dummy arguments. */ if (sym->attr.dummy && !sym->attr.dimension - && !(sym->attr.codimension && sym->attr.allocatable)) + && !(sym->attr.codimension && sym->attr.allocatable) + && (sym->ts.type != BT_CLASS + || (!CLASS_DATA (sym)->attr.dimension + && !(CLASS_DATA (sym)->attr.codimension + && CLASS_DATA (sym)->attr.allocatable)))) se->expr = build_fold_indirect_ref_loc (input_location, se->expr); @@ -2403,11 +2501,12 @@ se->expr = build_fold_indirect_ref_loc (input_location, se->expr); - /* Dereference non-character pointer variables. + /* Dereference non-character, non-class pointer variables. These must be dummies, results, or scalars. */ - if ((sym->attr.pointer || sym->attr.allocatable - || gfc_is_associate_pointer (sym) - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) + if (!is_classarray + && (sym->attr.pointer || sym->attr.allocatable + || gfc_is_associate_pointer (sym) + || (sym->as && sym->as->type == AS_ASSUMED_RANK)) && (sym->attr.dummy || sym->attr.function || sym->attr.result @@ -2415,6 +2514,32 @@ && (!sym->attr.codimension || !sym->attr.allocatable)))) se->expr = build_fold_indirect_ref_loc (input_location, se->expr); + /* Now treat the class array pointer variables accordingly. */ + else if (sym->ts.type == BT_CLASS + && sym->attr.dummy + && (CLASS_DATA (sym)->attr.dimension + || CLASS_DATA (sym)->attr.codimension) + && ((CLASS_DATA (sym)->as + && CLASS_DATA (sym)->as->type == AS_ASSUMED_RANK) + || CLASS_DATA (sym)->attr.allocatable + || CLASS_DATA (sym)->attr.class_pointer)) + se->expr = build_fold_indirect_ref_loc (input_location, + se->expr); + /* And the case where a non-dummy, non-result, non-function, + non-allotable and non-pointer classarray is present. This case was + previously covered by the first if, but with introducing the + condition !is_classarray there, that case has to be covered + explicitly. */ + else if (sym->ts.type == BT_CLASS + && !sym->attr.dummy + && !sym->attr.function + && !sym->attr.result + && (CLASS_DATA (sym)->attr.dimension + || CLASS_DATA (sym)->attr.codimension) + && !CLASS_DATA (sym)->attr.allocatable + && !CLASS_DATA (sym)->attr.class_pointer) + se->expr = build_fold_indirect_ref_loc (input_location, + se->expr); } ref = expr->ref; @@ -2452,6 +2577,18 @@ break; case REF_COMPONENT: + if (first_time && is_classarray && sym->attr.dummy + && se->descriptor_only + && !CLASS_DATA (sym)->attr.allocatable + && !CLASS_DATA (sym)->attr.class_pointer + && CLASS_DATA (sym)->as + && CLASS_DATA (sym)->as->type != AS_ASSUMED_RANK + && strcmp ("_data", ref->u.c.component->name) == 0) + /* Skip the first ref of a _data component, because for class + arrays that one is already done by introducing a temporary + array descriptor. */ + break; + if (ref->u.c.sym->attr.extension) conv_parent_component_references (se, ref); @@ -2471,6 +2608,7 @@ gcc_unreachable (); break; } + first_time = false; ref = ref->next; } /* Pointer assignment, allocation or pass by reference. Arrays are handled @@ -4597,7 +4735,19 @@ gfc_init_se (&parmse, se); parm_kind = ELEMENTAL; - if (fsym && fsym->attr.value) + /* For all value functions or polymorphic scalar non-pointer + non-allocatable variables use the expression in e directly. This + ensures, that initializers of polymorphic entities are correctly + copied. */ + if (fsym && (fsym->attr.value + || (e->expr_type == EXPR_VARIABLE + && fsym->ts.type == BT_DERIVED + && e->ts.type == BT_DERIVED + && !e->ts.u.derived->attr.dimension + && !e->rank + && (!e->symtree + || (!e->symtree->n.sym->attr.allocatable + && !e->symtree->n.sym->attr.pointer))))) gfc_conv_expr (&parmse, e); else gfc_conv_expr_reference (&parmse, e); Index: gcc/fortran/ChangeLog =================================================================== --- gcc/fortran/ChangeLog (Revision 222360) +++ gcc/fortran/ChangeLog (Arbeitskopie) @@ -1,3 +1,61 @@ +2015-04-23 Andre Vehreschild <vehre@gmx.de> + + PR fortran/60322 + * expr.c (gfc_lval_expr_from_sym): Code to select the regular + or class array added. + * gfortran.h: Add IS_CLASS_ARRAY macro. + * trans-array.c (gfc_add_loop_ss_code): Treat class objects + to be referenced always. + (build_class_array_ref): Adapt retrieval of array descriptor. + (build_array_ref): Likewise. + (gfc_conv_array_ref): Hand the vptr or the descriptor to + build_array_ref depending whether the sym is class or not. + (gfc_trans_array_cobounds): Select correct gfc_array_spec for + regular and class arrays. + (gfc_trans_array_bounds): Likewise. + (gfc_trans_dummy_array_bias): Likewise. + (gfc_get_dataptr_offset): Correcting call of build_array_ref. + (gfc_conv_expr_descriptor): Set the array's offset to -1 when + lbound in inner most dim is 1 and symbol non-pointer/assoc. + * trans-decl.c (gfc_build_qualified_array): Select correct + gfc_array_spec for regular and class arrays. + (gfc_build_dummy_array_decl): Likewise. + (gfc_get_symbol_decl): Get a dummy array for class arrays. + (gfc_trans_deferred_vars): Tell conv_expr that the descriptor + is desired. + * trans-expr.c (gfc_class_vptr_get): Get the class descriptor + from the correct location for class arrays. + (gfc_class_len_get): Likewise. + (gfc_conv_intrinsic_to_class): Add handling of _len component. + (gfc_conv_class_to_class): Prevent access to unset array data + when the array is an optional argument. Add handling of _len + component. + (gfc_copy_class_to_class): Check that _def_init is non-NULL + when used in _vptr->copy() + (gfc_trans_class_init_assign): Ensure that the rank of + _def_init is zero. + (gfc_conv_component_ref): Get the _vptr along with _data refs. + (gfc_conv_variable): Make sure the temp array descriptor is + returned for class arrays, too, and that class arrays are + dereferenced correctly. + (gfc_conv_procedure_call): For polymorphic type initialization + the initializer has to be a pointer to _def_init stored in a + dummy variable, which then needs to be used by value. + * trans-intrinsic.c (gfc_conv_intrinsic_sizeof): Use the + temporary array descriptor for class arrays, too. + (gfc_conv_intrinsic_storage_size): Likewise. + (gfc_conv_intrinsic_loc): Add ref to _data for BT_CLASS + expressions. + * trans-stmt.c (trans_associate_var): Use a temporary array for + the associate variable of class arrays, too, making the array + one-based (lbound == 1). + * trans-types.c (gfc_is_nodesc_array): Use the correct + array data. + * trans.c (gfc_build_array_ref): Use the dummy array descriptor + when present. + * trans.h: Add class_vptr to gfc_se for storing a class ref's + vptr. + 2015-04-22 Steven G. Kargl <kargl@gcc.gnu.org> PR fortran/65429 Index: gcc/fortran/trans-types.c =================================================================== --- gcc/fortran/trans-types.c (Revision 222360) +++ gcc/fortran/trans-types.c (Arbeitskopie) @@ -1288,25 +1288,35 @@ int gfc_is_nodesc_array (gfc_symbol * sym) { - gcc_assert (sym->attr.dimension || sym->attr.codimension); + symbol_attribute *array_attr; + gfc_array_spec *as; + bool is_classarray = IS_CLASS_ARRAY (sym); + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; + + gcc_assert (array_attr->dimension || array_attr->codimension); + /* We only want local arrays. */ - if (sym->attr.pointer || sym->attr.allocatable) + if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) + || array_attr->allocatable) return 0; /* We want a descriptor for associate-name arrays that do not have an - explicitly known shape already. */ - if (sym->assoc && sym->as->type != AS_EXPLICIT) + explicitly known shape already. */ + if (sym->assoc && as->type != AS_EXPLICIT) return 0; + /* The dummy is stored in sym and not in the component. */ if (sym->attr.dummy) - return sym->as->type != AS_ASSUMED_SHAPE - && sym->as->type != AS_ASSUMED_RANK; + return as->type != AS_ASSUMED_SHAPE + && as->type != AS_ASSUMED_RANK; if (sym->attr.result || sym->attr.function) return 0; - gcc_assert (sym->as->type == AS_EXPLICIT || sym->as->cp_was_assumed); + gcc_assert (as->type == AS_EXPLICIT || as->cp_was_assumed); return 1; } Index: gcc/fortran/trans-stmt.c =================================================================== --- gcc/fortran/trans-stmt.c (Revision 222360) +++ gcc/fortran/trans-stmt.c (Arbeitskopie) @@ -1390,13 +1390,30 @@ gfc_init_se (&se, NULL); se.descriptor_only = 1; - gfc_conv_expr (&se, e); + /* In a select type the (temporary) associate variable shall point to + a standard fortran array (lower bound == 1), but conv_expr () + just maps to the input array in the class object, whose lbound may + be arbitrary. conv_expr_descriptor solves this by inserting a + temporary array descriptor. */ + gfc_conv_expr_descriptor (&se, e); - gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se.expr))); + gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (se.expr)) + || GFC_ARRAY_TYPE_P (TREE_TYPE (se.expr))); gcc_assert (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (sym->backend_decl))); - gfc_add_modify (&se.pre, sym->backend_decl, se.expr); + if (GFC_ARRAY_TYPE_P (TREE_TYPE (se.expr))) + { + if (INDIRECT_REF_P (se.expr)) + tmp = TREE_OPERAND (se.expr, 0); + else + tmp = se.expr; + gfc_add_modify (&se.pre, sym->backend_decl, + gfc_class_data_get (GFC_DECL_SAVED_DESCRIPTOR (tmp))); + } + else + gfc_add_modify (&se.pre, sym->backend_decl, se.expr); + if (unlimited) { /* Recover the dtype, which has been overwritten by the @@ -1406,7 +1423,7 @@ gfc_get_dtype (TREE_TYPE (sym->backend_decl))); } - gfc_add_init_cleanup (block, gfc_finish_block( &se.pre), + gfc_add_init_cleanup (block, gfc_finish_block (&se.pre), gfc_finish_block (&se.post)); } @@ -1449,9 +1466,18 @@ } if (need_len_assign) { - /* Get the _len comp from the target expr by stripping _data - from it and adding component-ref to _len. */ - tmp = gfc_class_len_get (TREE_OPERAND (target_expr, 0)); + if (e->symtree + && DECL_LANG_SPECIFIC (e->symtree->n.sym->backend_decl) + && GFC_DECL_SAVED_DESCRIPTOR (e->symtree->n.sym->backend_decl)) + /* Use the original class descriptor stored in the saved + descriptor to get the target_expr. */ + target_expr = + GFC_DECL_SAVED_DESCRIPTOR (e->symtree->n.sym->backend_decl); + else + /* Strip the _data component from the target_expr. */ + target_expr = TREE_OPERAND (target_expr, 0); + /* Add a reference to the _len comp to the target expr. */ + tmp = gfc_class_len_get (target_expr); /* Get the component-ref for the temp structure's _len comp. */ charlen = gfc_class_len_get (se.expr); /* Add the assign to the beginning of the the block... */ Index: gcc/fortran/gfortran.h =================================================================== --- gcc/fortran/gfortran.h (Revision 222360) +++ gcc/fortran/gfortran.h (Arbeitskopie) @@ -3210,6 +3210,11 @@ && CLASS_DATA (sym) \ && CLASS_DATA (sym)->ts.u.derived \ && CLASS_DATA (sym)->ts.u.derived->attr.unlimited_polymorphic) +#define IS_CLASS_ARRAY(sym) \ + (sym->ts.type == BT_CLASS \ + && CLASS_DATA (sym) \ + && CLASS_DATA (sym)->attr.dimension \ + && !CLASS_DATA (sym)->attr.class_pointer) /* frontend-passes.c */ Index: gcc/fortran/trans-intrinsic.c =================================================================== --- gcc/fortran/trans-intrinsic.c (Revision 222360) +++ gcc/fortran/trans-intrinsic.c (Arbeitskopie) @@ -5921,8 +5921,17 @@ } else if (arg->ts.type == BT_CLASS) { - if (arg->rank) + /* For deferred length arrays, conv_expr_descriptor returns an + indirect_ref to the component. */ + if (arg->rank < 0 + || (arg->rank > 0 && !VAR_P (argse.expr) + && GFC_DECL_CLASS (TREE_OPERAND (argse.expr, 0)))) byte_size = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0)); + else if (arg->rank > 0) + /* The scalarizer added an additional temp. To get the class' vptr + one has to look at the original backend_decl. */ + byte_size = gfc_class_vtab_size_get ( + GFC_DECL_SAVED_DESCRIPTOR (arg->symtree->n.sym->backend_decl)); else byte_size = gfc_class_vtab_size_get (argse.expr); } @@ -6053,7 +6062,11 @@ gfc_conv_expr_descriptor (&argse, arg); if (arg->ts.type == BT_CLASS) { - tmp = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0)); + if (arg->rank > 0) + tmp = gfc_class_vtab_size_get ( + GFC_DECL_SAVED_DESCRIPTOR (arg->symtree->n.sym->backend_decl)); + else + tmp = gfc_class_vtab_size_get (TREE_OPERAND (argse.expr, 0)); tmp = fold_convert (result_type, tmp); goto done; } @@ -7080,7 +7093,11 @@ arg_expr = expr->value.function.actual->expr; if (arg_expr->rank == 0) - gfc_conv_expr_reference (se, arg_expr); + { + if (arg_expr->ts.type == BT_CLASS) + gfc_add_component_ref (arg_expr, "_data"); + gfc_conv_expr_reference (se, arg_expr); + } else gfc_conv_array_parameter (se, arg_expr, true, NULL, NULL, NULL); se->expr = convert (gfc_get_int_type (gfc_index_integer_kind), se->expr); Index: gcc/fortran/trans.c =================================================================== --- gcc/fortran/trans.c (Revision 222360) +++ gcc/fortran/trans.c (Arbeitskopie) @@ -321,7 +321,7 @@ /* Build an ARRAY_REF with its natural type. */ tree -gfc_build_array_ref (tree base, tree offset, tree decl) +gfc_build_array_ref (tree base, tree offset, tree decl, tree vptr) { tree type = TREE_TYPE (base); tree tmp; @@ -353,30 +353,47 @@ /* If the array reference is to a pointer, whose target contains a subreference, use the span that is stored with the backend decl and reference the element with pointer arithmetic. */ - if (decl && (TREE_CODE (decl) == FIELD_DECL - || TREE_CODE (decl) == VAR_DECL - || TREE_CODE (decl) == PARM_DECL) - && ((GFC_DECL_SUBREF_ARRAY_P (decl) - && !integer_zerop (GFC_DECL_SPAN(decl))) + if ((decl && (TREE_CODE (decl) == FIELD_DECL + || TREE_CODE (decl) == VAR_DECL + || TREE_CODE (decl) == PARM_DECL) + && ((GFC_DECL_SUBREF_ARRAY_P (decl) + && !integer_zerop (GFC_DECL_SPAN (decl))) || GFC_DECL_CLASS (decl))) + || vptr) { - if (GFC_DECL_CLASS (decl)) + if (decl) { - /* Allow for dummy arguments and other good things. */ - if (POINTER_TYPE_P (TREE_TYPE (decl))) - decl = build_fold_indirect_ref_loc (input_location, decl); + if (GFC_DECL_CLASS (decl)) + { + /* When a temporary is in place for the class array, then the + original class' declaration is stored in the saved + descriptor. */ + if (DECL_LANG_SPECIFIC (decl) && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); + else + { + /* Allow for dummy arguments and other good things. */ + if (POINTER_TYPE_P (TREE_TYPE (decl))) + decl = build_fold_indirect_ref_loc (input_location, decl); - /* Check if '_data' is an array descriptor. If it is not, - the array must be one of the components of the class object, - so return a normal array reference. */ - if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (gfc_class_data_get (decl)))) - return build4_loc (input_location, ARRAY_REF, type, base, - offset, NULL_TREE, NULL_TREE); + /* Check if '_data' is an array descriptor. If it is not, + the array must be one of the components of the class + object, so return a normal array reference. */ + if (!GFC_DESCRIPTOR_TYPE_P (TREE_TYPE ( + gfc_class_data_get (decl)))) + return build4_loc (input_location, ARRAY_REF, type, base, + offset, NULL_TREE, NULL_TREE); + } - span = gfc_class_vtab_size_get (decl); + span = gfc_class_vtab_size_get (decl); + } + else if (GFC_DECL_SUBREF_ARRAY_P (decl)) + span = GFC_DECL_SPAN (decl); + else + gcc_unreachable (); } - else if (GFC_DECL_SUBREF_ARRAY_P (decl)) - span = GFC_DECL_SPAN(decl); + else if (vptr) + span = gfc_vptr_size_get (vptr); else gcc_unreachable (); Index: gcc/fortran/trans-decl.c =================================================================== --- gcc/fortran/trans-decl.c (Revision 222360) +++ gcc/fortran/trans-decl.c (Arbeitskopie) @@ -812,8 +812,13 @@ int dim; int nest; gfc_namespace* procns; + symbol_attribute *array_attr; + gfc_array_spec *as; + bool is_classarray = IS_CLASS_ARRAY (sym); type = TREE_TYPE (decl); + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; /* We just use the descriptor, if there is one. */ if (GFC_DESCRIPTOR_TYPE_P (type)) @@ -824,8 +829,8 @@ nest = (procns->proc_name->backend_decl != current_function_decl) && !sym->attr.contained; - if (sym->attr.codimension && flag_coarray == GFC_FCOARRAY_LIB - && sym->as->type != AS_ASSUMED_SHAPE + if (array_attr->codimension && flag_coarray == GFC_FCOARRAY_LIB + && as->type != AS_ASSUMED_SHAPE && GFC_TYPE_ARRAY_CAF_TOKEN (type) == NULL_TREE) { tree token; @@ -878,8 +883,8 @@ } /* Don't try to use the unknown bound for assumed shape arrays. */ if (GFC_TYPE_ARRAY_UBOUND (type, dim) == NULL_TREE - && (sym->as->type != AS_ASSUMED_SIZE - || dim < GFC_TYPE_ARRAY_RANK (type) - 1)) + && (as->type != AS_ASSUMED_SIZE + || dim < GFC_TYPE_ARRAY_RANK (type) - 1)) { GFC_TYPE_ARRAY_UBOUND (type, dim) = create_index_var ("ubound", nest); TREE_NO_WARNING (GFC_TYPE_ARRAY_UBOUND (type, dim)) = 1; @@ -920,7 +925,7 @@ } if (GFC_TYPE_ARRAY_SIZE (type) == NULL_TREE - && sym->as->type != AS_ASSUMED_SIZE) + && as->type != AS_ASSUMED_SIZE) { GFC_TYPE_ARRAY_SIZE (type) = create_index_var ("size", nest); TREE_NO_WARNING (GFC_TYPE_ARRAY_SIZE (type)) = 1; @@ -947,12 +952,12 @@ } if (TYPE_NAME (type) != NULL_TREE - && GFC_TYPE_ARRAY_UBOUND (type, sym->as->rank - 1) != NULL_TREE - && TREE_CODE (GFC_TYPE_ARRAY_UBOUND (type, sym->as->rank - 1)) == VAR_DECL) + && GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1) != NULL_TREE + && TREE_CODE (GFC_TYPE_ARRAY_UBOUND (type, as->rank - 1)) == VAR_DECL) { tree gtype = DECL_ORIGINAL_TYPE (TYPE_NAME (type)); - for (dim = 0; dim < sym->as->rank - 1; dim++) + for (dim = 0; dim < as->rank - 1; dim++) { gcc_assert (TREE_CODE (gtype) == ARRAY_TYPE); gtype = TREE_TYPE (gtype); @@ -966,7 +971,7 @@ { tree gtype = TREE_TYPE (type), rtype, type_decl; - for (dim = sym->as->rank - 1; dim >= 0; dim--) + for (dim = as->rank - 1; dim >= 0; dim--) { tree lbound, ubound; lbound = GFC_TYPE_ARRAY_LBOUND (type, dim); @@ -1014,41 +1019,56 @@ tree decl; tree type; gfc_array_spec *as; + symbol_attribute *array_attr; char *name; gfc_packed packed; int n; bool known_size; + bool is_classarray = IS_CLASS_ARRAY (sym); - if (sym->attr.pointer || sym->attr.allocatable - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) + /* Use the array as and attr. */ + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + + /* The dummy is returned for pointer, allocatable or assumed rank arrays. + For class arrays the information if sym is an allocatable or pointer + object needs to be checked explicitly (IS_CLASS_ARRAY can be false for + too many reasons to be of use here). */ + if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) + || array_attr->allocatable + || (as && as->type == AS_ASSUMED_RANK)) return dummy; - /* Add to list of variables if not a fake result variable. */ + /* Add to list of variables if not a fake result variable. + These symbols are set on the symbol only, not on the class component. */ if (sym->attr.result || sym->attr.dummy) gfc_defer_symbol_init (sym); - type = TREE_TYPE (dummy); + /* For a class array the array descriptor is in the _data component, while + for a regular array the TREE_TYPE of the dummy is a pointer to the + descriptor. */ + type = TREE_TYPE (is_classarray ? gfc_class_data_get (dummy) + : TREE_TYPE (dummy)); + /* type now is the array descriptor w/o any indirection. */ gcc_assert (TREE_CODE (dummy) == PARM_DECL - && POINTER_TYPE_P (type)); + && POINTER_TYPE_P (TREE_TYPE (dummy))); /* Do we know the element size? */ known_size = sym->ts.type != BT_CHARACTER || INTEGER_CST_P (sym->ts.u.cl->backend_decl); - if (known_size && !GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (type))) + if (known_size && !GFC_DESCRIPTOR_TYPE_P (type)) { /* For descriptorless arrays with known element size the actual argument is sufficient. */ - gcc_assert (GFC_ARRAY_TYPE_P (type)); gfc_build_qualified_array (dummy, sym); return dummy; } - type = TREE_TYPE (type); if (GFC_DESCRIPTOR_TYPE_P (type)) { /* Create a descriptorless array pointer. */ - as = sym->as; packed = PACKED_NO; /* Even when -frepack-arrays is used, symbols with TARGET attribute @@ -1079,8 +1099,11 @@ packed = PACKED_PARTIAL; } - type = gfc_typenode_for_spec (&sym->ts); - type = gfc_get_nodesc_array_type (type, sym->as, packed, + /* For classarrays the element type is required, but + gfc_typenode_for_spec () returns the array descriptor. */ + type = is_classarray ? gfc_get_element_type (type) + : gfc_typenode_for_spec (&sym->ts); + type = gfc_get_nodesc_array_type (type, as, packed, !sym->attr.target); } else @@ -1110,7 +1133,7 @@ /* We should never get deferred shape arrays here. We used to because of frontend bugs. */ - gcc_assert (sym->as->type != AS_DEFERRED); + gcc_assert (as->type != AS_DEFERRED); if (packed == PACKED_PARTIAL) GFC_DECL_PARTIAL_PACKED_ARRAY (decl) = 1; @@ -1429,6 +1452,23 @@ sym->backend_decl = decl; } + /* Returning the descriptor for dummy class arrays is hazardous, because + some caller is expecting an expression to apply the component refs to. + Therefore the descriptor is only created and stored in + sym->backend_decl's GFC_DECL_SAVED_DESCRIPTOR. The caller is then + responsible to extract it from there, when the descriptor is + desired. */ + if (IS_CLASS_ARRAY (sym) + && (!DECL_LANG_SPECIFIC (sym->backend_decl) + || !GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl))) + { + decl = gfc_build_dummy_array_decl (sym, sym->backend_decl); + /* Prevent the dummy from being detected as unused if it is copied. */ + if (sym->backend_decl != NULL && decl != sym->backend_decl) + DECL_ARTIFICIAL (sym->backend_decl) = 1; + sym->backend_decl = decl; + } + TREE_USED (sym->backend_decl) = 1; if (sym->attr.assign && GFC_DECL_ASSIGN (sym->backend_decl) == 0) { @@ -1435,7 +1475,7 @@ gfc_add_assign_aux_vars (sym); } - if (sym->attr.dimension + if ((sym->attr.dimension || IS_CLASS_ARRAY (sym)) && DECL_LANG_SPECIFIC (sym->backend_decl) && GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl) && DECL_CONTEXT (sym->backend_decl) != current_function_decl) @@ -3976,18 +4016,31 @@ = gfc_class_set_static_fields (sym->backend_decl, vptr, tmp); TREE_CONSTANT (DECL_INITIAL (sym->backend_decl)) = 1; } - else if (sym->attr.dimension || sym->attr.codimension) + else if (sym->attr.dimension || sym->attr.codimension + || (IS_CLASS_ARRAY (sym) && !CLASS_DATA (sym)->attr.allocatable)) { - /* Assumed-size Cray pointees need to be treated as AS_EXPLICIT. */ - array_type tmp = sym->as->type; - if (tmp == AS_ASSUMED_SIZE && sym->as->cp_was_assumed) - tmp = AS_EXPLICIT; - switch (tmp) + bool is_classarray = IS_CLASS_ARRAY (sym); + symbol_attribute *array_attr; + gfc_array_spec *as; + array_type tmp; + + array_attr = is_classarray ? &CLASS_DATA (sym)->attr : &sym->attr; + as = is_classarray ? CLASS_DATA (sym)->as : sym->as; + /* Assumed-size Cray pointees need to be treated as AS_EXPLICIT. */ + tmp = as->type; + if (tmp == AS_ASSUMED_SIZE && as->cp_was_assumed) + tmp = AS_EXPLICIT; + switch (tmp) { case AS_EXPLICIT: if (sym->attr.dummy || sym->attr.result) gfc_trans_dummy_array_bias (sym, sym->backend_decl, block); - else if (sym->attr.pointer || sym->attr.allocatable) + /* Allocatable and pointer arrays need to processed + explicitly. */ + else if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS + && CLASS_DATA (sym)->attr.class_pointer) + || array_attr->allocatable) { if (TREE_STATIC (sym->backend_decl)) { @@ -4002,7 +4055,8 @@ gfc_trans_deferred_array (sym, block); } } - else if (sym->attr.codimension && TREE_STATIC (sym->backend_decl)) + else if (sym->attr.codimension + && TREE_STATIC (sym->backend_decl)) { gfc_init_block (&tmpblock); gfc_trans_array_cobounds (TREE_TYPE (sym->backend_decl), @@ -4041,7 +4095,7 @@ case AS_ASSUMED_SIZE: /* Must be a dummy parameter. */ - gcc_assert (sym->attr.dummy || sym->as->cp_was_assumed); + gcc_assert (sym->attr.dummy || as->cp_was_assumed); /* We should always pass assumed size arrays the g77 way. */ if (sym->attr.dummy) @@ -4103,6 +4157,7 @@ } else { + se.descriptor_only = 1; gfc_conv_expr (&se, e); descriptor = se.expr; se.expr = gfc_conv_descriptor_data_addr (se.expr); Index: gcc/fortran/trans.h =================================================================== --- gcc/fortran/trans.h (Revision 222360) +++ gcc/fortran/trans.h (Arbeitskopie) @@ -49,6 +49,10 @@ /* The length of a character string value. */ tree string_length; + /* When expr is a reference to a class object, store its vptr access + here. */ + tree class_vptr; + /* If set gfc_conv_variable will return an expression for the array descriptor. When set, want_pointer should also be set. If not set scalarizing variables will be substituted. */ @@ -528,7 +532,7 @@ tree gfc_build_addr_expr (tree, tree); /* Build an ARRAY_REF. */ -tree gfc_build_array_ref (tree, tree, tree); +tree gfc_build_array_ref (tree, tree, tree, tree vptr = NULL_TREE); /* Creates a label. Decl is artificial if label_id == NULL_TREE. */ tree gfc_build_label_decl (tree); Index: gcc/fortran/trans-array.c =================================================================== --- gcc/fortran/trans-array.c (Revision 222360) +++ gcc/fortran/trans-array.c (Arbeitskopie) @@ -2495,11 +2495,14 @@ case GFC_SS_REFERENCE: /* Scalar argument to elemental procedure. */ gfc_init_se (&se, NULL); - if (ss_info->can_be_null_ref) + if (ss_info->can_be_null_ref || (expr->symtree + && (expr->symtree->n.sym->ts.type == BT_DERIVED + || expr->symtree->n.sym->ts.type == BT_CLASS))) { /* If the actual argument can be absent (in other words, it can be a NULL reference), don't try to evaluate it; pass instead - the reference directly. */ + the reference directly. The reference is also needed when + expr is of type class or derived. */ gfc_conv_expr_reference (&se, expr); } else @@ -3046,7 +3049,14 @@ return false; } else if (class_ref == NULL) - decl = expr->symtree->n.sym->backend_decl; + { + decl = expr->symtree->n.sym->backend_decl; + /* For class arrays the tree containing the class is stored in + GFC_DECL_SAVED_DESCRIPTOR of the sym's backend_decl. + For all others it's sym's backend_decl directly. */ + if (DECL_LANG_SPECIFIC (decl) && GFC_DECL_SAVED_DESCRIPTOR (decl)) + decl = GFC_DECL_SAVED_DESCRIPTOR (decl); + } else { /* Remove everything after the last class reference, convert the @@ -3155,20 +3165,35 @@ static tree -build_array_ref (tree desc, tree offset, tree decl) +build_array_ref (tree desc, tree offset, tree decl, tree vptr) { tree tmp; tree type; + tree cdecl; + bool classarray = false; + /* For class arrays the class declaration is stored in the saved + descriptor. */ + if (INDIRECT_REF_P (desc) + && DECL_LANG_SPECIFIC (TREE_OPERAND (desc, 0)) + && GFC_DECL_SAVED_DESCRIPTOR (TREE_OPERAND (desc, 0))) + cdecl = gfc_class_data_get (GFC_DECL_SAVED_DESCRIPTOR ( + TREE_OPERAND (desc, 0))); + else + cdecl = desc; + /* Class container types do not always have the GFC_CLASS_TYPE_P but the canonical type does. */ - if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (desc)) - && TREE_CODE (desc) == COMPONENT_REF) + if (GFC_DESCRIPTOR_TYPE_P (TREE_TYPE (cdecl)) + && TREE_CODE (cdecl) == COMPONENT_REF) { - type = TREE_TYPE (TREE_OPERAND (desc, 0)); + type = TREE_TYPE (TREE_OPERAND (cdecl, 0)); if (TYPE_CANONICAL (type) && GFC_CLASS_TYPE_P (TYPE_CANONICAL (type))) - type = TYPE_CANONICAL (type); + { + type = TREE_TYPE (desc); + classarray = true; + } } else type = NULL; @@ -3175,10 +3200,10 @@ /* Class array references need special treatment because the assigned type size needs to be used to point to the element. */ - if (type && GFC_CLASS_TYPE_P (type)) + if (classarray) { - type = gfc_get_element_type (TREE_TYPE (desc)); - tmp = TREE_OPERAND (desc, 0); + type = gfc_get_element_type (type); + tmp = TREE_OPERAND (cdecl, 0); tmp = gfc_get_class_array_ref (offset, tmp); tmp = fold_convert (build_pointer_type (type), tmp); tmp = build_fold_indirect_ref_loc (input_location, tmp); @@ -3187,7 +3212,7 @@ tmp = gfc_conv_array_data (desc); tmp = build_fold_indirect_ref_loc (input_location, tmp); - tmp = gfc_build_array_ref (tmp, offset, decl); + tmp = gfc_build_array_ref (tmp, offset, decl, vptr); return tmp; } @@ -3350,7 +3375,8 @@ offset = fold_build2_loc (input_location, PLUS_EXPR, gfc_array_index_type, offset, cst_offset); - se->expr = build_array_ref (se->expr, offset, sym->backend_decl); + se->expr = build_array_ref (se->expr, offset, sym->ts.type == BT_CLASS ? + NULL_TREE : sym->backend_decl, se->class_vptr); } @@ -5570,7 +5596,7 @@ gfc_se se; gfc_array_spec *as; - as = sym->as; + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; for (dim = as->rank; dim < as->rank + as->corank; dim++) { @@ -5613,7 +5639,7 @@ int dim; - as = sym->as; + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; size = gfc_index_one_node; offset = gfc_index_zero_node; @@ -5900,12 +5926,17 @@ int checkparm; int no_repack; bool optional_arg; + gfc_array_spec *as; + bool is_classarray = IS_CLASS_ARRAY (sym); /* Do nothing for pointer and allocatable arrays. */ - if (sym->attr.pointer || sym->attr.allocatable) + if ((sym->ts.type != BT_CLASS && sym->attr.pointer) + || (sym->ts.type == BT_CLASS && CLASS_DATA (sym)->attr.class_pointer) + || sym->attr.allocatable + || (is_classarray && CLASS_DATA (sym)->attr.allocatable)) return; - if (sym->attr.dummy && gfc_is_nodesc_array (sym)) + if (!is_classarray && sym->attr.dummy && gfc_is_nodesc_array (sym)) { gfc_trans_g77_array (sym, block); return; @@ -5918,7 +5949,13 @@ type = TREE_TYPE (tmpdesc); gcc_assert (GFC_ARRAY_TYPE_P (type)); dumdesc = GFC_DECL_SAVED_DESCRIPTOR (tmpdesc); - dumdesc = build_fold_indirect_ref_loc (input_location, dumdesc); + if (is_classarray) + /* For a class array the dummy array descriptor is in the _class + component. */ + dumdesc = gfc_class_data_get (dumdesc); + else + dumdesc = build_fold_indirect_ref_loc (input_location, dumdesc); + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; gfc_start_block (&init); if (sym->ts.type == BT_CHARACTER @@ -5925,7 +5962,7 @@ && TREE_CODE (sym->ts.u.cl->backend_decl) == VAR_DECL) gfc_conv_string_length (sym->ts.u.cl, NULL, &init); - checkparm = (sym->as->type == AS_EXPLICIT + checkparm = (as->type == AS_EXPLICIT && (gfc_option.rtcheck & GFC_RTCHECK_BOUNDS)); no_repack = !(GFC_DECL_PACKED_ARRAY (tmpdesc) @@ -6001,9 +6038,9 @@ size = gfc_index_one_node; /* Evaluate the bounds of the array. */ - for (n = 0; n < sym->as->rank; n++) + for (n = 0; n < as->rank; n++) { - if (checkparm || !sym->as->upper[n]) + if (checkparm || !as->upper[n]) { /* Get the bounds of the actual parameter. */ dubound = gfc_conv_descriptor_ubound_get (dumdesc, gfc_rank_cst[n]); @@ -6019,7 +6056,7 @@ if (!INTEGER_CST_P (lbound)) { gfc_init_se (&se, NULL); - gfc_conv_expr_type (&se, sym->as->lower[n], + gfc_conv_expr_type (&se, as->lower[n], gfc_array_index_type); gfc_add_block_to_block (&init, &se.pre); gfc_add_modify (&init, lbound, se.expr); @@ -6027,13 +6064,13 @@ ubound = GFC_TYPE_ARRAY_UBOUND (type, n); /* Set the desired upper bound. */ - if (sym->as->upper[n]) + if (as->upper[n]) { /* We know what we want the upper bound to be. */ if (!INTEGER_CST_P (ubound)) { gfc_init_se (&se, NULL); - gfc_conv_expr_type (&se, sym->as->upper[n], + gfc_conv_expr_type (&se, as->upper[n], gfc_array_index_type); gfc_add_block_to_block (&init, &se.pre); gfc_add_modify (&init, ubound, se.expr); @@ -6086,7 +6123,7 @@ gfc_array_index_type, offset, tmp); /* The size of this dimension, and the stride of the next. */ - if (n + 1 < sym->as->rank) + if (n + 1 < as->rank) { stride = GFC_TYPE_ARRAY_STRIDE (type, n + 1); @@ -6234,7 +6271,7 @@ return; } - tmp = build_array_ref (desc, offset, NULL); + tmp = build_array_ref (desc, offset, NULL, NULL); /* Offset the data pointer for pointer assignments from arrays with subreferences; e.g. my_integer => my_type(:)%integer_component. */ @@ -6789,6 +6826,7 @@ tree from; tree to; tree base; + bool onebased = false; ndim = info->ref ? info->ref->u.ar.dimen : ss->dimen; @@ -6930,6 +6968,7 @@ gfc_array_index_type, to, tmp); from = gfc_index_one_node; } + onebased = integer_onep (from); gfc_conv_descriptor_lbound_set (&loop.pre, parm, gfc_rank_cst[dim], from); @@ -6986,13 +7025,29 @@ gfc_get_dataptr_offset (&loop.pre, parm, desc, offset, subref_array_target, expr); - if (((se->direct_byref || GFC_ARRAY_TYPE_P (TREE_TYPE (desc))) - && !se->data_not_needed) - || (se->use_offset && base != NULL_TREE)) + /* Force the offset to be -1, when the lower bound of the highest + dimension is one and the symbol is present and is not a + pointer/allocatable or associated. */ + if (onebased && se->use_offset + && expr->symtree + && !(expr->symtree->n.sym && expr->symtree->n.sym->ts.type == BT_CLASS + && !CLASS_DATA (expr->symtree->n.sym)->attr.class_pointer) + && !expr->symtree->n.sym->attr.allocatable + && !expr->symtree->n.sym->attr.pointer + && !expr->symtree->n.sym->attr.host_assoc + && !expr->symtree->n.sym->attr.use_assoc) { - /* Set the offset. */ - gfc_conv_descriptor_offset_set (&loop.pre, parm, base); + /* Set the offset to -1. */ + mpz_t minus_one; + mpz_init_set_si (minus_one, -1); + tmp = gfc_conv_mpz_to_tree (minus_one, gfc_index_integer_kind); + gfc_conv_descriptor_offset_set (&loop.pre, parm, tmp); } + else if (((se->direct_byref || GFC_ARRAY_TYPE_P (TREE_TYPE (desc))) + && !se->data_not_needed) + || (se->use_offset && base != NULL_TREE)) + /* Set the offset depending on base. */ + gfc_conv_descriptor_offset_set (&loop.pre, parm, base); else { /* Only the callee knows what the correct offset it, so just set Index: gcc/fortran/expr.c =================================================================== --- gcc/fortran/expr.c (Revision 222360) +++ gcc/fortran/expr.c (Arbeitskopie) @@ -4052,6 +4052,7 @@ gfc_lval_expr_from_sym (gfc_symbol *sym) { gfc_expr *lval; + gfc_array_spec *as; lval = gfc_get_expr (); lval->expr_type = EXPR_VARIABLE; lval->where = sym->declared_at; @@ -4059,10 +4060,10 @@ lval->symtree = gfc_find_symtree (sym->ns->sym_root, sym->name); /* It will always be a full array. */ - lval->rank = sym->as ? sym->as->rank : 0; + as = IS_CLASS_ARRAY (sym) ? CLASS_DATA (sym)->as : sym->as; + lval->rank = as ? as->rank : 0; if (lval->rank) - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? - CLASS_DATA (sym)->as : sym->as); + gfc_add_full_array_ref (lval, as); return lval; } Index: gcc/testsuite/gfortran.dg/finalize_10.f90 =================================================================== --- gcc/testsuite/gfortran.dg/finalize_10.f90 (Revision 222360) +++ gcc/testsuite/gfortran.dg/finalize_10.f90 (Arbeitskopie) @@ -27,8 +27,8 @@ ! Finalize CLASS + set default init ! { dg-final { scan-tree-dump-times "y->_vptr->_final \\(&desc.\[0-9\]+, y->_vptr->_size, 0\\);" 1 "original" } } ! { dg-final { scan-tree-dump "__builtin_memcpy \\(\\(void .\\) y->_data, \\(void .\\) y->_vptr->_def_init, \\((unsigned long|unsigned int|character\\(kind=4\\))\\) y->_vptr->_size\\);" "original" } } -! { dg-final { scan-tree-dump-times "x->_vptr->_final \\(&x->_data, x->_vptr->_size, 0\\);" 1 "original" } } -! { dg-final { scan-tree-dump-times "x->_vptr->_copy \\(x->_vptr->_def_init, &x->_data\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times "x->_vptr->_final \\(&parm.\[0-9\]+, x->_vptr->_size, 0\\);" 1 "original" } } +! { dg-final { scan-tree-dump-times "x->_vptr->_copy \\(" 1 "original" } } ! FINALIZE TYPE: ! { dg-final { scan-tree-dump-times "parm.\[0-9\]+.data = \\(void \\*\\) &\\(\\*aa.\[0-9\]+\\)\\\[0\\\];" 1 "original" } } Index: gcc/testsuite/gfortran.dg/finalize_15.f90 =================================================================== --- gcc/testsuite/gfortran.dg/finalize_15.f90 (Revision 222360) +++ gcc/testsuite/gfortran.dg/finalize_15.f90 (Arbeitskopie) @@ -9,37 +9,37 @@ implicit none type t1 - integer :: i + integer :: i = 1 contains final :: fini_elem end type t1 type, extends(t1) :: t1e - integer :: j + integer :: j = 11 contains final :: fini_elem2 end type t1e type t2 - integer :: i + integer :: i = 2 contains final :: fini_shape end type t2 type, extends(t2) :: t2e - integer :: j + integer :: j = 22 contains final :: fini_shape2 end type t2e type t3 - integer :: i + integer :: i = 3 contains final :: fini_explicit end type t3 type, extends(t3) :: t3e - integer :: j + integer :: j = 33 contains final :: fini_explicit2 end type t3e @@ -204,31 +204,31 @@ select type(x) type is (t1e) - call check_val(x%i, 1) - call check_val(x%j, 100) + call check_val(x%i, 1, 1) + call check_val(x%j, 100, 11) end select select type(y) type is (t2e) - call check_val(y%i, 1) - call check_val(y%j, 100) + call check_val(y%i, 1, 2) + call check_val(y%j, 100, 22) end select select type(z) type is (t3e) - call check_val(z%i, 1) - call check_val(z%j, 100) + call check_val(z%i, 1, 3) + call check_val(z%j, 100, 33) end select contains - subroutine check_val(x, factor) + subroutine check_val(x, factor, val) integer :: x(:,:) - integer, value :: factor + integer, value :: factor, val integer :: i, j do i = 1, 10 do j = 1, 10 if (mod (j-1, 2) == 0 .and. mod (i-1, 3) == 0) then - if (x(j,i) /= (j + 100*i)*factor*(-13)) call abort () + if (x(j,i) /= val) call abort () else if (x(j,i) /= (j + 100*i)*factor) call abort () end if Index: gcc/testsuite/ChangeLog =================================================================== --- gcc/testsuite/ChangeLog (Revision 222360) +++ gcc/testsuite/ChangeLog (Arbeitskopie) @@ -1,3 +1,14 @@ +2015-04-23 Andre Vehreschild <vehre@gmx.de> + + PR fortran/60322 + * gfortran.dg/class_allocate_19.f03: New test. + * gfortran.dg/class_array_20.f03: New test. + * gfortran.dg/class_array_21.f03: New test. + * gfortran.dg/finalize_10.f90: Corrected scan-trees. + * gfortran.dg/finalize_15.f90: Fixing comparision to model + initialization correctly. + * gfortran.dg/finalize_29.f08: New test. + 2015-04-22 Bill Schmidt <wschmidt@linux.vnet.ibm.com> * gcc.target/powerpc/swaps-p8-18.c: New test. ^ permalink raw reply [flat|nested] 18+ messages in thread
* Re: [commited, Patch, Fortran, pr60322, addendum] was: [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array 2015-04-23 11:34 ` [commited, Patch, " Andre Vehreschild @ 2015-04-27 17:43 ` Andre Vehreschild 0 siblings, 0 replies; 18+ messages in thread From: Andre Vehreschild @ 2015-04-27 17:43 UTC (permalink / raw) To: Paul Richard Thomas Cc: Mikael Morin, GCC-Fortran-ML, GCC-Patches-ML, Antony Lewis, Dominique Dhumieres [-- Attachment #1: Type: text/plain, Size: 18662 bytes --] Hi all, sorry, I forgot to svn-add the testcases for the patch of pr60322. I fixed this with commit r222478. My apologies for the oversight. Regards, Andre On Thu, 23 Apr 2015 13:34:16 +0200 Andre Vehreschild <vehre@gmx.de> wrote: > Hi Paul, hi all, > > Paul, thanks for the review. I have commited this as r222361. > > Regards, > Andre > > On Thu, 16 Apr 2015 21:13:31 +0200 > Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: > > > Hi Andre, > > > > The delta patch is OK for trunk and eventual backport to 5.2. > > > > Thanks for all the hard work > > > > Paul > > > > On 14 April 2015 at 19:00, Andre Vehreschild <vehre@gmx.de> wrote: > > > Hi all, > > > > > > during further testing of a big Fortran software I encounter two bugs with > > > class arrays, that are somehow connected to pr60322. I therefore propose > > > an extended patch for pr60322. Because Paul has already reviewed most the > > > extended patch, I give you two patches: > > > > > > 1. a full patch, fixing all the issues connected to pr60322, and > > > 2. a delta patch to get from the reviewed patch to the latest version. > > > > > > With the second patch I hope to get a faster review, because it is > > > significantly shorter. > > > > > > Now what was the issue? To be precise there were two issues: > > > > > > i. a pointer to a class array (CLASS_DATA(sym).attr.class_pointer == 1) > > > was dereferenced, which lead to an ICE (the patch for this in the delta is > > > chunk 5 in gfc_conv_expr_descriptor, and > > > > > > ii. (and this was a severe brain cracker) in chains of references > > > consisting of more then one class-(array)-ref always the _vptr of the > > > first symbol was taken and not the _vptr of the currently dereferenced > > > class object. This occurred when fortran code similiar to this was > > > executed: > > > > > > type innerT > > > integer, allocatable :: arr(:) > > > end type > > > > > > type T > > > class(innerT) :: mat(:,:) > > > end type > > > > > > class(T) :: o > > > > > > allocate(o%mat(2,2)) > > > allocate(o%mat(:,:)%arr(10)) ! This is obviously pseudo code, > > > ! but I think you get what is meant. > > > > > > o%mat(1,1)%arr(1) = 1 > > > > > > In the last line the address to get to arr(1) was computed using the > > > _vptr->size of o and not of o%mat(1,1). To fix this gfc_component_ref () > > > now computes the class' _vptr-ref whenever it does a _data-ref (chunk 1 of > > > trans-expr.c in the delta patch). The _vptr-ref is stored in gfc_se, > > > where I added the new member class_vptr. The gfc_se->class_vptr is then > > > used in array-refs (chunk 2 of trans.c) to get the size of the array > > > elements of the correct level. > > > > > > The other chunks of the delta patch are: > > > - parameter passing fixes, and > > > - documentation fixes as requested for the version 5 of the pr60322 patch. > > > > > > I hope this helps in getting the patch reviewed quickly. > > > > > > Bootstraps and regtests ok on x86_64-linux-gnu/F21. > > > > > > Ok for trunk -> 6.0? > > > Ok, for backport to 5.2, once available? > > > > > > Note, the patches may apply with shifts, as I forgot to update before > > > taking the diffs. > > > > > > Regards, > > > Andre > > > > > > On Thu, 9 Apr 2015 14:37:09 +0200 > > > Andre Vehreschild <vehre@gmx.de> wrote: > > > > > >> Hi Paul, hi all, > > >> > > >> Paul, thanks for the review. Answers to your questions are inline below: > > >> > > >> On Sun, 5 Apr 2015 11:13:05 +0200 > > >> Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: > > >> <snip> > > >> > + /* The dummy is returned for pointer, allocatable or assumed rank > > >> > arrays. > > >> > + The check for pointerness needs to be repeated here (it is done > > >> > in > > >> > + IS_CLASS_ARRAY (), too), because for class arrays that are > > >> > pointers, as > > >> > + is the one of the sym, which is incorrect here. */ > > >> > > > >> > What does this mean, please? > > >> > > >> The first sentence is about regular arrays and should be unchanged from > > >> the original source. Then I have to check for class (arrays) that are > > >> pointers, i.e., independent of whether the sym is a class array or a > > >> regular pointer to a class object. (The latter shouldn't make it into > > >> the routine anyway.) IS_CLASS_ARRAY () returns false for too many > > >> reasons to be of use here. I have to apologize and confess that the > > >> comment was a mere note to myself to not return to use is_classarray in > > >> the if below. Let me rephrase the comment to be: > > >> > > >> /* The dummy is returned for pointer, allocatable or assumed rank arrays. > > >> For class arrays the information if sym is an allocatable or pointer > > >> object needs to be checked explicitly (IS_CLASS_ARRAY can be false for > > >> too many reasons to be of use here). */ > > >> > > >> > + /* Returning the descriptor for dummy class arrays is hazardous, > > >> > because > > >> > + some caller is expecting an expression to apply the component > > >> > refs to. > > >> > + Therefore the descriptor is only created and stored in > > >> > + sym->backend_decl's GFC_DECL_SAVED_DESCRIPTOR. The caller is > > >> > then > > >> > + responsible to extract it from there, when the descriptor is > > >> > + desired. */ > > >> > + if (IS_CLASS_ARRAY (sym) > > >> > + && (!DECL_LANG_SPECIFIC (sym->backend_decl) > > >> > + || !GFC_DECL_SAVED_DESCRIPTOR (sym->backend_decl))) > > >> > + { > > >> > + decl = gfc_build_dummy_array_decl (sym, sym->backend_decl); > > >> > + /* Prevent the dummy from being detected as unused if it is > > >> > copied. */ > > >> > + if (sym->backend_decl != NULL && decl != sym->backend_decl) > > >> > + DECL_ARTIFICIAL (sym->backend_decl) = 1; > > >> > + sym->backend_decl = decl; > > >> > + } > > >> > > > >> > The comments, such as the above are often going well beyond column 72, > > >> > into the 80's. I know that much of the existing code violates this > > >> > style requirement but there is no need to do so if clarity is not > > >> > reduced thereby. > > >> > > >> Er, the document at > > >> > > >> https://gcc.gnu.org/codingconventions.html#C_Formatting > > >> > > >> says that line length is 80, or is there another convention, that I am > > >> not aware of? > > >> > > >> > In trans-stmt.c s/standart/standard/ > > >> > > >> Fixed. > > >> > > >> > Don't forget to put the PR numbers in the ChangeLogs. > > >> > > >> I won't anymore, already got told off :-) > > >> > > >> > For this submission, I would have appreciated some a description of > > >> > what each chunk in the patch is doing, just because there is so much > > >> > of it. I suppose that it was good for my imortal soul to sort it out > > >> > for myself but it took a little while :-) > > >> > > >> I initially tried to split the submission in two parts to make it more > > >> manageable. One part with the brain-dead substitutions of as and > > >> array_attr and one with the new code. Albeit I failed to get the > > >> brain-dead part right and made some mistakes there already, which Mikael > > >> pointed out. I therefore went for the big submission. > > >> > > >> Now doing a description of what each "chunk" does is quite tedious. I > > >> really would like to spend my time more productive. Would you be > > >> satisfied, when I write a story about the patch, referring to some parts > > >> more explicitly, like > > >> > > >> "Chunk 4 of file trans-stmt.c is the heart of the patch and does this and > > >> that. The remaining chunks are more or less putting the data together." > > >> > > >> (This is not correct for this patch of course. Just an example.) More > > >> elaborate of course, but just to give an idea. > > >> > > >> Thanks again. I will commit as soon as 5.2/6.0 commit window is open. > > >> > > >> Regards, > > >> Andre > > >> > > >> > > > >> > Cheers and many thanks for the patch. > > >> > > > >> > Paul > > >> > > > >> > On 27 March 2015 at 13:48, Paul Richard Thomas > > >> > <paul.richard.thomas@gmail.com> wrote: > > >> > > Dear Andre, > > >> > > > > >> > > I am in the UK as of last night. Before leaving, I bootstrapped and > > >> > > regtested your patch and all was well. I must drive to Cambridge this > > >> > > afternoon to see my mother and will try to get to it either this > > >> > > evening or tomorrow morning. There is so much of it and it touches > > >> > > many places; so I must give it a very careful looking over before > > >> > > giving the green light. Bear with me please. > > >> > > > > >> > > Great work though! > > >> > > > > >> > > Paul > > >> > > > > >> > > On 24 March 2015 at 18:06, Andre Vehreschild <vehre@gmx.de> wrote: > > >> > >> Hi all, > > >> > >> > > >> > >> I have worked on the comments Mikael gave me. I am now checking for > > >> > >> class_pointer in the way he pointed out. > > >> > >> > > >> > >> Furthermore did I *join the two parts* of the patch into this one, > > >> > >> because keeping both in sync was no benefit but only tedious and did > > >> > >> not prove to be reviewed faster. > > >> > >> > > >> > >> Paul, Dominique: I have addressed the LOC issue that came up lately. > > >> > >> Or rather the patch addressed it already. I feel like this is not > > >> > >> tested very well, not the loc() call nor the sizeof() call as given > > >> > >> in the 57305 second's download. Unfortunately, is that download not > > >> > >> runable. I would love to see a test similar to that download, but > > >> > >> couldn't come up with one, that satisfied me. Given that the patch's > > >> > >> review will last some days, I still have enough time to come up with > > >> > >> something beautiful which I will add then. > > >> > >> > > >> > >> Bootstraps and regtests ok on x86_64-linux-gnu/F20. > > >> > >> > > >> > >> Regards, > > >> > >> Andre > > >> > >> > > >> > >> > > >> > >> On Tue, 24 Mar 2015 11:13:27 +0100 > > >> > >> Paul Richard Thomas <paul.richard.thomas@gmail.com> wrote: > > >> > >> > > >> > >>> Dear Andre, > > >> > >>> > > >> > >>> Dominique pointed out to me that the 'loc' patch causes a ICE in > > >> > >>> the testsuite. It seems that 'loc' should provide the address of > > >> > >>> the class container in some places and the address of the data in > > >> > >>> others. I will put my thinking cap on tonight :-) > > >> > >>> > > >> > >>> Cheers > > >> > >>> > > >> > >>> Paul > > >> > >>> > > >> > >>> On 23 March 2015 at 13:43, Andre Vehreschild <vehre@gmx.de> wrote: > > >> > >>> > Hi Mikael, > > >> > >>> > > > >> > >>> > thanks for looking at the patch. Please note, that Paul has sent > > >> > >>> > an addendum to the patches for 60322, which I deliberately have > > >> > >>> > attached. > > >> > >>> > > > >> > >>> >> 26/02/2015 18:17, Andre Vehreschild a écrit : > > >> > >>> >> > This first patch is only preparatory and does not change any > > >> > >>> >> > of the semantics of gfortran at all. > > >> > >>> >> Sure? > > >> > >>> > > > >> > >>> > With the counterexample you found below, this of course is a > > >> > >>> > wrong statement. > > >> > >>> > > > >> > >>> >> > diff --git a/gcc/fortran/expr.c b/gcc/fortran/expr.c > > >> > >>> >> > index ab6f7a5..d28cf77 100644 > > >> > >>> >> > --- a/gcc/fortran/expr.c > > >> > >>> >> > +++ b/gcc/fortran/expr.c > > >> > >>> >> > @@ -4059,10 +4060,10 @@ gfc_lval_expr_from_sym (gfc_symbol > > >> > >>> >> > *sym) lval->symtree = gfc_find_symtree (sym->ns->sym_root, > > >> > >>> >> > sym->name); > > >> > >>> >> > > > >> > >>> >> > /* It will always be a full array. */ > > >> > >>> >> > - lval->rank = sym->as ? sym->as->rank : 0; > > >> > >>> >> > + as = sym->as; > > >> > >>> >> > + lval->rank = as ? as->rank : 0; > > >> > >>> >> > if (lval->rank) > > >> > >>> >> > - gfc_add_full_array_ref (lval, sym->ts.type == BT_CLASS ? > > >> > >>> >> > - CLASS_DATA (sym)->as : sym->as); > > >> > >>> >> > + gfc_add_full_array_ref (lval, as); > > >> > >>> >> > > >> > >>> >> This is a change of semantics. Or do you know that > > >> > >>> >> sym->ts.type != BT_CLASS? > > >> > >>> > > > >> > >>> > You are completely right. I have made a mistake here. I have to > > >> > >>> > tell the truth, I never ran a regtest with only part 1 of the > > >> > >>> > patches applied. The second part of the patch will correct this, > > >> > >>> > by setting the variable as depending on whether type == BT_CLASS > > >> > >>> > or not. Sorry for the mistake. > > >> > >>> > > > >> > >>> >> > diff --git a/gcc/fortran/trans-decl.c > > >> > >>> >> > b/gcc/fortran/trans-decl.c index 3664824..e571a17 100644 > > >> > >>> >> > --- a/gcc/fortran/trans-decl.c > > >> > >>> >> > +++ b/gcc/fortran/trans-decl.c > > >> > >>> >> > @@ -1013,16 +1017,24 @@ gfc_build_dummy_array_decl > > >> > >>> >> > (gfc_symbol * sym, tree dummy) tree decl; > > >> > >>> >> > tree type; > > >> > >>> >> > gfc_array_spec *as; > > >> > >>> >> > + symbol_attribute *array_attr; > > >> > >>> >> > char *name; > > >> > >>> >> > gfc_packed packed; > > >> > >>> >> > int n; > > >> > >>> >> > bool known_size; > > >> > >>> >> > > > >> > >>> >> > - if (sym->attr.pointer || sym->attr.allocatable > > >> > >>> >> > - || (sym->as && sym->as->type == AS_ASSUMED_RANK)) > > >> > >>> >> > + /* Use the array as and attr. */ > > >> > >>> >> > + as = sym->as; > > >> > >>> >> > + array_attr = &sym->attr; > > >> > >>> >> > + > > >> > >>> >> > + /* The pointer attribute is always set on a _data > > >> > >>> >> > component, therefore check > > >> > >>> >> > + the sym's attribute only. */ > > >> > >>> >> > + if (sym->attr.pointer || array_attr->allocatable > > >> > >>> >> > + || (as && as->type == AS_ASSUMED_RANK)) > > >> > >>> >> > return dummy; > > >> > >>> >> > > > >> > >>> >> Any reason to sometimes use array_attr, sometimes not, like > > >> > >>> >> here? By the way, the comment is misleading: for classes, there > > >> > >>> >> is the class_pointer attribute (and it is a pain, I know). > > >> > >>> > > > >> > >>> > Yes, and a good one. Array_attr is sometimes sym->attr and > > >> > >>> > sometimes CLASS_DATA(sym)->attr aka > > >> > >>> > sym->ts.u.derived->components->attr. In the later case .pointer > > >> > >>> > is always set to 1 in the _data component's attr. I.e., the > > >> > >>> > above if, would always yield true for a class_array, which is > > >> > >>> > not intended, but rather destructive. I know about the > > >> > >>> > class_pointer attribute, but I figured, that it is not relevant > > >> > >>> > here. Any idea how to formulate the comment better, to reflect > > >> > >>> > what I just explained? > > >> > >>> > > > >> > >>> > Regards, > > >> > >>> > Andre > > >> > >>> > -- > > >> > >>> > Andre Vehreschild * Email: vehre ad gmx dot de > > >> > >>> > > > >> > >>> > > > >> > >>> > ---------- Forwarded message ---------- > > >> > >>> > From: Paul Richard Thomas <paul.richard.thomas@gmail.com> > > >> > >>> > To: Andre Vehreschild <vehre@gmx.de>, Dominique Dhumieres > > >> > >>> > <dominiq@lps.ens.fr> Cc: > > >> > >>> > Date: Sun, 22 Mar 2015 21:20:20 +0100 > > >> > >>> > Subject: Bug in intrinsic LOC for scalar class objects > > >> > >>> > Dear Andre and Dominique, > > >> > >>> > > > >> > >>> > I have found that LOC is returning the address of the class > > >> > >>> > container rather than the _data component for class scalars. See > > >> > >>> > the source below, which you will recognise! A fix is attached. > > >> > >>> > > > >> > >>> > Note that the scalar allocate fails with MOLD= and so I > > >> > >>> > substituted SOURCE=. > > >> > >>> > > > >> > >>> > Cheers > > >> > >>> > > > >> > >>> > Paul > > >> > >>> > > > >> > >>> > class(*), allocatable :: a(:), e ! Change 'e' to an array and > > >> > >>> > second memcpy works correctly > > >> > >>> > ! Problem is with loc(e), > > >> > >>> > which returns the address of the > > >> > >>> > ! class container. > > >> > >>> > allocate (e, source = 99.0) > > >> > >>> > allocate (a(2), source = [1.0, 2.0]) > > >> > >>> > call add_element_poly (a,e) > > >> > >>> > select type (a) > > >> > >>> > type is (real) > > >> > >>> > print *, a > > >> > >>> > end select > > >> > >>> > > > >> > >>> > contains > > >> > >>> > > > >> > >>> > subroutine add_element_poly(a,e) > > >> > >>> > use iso_c_binding > > >> > >>> > class(*),allocatable,intent(inout),target :: a(:) > > >> > >>> > class(*),intent(in),target :: e > > >> > >>> > class(*),allocatable,target :: tmp(:) > > >> > >>> > type(c_ptr) :: dummy > > >> > >>> > > > >> > >>> > interface > > >> > >>> > function memcpy(dest,src,n) bind(C,name="memcpy") > > >> > >>> > result(res) import > > >> > >>> > type(c_ptr) :: res > > >> > >>> > integer(c_intptr_t),value :: dest > > >> > >>> > integer(c_intptr_t),value :: src > > >> > >>> > integer(c_size_t),value :: n > > >> > >>> > end function > > >> > >>> > end interface > > >> > >>> > > > >> > >>> > if (.not.allocated(a)) then > > >> > >>> > allocate(a(1), source=e) > > >> > >>> > else > > >> > >>> > allocate(tmp(size(a)),source=a) > > >> > >>> > deallocate(a) > > >> > >>> > allocate(a(size(tmp)+1),source=e) ! mold gives a segfault > > >> > >>> > dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) > > >> > >>> > dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) > > >> > >>> > end if > > >> > >>> > end subroutine > > >> > >>> > end > > >> > >>> > > > >> > >>> > > >> > >>> > > >> > >>> > > >> > >> > > >> > >> > > >> > >> -- > > >> > >> Andre Vehreschild * Email: vehre ad gmx dot de > > >> > > > > >> > > > > >> > > > > >> > > -- > > >> > > Outside of a dog, a book is a man's best friend. Inside of a dog it's > > >> > > too dark to read. > > >> > > > > >> > > Groucho Marx > > >> > > > >> > > > >> > > > >> > > >> > > > > > > > > > -- > > > Andre Vehreschild * Email: vehre ad gmx dot de > > > > > > > > -- Andre Vehreschild * Email: vehre ad gmx dot de [-- Attachment #2: submit.diff --] [-- Type: text/x-patch, Size: 16579 bytes --] Index: gcc/testsuite/gfortran.dg/class_allocate_19.f03 =================================================================== --- gcc/testsuite/gfortran.dg/class_allocate_19.f03 (Revision 0) +++ gcc/testsuite/gfortran.dg/class_allocate_19.f03 (Revision 222478) @@ -0,0 +1,47 @@ +! { dg-do run } +! +! Contributed by: Vladimir Fuka <vladimir.fuka@gmail.com> + +use iso_c_binding +implicit none +real, target :: e +class(*), allocatable, target :: a(:) +e = 1.0 +call add_element_poly(a,e) +if (size(a) /= 1) call abort() +call add_element_poly(a,e) +if (size(a) /= 2) call abort() +select type (a) + type is (real) + if (any (a /= [ 1, 1])) call abort() +end select +contains + subroutine add_element_poly(a,e) + use iso_c_binding + class(*),allocatable,intent(inout),target :: a(:) + class(*),intent(in),target :: e + class(*),allocatable,target :: tmp(:) + type(c_ptr) :: dummy + + interface + function memcpy(dest,src,n) bind(C,name="memcpy") result(res) + import + type(c_ptr) :: res + integer(c_intptr_t),value :: dest + integer(c_intptr_t),value :: src + integer(c_size_t),value :: n + end function + end interface + + if (.not.allocated(a)) then + allocate(a(1), source=e) + else + allocate(tmp(size(a)),source=a) + deallocate(a) + allocate(a(size(tmp)+1),mold=e) + dummy = memcpy(loc(a(1)),loc(tmp),sizeof(tmp)) + dummy = memcpy(loc(a(size(tmp)+1)),loc(e),sizeof(e)) + end if + end subroutine +end + Index: gcc/testsuite/gfortran.dg/class_array_20.f03 =================================================================== --- gcc/testsuite/gfortran.dg/class_array_20.f03 (Revision 0) +++ gcc/testsuite/gfortran.dg/class_array_20.f03 (Revision 222478) @@ -0,0 +1,100 @@ +! {dg-do run} +! +! Test contributed by Thomas L. Clune via pr60322 +! and Antony Lewis via pr64692 + +program class_array_20 + implicit none + + type Foo + end type + + type(foo), dimension(2:3) :: arg + integer :: oneDarr(2) + integer :: twoDarr(2,3) + integer :: x, y + double precision :: P(2, 2) + + ! Checking for PR/60322 + call copyFromClassArray([Foo(), Foo()]) + call copyFromClassArray(arg) + call copyFromClassArray(arg(:)) + + x= 3 + y= 4 + oneDarr = [x, y] + call W([x, y]) + call W(oneDarr) + call W([3, 4]) + + twoDarr = reshape([3, 4, 5, 5, 6, 7], [2, 3]) + call WtwoD(twoDarr) + call WtwoD(reshape([3, 4, 5, 5, 6, 7], [2, 3])) + + ! Checking for PR/64692 + P(1:2, 1) = [1.d0, 2.d0] + P(1:2, 2) = [3.d0, 4.d0] + call AddArray(P(1:2, 2)) + +contains + + subroutine copyFromClassArray(classarray) + class (Foo), intent(in) :: classarray(:) + + if (lbound(classarray, 1) .ne. 1) call abort() + if (ubound(classarray, 1) .ne. 2) call abort() + if (size(classarray) .ne. 2) call abort() + end subroutine + + subroutine AddArray(P) + class(*), target, intent(in) :: P(:) + class(*), pointer :: Pt(:) + + allocate(Pt(1:size(P)), source= P) + + select type (P) + type is (double precision) + if (abs(P(1)-3.d0) .gt. 1.d-8) call abort() + if (abs(P(2)-4.d0) .gt. 1.d-8) call abort() + class default + call abort() + end select + + select type (Pt) + type is (double precision) + if (abs(Pt(1)-3.d0) .gt. 1.d-8) call abort() + if (abs(Pt(2)-4.d0) .gt. 1.d-8) call abort() + class default + call abort() + end select + end subroutine + + subroutine W(ar) + class(*), intent(in) :: ar(:) + + if (lbound(ar, 1) /= 1) call abort() + select type (ar) + type is (integer) + ! The indeces 1:2 are essential here, or else one would not + ! note, that the array internally starts at 0, although the + ! check for the lbound above went fine. + if (any (ar(1:2) .ne. [3, 4])) call abort() + class default + call abort() + end select + end subroutine + + subroutine WtwoD(ar) + class(*), intent(in) :: ar(:,:) + + if (any (lbound(ar) /= [1, 1])) call abort() + select type (ar) + type is (integer) + if (any (reshape(ar(1:2,1:3), [6]) .ne. [3, 4, 5, 5, 6, 7])) & + call abort() + class default + call abort() + end select + end subroutine +end program class_array_20 + Index: gcc/testsuite/gfortran.dg/class_array_21.f03 =================================================================== --- gcc/testsuite/gfortran.dg/class_array_21.f03 (Revision 0) +++ gcc/testsuite/gfortran.dg/class_array_21.f03 (Revision 222478) @@ -0,0 +1,97 @@ +! {dg-do run} +! +! Contributed by Andre Vehreschild +! Check more elaborate class array addressing. + +module m1 + + type InnerBaseT + integer, allocatable :: a(:) + end type InnerBaseT + + type, extends(InnerBaseT) :: InnerT + integer :: i + end type InnerT + + type BaseT + class(InnerT), allocatable :: arr(:,:) + contains + procedure P + end type BaseT + +contains + + subroutine indir(this, mat) + class(BaseT) :: this + class(InnerT), intent(inout) :: mat(:,:) + + call this%P(mat) + end subroutine indir + + subroutine P(this, mat) + class(BaseT) :: this + class(InnerT), intent(inout) :: mat(:,:) + integer :: i,j + + mat%i = 42 + do i= 1, ubound(mat, 1) + do j= 1, ubound(mat, 2) + if (.not. allocated(mat(i,j)%a)) then + allocate(mat(i,j)%a(10), source = 72) + end if + end do + end do + mat(1,1)%i = 9 + mat(1,1)%a(5) = 1 + end subroutine + +end module m1 + +program test + use m1 + + class(BaseT), allocatable, target :: o + class(InnerT), pointer :: i_p(:,:) + class(InnerBaseT), allocatable :: i_a(:,:) + integer i,j,l + + allocate(o) + allocate(o%arr(2,2)) + allocate(InnerT::i_a(2,2)) + o%arr%i = 1 + + i_p => o%arr + call o%P(i_p) + if (any(o%arr%i /= reshape([9,42,42,42],[2,2]))) call abort() + do l= 1, 10 + do i= 1, 2 + do j= 1,2 + if ((i == 1 .and. j == 1 .and. l == 5 .and. & + o%arr(i,j)%a(5) /= 1) & + .or. (.not. (i == 1 .and. j == 1 .and. l == 5) & + .and. o%arr(i,j)%a(l) /= 72)) call abort() + end do + end do + end do + + select type (i_a) + type is (InnerT) + call o%P(i_a) + do l= 1, 10 + do i= 1, 2 + do j= 1,2 + if ((i == 1 .and. j == 1 .and. l == 5 .and. & + i_a(i,j)%a(5) /= 1) & + .or. (.not. (i == 1 .and. j == 1 .and. l == 5) & + .and. i_a(i,j)%a(l) /= 72)) call abort() + end do + end do + end do + end select + + i_p%i = 4 + call indir(o, i_p) + if (any(o%arr%i /= reshape([9,42,42,42],[2,2]))) call abort() +end program test + +! vim:ts=2:sts=2:cindent:sw=2:tw=80: Index: gcc/testsuite/gfortran.dg/finalize_29.f08 =================================================================== --- gcc/testsuite/gfortran.dg/finalize_29.f08 (Revision 0) +++ gcc/testsuite/gfortran.dg/finalize_29.f08 (Revision 222478) @@ -0,0 +1,289 @@ +! {dg-do run} +! +! Testcase contributed by Andre Vehreschild <vehre@gcc.gnu.org> + +module module_finalize_29 + implicit none + + ! The type name is encoding the state of its finalizer being + ! elemental (second letter 'e'), or non-element (second letter 'n') + ! or array shaped (second letter 'a'), or shape-specific routine + ! (generic; second letter 'g'), + ! and whether the init-routine is elemental or not (third letter + ! either 'e' or 'n'). + type ten + integer :: i = 40 + contains + final :: ten_fin + end type ten + + type tee + integer :: i = 41 + contains + final :: tee_fin + end type tee + + type tne + integer :: i = 42 + contains + final :: tne_fin + end type tne + + type tnn + integer :: i = 43 + contains + final :: tnn_fin + end type tnn + + type tae + integer :: i = 44 + contains + final :: tae_fin + end type tae + + type tan + integer :: i = 45 + contains + final :: tan_fin + end type tan + + type tge + integer :: i = 46 + contains + final :: tge_scalar_fin, tge_array_fin + end type tge + + type tgn + integer :: i = 47 + contains + final :: tgn_scalar_fin, tgn_array_fin + end type tgn + + integer :: ten_fin_counts, tee_fin_counts, tne_fin_counts, tnn_fin_counts + integer :: tae_fin_counts, tan_fin_counts + integer :: tge_scalar_fin_counts, tge_array_fin_counts + integer :: tgn_scalar_fin_counts, tgn_array_fin_counts +contains + impure elemental subroutine ten_fin(x) + type(ten), intent(inout) :: x + x%i = -10 * x%i + ten_fin_counts = ten_fin_counts + 1 + end subroutine ten_fin + + impure elemental subroutine tee_fin(x) + type(tee), intent(inout) :: x + x%i = -11 * x%i + tee_fin_counts = tee_fin_counts + 1 + end subroutine tee_fin + + subroutine tne_fin(x) + type(tne), intent(inout) :: x + x%i = -12 * x%i + tne_fin_counts = tne_fin_counts + 1 + end subroutine tne_fin + + subroutine tnn_fin(x) + type(tnn), intent(inout) :: x + x%i = -13 * x%i + tnn_fin_counts = tnn_fin_counts + 1 + end subroutine tnn_fin + + subroutine tae_fin(x) + type(tae), intent(inout) :: x(:,:) + x%i = -14 * x%i + tae_fin_counts = tae_fin_counts + 1 + end subroutine tae_fin + + subroutine tan_fin(x) + type(tan), intent(inout) :: x(:,:) + x%i = -15 * x%i + tan_fin_counts = tan_fin_counts + 1 + end subroutine tan_fin + + subroutine tge_scalar_fin(x) + type(tge), intent(inout) :: x + x%i = -16 * x%i + tge_scalar_fin_counts = tge_scalar_fin_counts + 1 + end subroutine tge_scalar_fin + + subroutine tge_array_fin(x) + type(tge), intent(inout) :: x(:,:) + x%i = -17 * x%i + tge_array_fin_counts = tge_array_fin_counts + 1 + end subroutine tge_array_fin + + subroutine tgn_scalar_fin(x) + type(tgn), intent(inout) :: x + x%i = -18 * x%i + tgn_scalar_fin_counts = tgn_scalar_fin_counts + 1 + end subroutine tgn_scalar_fin + + subroutine tgn_array_fin(x) + type(tgn), intent(inout) :: x(:,:) + x%i = -19 * x%i + tgn_array_fin_counts = tgn_array_fin_counts + 1 + end subroutine tgn_array_fin + + ! The finalizer/initializer call producer + subroutine ten_init(x) + class(ten), intent(out) :: x(:,:) + end subroutine ten_init + + impure elemental subroutine tee_init(x) + class(tee), intent(out) :: x + end subroutine tee_init + + impure elemental subroutine tne_init(x) + class(tne), intent(out) :: x + end subroutine tne_init + + subroutine tnn_init(x) + class(tnn), intent(out) :: x(:,:) + end subroutine tnn_init + + impure elemental subroutine tae_init(x) + class(tae), intent(out) :: x + end subroutine tae_init + + subroutine tan_init(x) + class(tan), intent(out) :: x(:,:) + end subroutine tan_init + + impure elemental subroutine tge_init(x) + class(tge), intent(out) :: x + end subroutine tge_init + + subroutine tgn_init(x) + class(tgn), intent(out) :: x(:,:) + end subroutine tgn_init +end module module_finalize_29 + +program finalize_29 + use module_finalize_29 + implicit none + + type(ten), allocatable :: x_ten(:,:) + type(tee), allocatable :: x_tee(:,:) + type(tne), allocatable :: x_tne(:,:) + type(tnn), allocatable :: x_tnn(:,:) + type(tae), allocatable :: x_tae(:,:) + type(tan), allocatable :: x_tan(:,:) + type(tge), allocatable :: x_tge(:,:) + type(tgn), allocatable :: x_tgn(:,:) + + ! Set the global counts to zero. + ten_fin_counts = 0 + tee_fin_counts = 0 + tne_fin_counts = 0 + tnn_fin_counts = 0 + tae_fin_counts = 0 + tan_fin_counts = 0 + tge_scalar_fin_counts = 0 + tge_array_fin_counts = 0 + tgn_scalar_fin_counts = 0 + tgn_array_fin_counts = 0 + + allocate(ten :: x_ten(5,5)) + allocate(tee :: x_tee(5,5)) + allocate(tne :: x_tne(5,5)) + allocate(tnn :: x_tnn(5,5)) + allocate(tae :: x_tae(5,5)) + allocate(tan :: x_tan(5,5)) + allocate(tge :: x_tge(5,5)) + allocate(tgn :: x_tgn(5,5)) + + x_ten%i = 1 + x_tee%i = 2 + x_tne%i = 3 + x_tnn%i = 4 + x_tae%i = 5 + x_tan%i = 6 + x_tge%i = 7 + x_tgn%i = 8 + + call ten_init(x_ten(::2, ::3)) + + if (ten_fin_counts /= 6) call abort() + if (tee_fin_counts + tne_fin_counts + tnn_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + ten_fin_counts = 0 + + call tee_init(x_tee(::2, ::3)) + + if (tee_fin_counts /= 6) call abort() + if (ten_fin_counts + tne_fin_counts + tnn_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tee_fin_counts = 0 + + call tne_init(x_tne(::2, ::3)) + + if (tne_fin_counts /= 6) call abort() + if (ten_fin_counts + tee_fin_counts + tnn_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tne_fin_counts = 0 + + call tnn_init(x_tnn(::2, ::3)) + + if (tnn_fin_counts /= 0) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tae_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + + call tae_init(x_tae(::2, ::3)) + + if (tae_fin_counts /= 0) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tan_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + + call tan_init(x_tan(::2, ::3)) + + if (tan_fin_counts /= 1) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tae_fin_counts + tge_scalar_fin_counts + tge_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tan_fin_counts = 0 + + call tge_init(x_tge(::2, ::3)) + + if (tge_scalar_fin_counts /= 6) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tae_fin_counts + tan_fin_counts + tgn_array_fin_counts + & + tgn_scalar_fin_counts + tgn_array_fin_counts /= 0) call abort() + tge_scalar_fin_counts = 0 + + call tgn_init(x_tgn(::2, ::3)) + + if (tgn_array_fin_counts /= 1) call abort() + if (ten_fin_counts + tee_fin_counts + tne_fin_counts + tnn_fin_counts + & + tae_fin_counts + tan_fin_counts + tge_scalar_fin_counts + & + tge_array_fin_counts + tgn_scalar_fin_counts /= 0) call abort() + tgn_array_fin_counts = 0 + + if (any (reshape (x_ten%i, [25]) /= [[40, 1, 40, 1, 40], [1, 1, 1, 1, 1],& + [1, 1, 1, 1, 1], [40, 1, 40, 1, 40], [1, 1, 1, 1, 1]])) call abort() + + if (any (reshape (x_tee%i, [25]) /= [[41, 2, 41, 2, 41], [2, 2, 2, 2, 2],& + [2, 2, 2, 2, 2], [41, 2, 41, 2, 41], [2, 2, 2, 2, 2]])) call abort() + + if (any (reshape (x_tne%i, [25]) /= [[42, 3, 42, 3, 42], [3, 3, 3, 3, 3],& + [3, 3, 3, 3, 3], [42, 3, 42, 3, 42], [3, 3, 3, 3, 3]])) call abort() + + if (any (reshape (x_tnn%i, [25]) /= [[43, 4, 43, 4, 43], [4, 4, 4, 4, 4],& + [4, 4, 4, 4, 4], [43, 4, 43, 4, 43], [4, 4, 4, 4, 4]])) call abort() + + if (any (reshape (x_tae%i, [25]) /= [[44, 5, 44, 5, 44], [5, 5, 5, 5, 5],& + [5, 5, 5, 5, 5], [44, 5, 44, 5, 44], [5, 5, 5, 5, 5]])) call abort() + + if (any (reshape (x_tan%i, [25]) /= [[45, 6, 45, 6, 45], [6, 6, 6, 6, 6],& + [6, 6, 6, 6, 6], [45, 6, 45, 6, 45], [6, 6, 6, 6, 6]])) call abort() + + if (any (reshape (x_tge%i, [25]) /= [[46, 7, 46, 7, 46], [7, 7, 7, 7, 7],& + [7, 7, 7, 7, 7], [46, 7, 46, 7, 46], [7, 7, 7, 7, 7]])) call abort() + + if (any (reshape (x_tgn%i, [25]) /= [[47, 8, 47, 8, 47], [8, 8, 8, 8, 8],& + [8, 8, 8, 8, 8], [47, 8, 47, 8, 47], [8, 8, 8, 8, 8]])) call abort() +end program finalize_29 Index: gcc/testsuite/ChangeLog =================================================================== --- gcc/testsuite/ChangeLog (Revision 222477) +++ gcc/testsuite/ChangeLog (Arbeitskopie) @@ -1,5 +1,14 @@ 2015-04-27 Andre Vehreschild <vehre@gmx.de> + PR fortran/60322 + Add tests forgotten to svn-add. + * gfortran.dg/class_allocate_19.f03: New test. + * gfortran.dg/class_array_20.f03: New test. + * gfortran.dg/class_array_21.f03: New test. + * gfortran.dg/finalize_29.f08: New test. + +2015-04-27 Andre Vehreschild <vehre@gmx.de> + PR fortran/59678 PR fortran/65841 * gfortran.dg/alloc_comp_deep_copy_1.f03: New test. ^ permalink raw reply [flat|nested] 18+ messages in thread
end of thread, other threads:[~2015-04-27 17:43 UTC | newest] Thread overview: 18+ messages (download: mbox.gz / follow: Atom feed) -- links below jump to the message on this page -- 2015-02-26 17:19 [Patch 1/2, Fortran, pr60322] [OOP] Incorrect bounds on polymorphic dummy array Andre Vehreschild 2015-03-23 12:29 ` Mikael Morin 2015-03-23 12:44 ` Andre Vehreschild 2015-03-23 14:58 ` Mikael Morin 2015-03-23 15:49 ` Andre Vehreschild 2015-03-23 19:28 ` Mikael Morin 2015-03-24 10:13 ` Paul Richard Thomas 2015-03-24 17:06 ` [Patch, Fortran, pr60322] was: " Andre Vehreschild 2015-03-25 9:43 ` Dominique d'Humières 2015-03-25 16:57 ` Andre Vehreschild 2015-03-26 9:27 ` Dominique d'Humières 2015-03-27 12:48 ` Paul Richard Thomas 2015-04-05 9:13 ` Paul Richard Thomas 2015-04-09 12:37 ` Andre Vehreschild 2015-04-14 17:01 ` [Patch, Fortran, pr60322, addendum] " Andre Vehreschild 2015-04-16 19:13 ` Paul Richard Thomas 2015-04-23 11:34 ` [commited, Patch, " Andre Vehreschild 2015-04-27 17:43 ` Andre Vehreschild
This is a public inbox, see mirroring instructions for how to clone and mirror all data and code used for this inbox; as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).