From: Paul Richard Thomas <paul.richard.thomas@gmail.com>
To: "fortran@gcc.gnu.org" <fortran@gcc.gnu.org>,
gcc-patches <gcc-patches@gcc.gnu.org>,
Harald Anlauf <anlauf@gmx.de>
Subject: [Patch, fortran] PR49213 - [OOP] gfortran rejects structure constructor expression
Date: Sat, 24 Jun 2023 14:18:54 +0100 [thread overview]
Message-ID: <CAGkQGiKPvpOMQSbx5tm9UGVvyGuDoEcQAR7WJMo7iQiYh9pL+A@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 1456 bytes --]
Hi All,
I was looking through Neil Carlson's collection of gfortran bugs and
was shocked to find this rather fundamental PR. At 12 years old, it is
certainly a "golden oldie"!
The patch is rather straightforward and seems to do the job of
admitting derived, intrinsic and character expressions to allocatable
class components in structure constructors.
I have included the adjustment to 'gfc_is_ptr_fcn' and eliminating the
extra blank line, introduced by my last patch. I played safe and went
exclusively for class functions with attr.class_pointer set on the
grounds that these have had all the accoutrements checked and built
(ie. class_ok). I am still not sure if this is necessary or not.
OK for trunk?
Paul
Fortran: Enable class expressions in structure constructors [PR49213]
2023-06-24 Paul Thomas <pault@gcc.gnu.org>
gcc/fortran
PR fortran/49213
* expr.cc (gfc_is_ptr_fcn): Guard pointer attribute to exclude
class expressions.
* resolve.cc (resolve_assoc_var): Call gfc_is_ptr_fcn to allow
associate names with pointer function targets to be used in
variable definition context.
* trans-decl.cc (get_symbol_decl): Remove extraneous line.
* trans-expr.cc (alloc_scalar_allocatable_subcomponent): Obtain
size of intrinsic and character expressions.
(gfc_trans_subcomponent_assign): Expand assignment to class
components to include intrinsic and character expressions.
gcc/testsuite/
PR fortran/49213
* gfortran.dg/pr49213.f90 : New test
[-- Attachment #2: pr49213.diff --]
[-- Type: text/x-patch, Size: 5161 bytes --]
diff --git a/gcc/fortran/expr.cc b/gcc/fortran/expr.cc
index c960dfeabd9..92061d69781 100644
--- a/gcc/fortran/expr.cc
+++ b/gcc/fortran/expr.cc
@@ -816,7 +816,7 @@ bool
gfc_is_ptr_fcn (gfc_expr *e)
{
return e != NULL && e->expr_type == EXPR_FUNCTION
- && (gfc_expr_attr (e).pointer
+ && ((e->ts.type != BT_CLASS && gfc_expr_attr (e).pointer)
|| (e->ts.type == BT_CLASS
&& CLASS_DATA (e)->attr.class_pointer));
}
diff --git a/gcc/fortran/resolve.cc b/gcc/fortran/resolve.cc
index 82e6ac53aa1..217d69d4e0b 100644
--- a/gcc/fortran/resolve.cc
+++ b/gcc/fortran/resolve.cc
@@ -1350,6 +1350,9 @@ resolve_structure_cons (gfc_expr *expr, int init)
&& CLASS_DATA (comp)->as)
rank = CLASS_DATA (comp)->as->rank;
+ if (comp->ts.type == BT_CLASS && cons->expr->ts.type == BT_DERIVED)
+ gfc_find_derived_vtab (cons->expr->ts.u.derived);
+
if (cons->expr->expr_type != EXPR_NULL && rank != cons->expr->rank
&& (comp->attr.allocatable || cons->expr->rank))
{
@@ -1381,7 +1384,7 @@ resolve_structure_cons (gfc_expr *expr, int init)
gfc_basic_typename (comp->ts.type));
t = false;
}
- else
+ else if (!UNLIMITED_POLY (comp))
{
bool t2 = gfc_convert_type (cons->expr, &comp->ts, 1);
if (t)
diff --git a/gcc/fortran/trans-decl.cc b/gcc/fortran/trans-decl.cc
index 18589e17843..b0fd25e92a3 100644
--- a/gcc/fortran/trans-decl.cc
+++ b/gcc/fortran/trans-decl.cc
@@ -1915,7 +1915,6 @@ gfc_get_symbol_decl (gfc_symbol * sym)
gcc_assert (!sym->value || sym->value->expr_type == EXPR_NULL);
}
-
gfc_finish_var_decl (decl, sym);
if (sym->ts.type == BT_CHARACTER)
diff --git a/gcc/fortran/trans-expr.cc b/gcc/fortran/trans-expr.cc
index 3c209bcde97..5a1ff0c1d21 100644
--- a/gcc/fortran/trans-expr.cc
+++ b/gcc/fortran/trans-expr.cc
@@ -8781,6 +8781,7 @@ alloc_scalar_allocatable_subcomponent (stmtblock_t *block, tree comp,
tree size;
tree size_in_bytes;
tree lhs_cl_size = NULL_TREE;
+ gfc_se se;
if (!comp)
return;
@@ -8815,16 +8816,26 @@ alloc_scalar_allocatable_subcomponent (stmtblock_t *block, tree comp,
}
else if (cm->ts.type == BT_CLASS)
{
- gcc_assert (expr2->ts.type == BT_CLASS || expr2->ts.type == BT_DERIVED);
- if (expr2->ts.type == BT_DERIVED)
+ if (expr2->ts.type != BT_CLASS)
{
- tmp = gfc_get_symbol_decl (expr2->ts.u.derived);
- size = TYPE_SIZE_UNIT (tmp);
+ if (expr2->ts.type == BT_CHARACTER)
+ {
+ gfc_init_se (&se, NULL);
+ gfc_conv_expr (&se, expr2);
+ size = fold_convert (size_type_node, se.string_length);
+ }
+ else
+ {
+ if (expr2->ts.type == BT_DERIVED)
+ tmp = gfc_get_symbol_decl (expr2->ts.u.derived);
+ else
+ tmp = gfc_typenode_for_spec (&expr2->ts);
+ size = TYPE_SIZE_UNIT (tmp);
+ }
}
else
{
gfc_expr *e2vtab;
- gfc_se se;
e2vtab = gfc_find_and_cut_at_last_class_ref (expr2);
gfc_add_vptr_component (e2vtab);
gfc_add_size_component (e2vtab);
@@ -8975,6 +8986,7 @@ gfc_trans_subcomponent_assign (tree dest, gfc_component * cm,
{
gfc_init_se (&se, NULL);
gfc_conv_expr (&se, expr);
+ tree size;
/* Take care about non-array allocatable components here. The alloc_*
routine below is motivated by the alloc_scalar_allocatable_for_
@@ -8990,7 +9002,7 @@ gfc_trans_subcomponent_assign (tree dest, gfc_component * cm,
&& expr->symtree->n.sym->attr.dummy)
se.expr = build_fold_indirect_ref_loc (input_location, se.expr);
- if (cm->ts.type == BT_CLASS && expr->ts.type == BT_DERIVED)
+ if (cm->ts.type == BT_CLASS)
{
tmp = gfc_class_data_get (dest);
tmp = build_fold_indirect_ref_loc (input_location, tmp);
@@ -9005,7 +9017,6 @@ gfc_trans_subcomponent_assign (tree dest, gfc_component * cm,
/* For deferred strings insert a memcpy. */
if (cm->ts.type == BT_CHARACTER && cm->ts.deferred)
{
- tree size;
gcc_assert (se.string_length || expr->ts.u.cl->backend_decl);
size = size_of_string_in_bytes (cm->ts.kind, se.string_length
? se.string_length
@@ -9013,6 +9024,29 @@ gfc_trans_subcomponent_assign (tree dest, gfc_component * cm,
tmp = gfc_build_memcpy_call (tmp, se.expr, size);
gfc_add_expr_to_block (&block, tmp);
}
+ else if (cm->ts.type == BT_CLASS)
+ {
+ /* Fix the expression for memcpy. */
+ if (expr->expr_type != EXPR_VARIABLE)
+ se.expr = gfc_evaluate_now (se.expr, &block);
+
+ if (expr->ts.type == BT_CHARACTER)
+ size = fold_convert (size_type_node, se.string_length);
+ else
+ size = TYPE_SIZE_UNIT (gfc_typenode_for_spec (&expr->ts));
+
+ /* Now copy the expression to the constructor component _data. */
+ gfc_add_expr_to_block (&block,
+ gfc_build_memcpy_call (tmp, se.expr, size));
+
+ /* Fill the unlimited polymorphic _len field. */
+ if (UNLIMITED_POLY (cm))
+ {
+ tmp = gfc_class_len_get (gfc_get_class_from_expr (tmp));
+ gfc_add_modify (&block, tmp,
+ fold_convert (TREE_TYPE (tmp), size));
+ }
+ }
else
gfc_add_modify (&block, tmp,
fold_convert (TREE_TYPE (tmp), se.expr));
[-- Attachment #3: pr49213.f90 --]
[-- Type: text/x-fortran, Size: 1893 bytes --]
! { dg-do run }
!
! Contributed by Neil Carlson <neil.n.carlson@gmail.com>
!
program main
character(2) :: c
type :: S
integer :: n
end type
type(S) :: Sobj
type, extends(S) :: S2
integer :: m
end type
type(S2) :: S2obj
type :: T
class(S), allocatable :: x
end type
type(T) :: Tobj
Sobj = S(1)
Tobj = T(Sobj)
S2obj = S2(1,2)
Tobj = T(S2obj) ! Failed here
select type (x => Tobj%x)
type is (S2)
if ((x%n .ne. 1) .or. (x%m .ne. 2)) stop 1
class default
stop 2
end select
c = " "
call pass_it (T(Sobj))
if (c .ne. "S ") stop 3
call pass_it (T(S2obj)) ! and here
if (c .ne. "S2") stop 4
call bar
contains
subroutine pass_it (foo)
type(T), intent(in) :: foo
select type (x => foo%x)
type is (S)
c = "S "
if (x%n .ne. 1) stop 5
type is (S2)
c = "S2"
if ((x%n .ne. 1) .or. (x%m .ne. 2)) stop 6
class default
stop 7
end select
end subroutine
subroutine bar
! Test from comment #29 of the PR - due to Janus Weil
type tContainer
class(*), allocatable :: x
end type
integer, parameter :: i = 0
character(7) :: chr = "goodbye"
type(tContainer) :: cont
cont%x = i ! linker error: undefined reference to `__copy_INTEGER_4_.3804'
cont = tContainer(i+42) ! Failed here
select type (z => cont%x)
type is (integer)
if (z .ne. 42) stop 8
class default
stop 9
end select
cont = tContainer('hello!')
select type (z => cont%x)
type is (character(*))
if (z .ne. 'hello!') stop 10
class default
stop 11
end select
cont = tContainer(chr)
select type (z => cont%x)
type is (character(*))
if (z .ne. 'goodbye') stop 12
class default
stop 13
end select
end subroutine bar
end program
next reply other threads:[~2023-06-24 13:19 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2023-06-24 13:18 Paul Richard Thomas [this message]
2023-06-24 19:50 ` Harald Anlauf
2023-06-24 19:50 ` Harald Anlauf
2023-06-27 10:30 ` Paul Richard Thomas
2023-06-27 19:27 ` Harald Anlauf
2023-06-27 19:27 ` Harald Anlauf
2023-06-28 9:47 ` Paul Richard Thomas
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAGkQGiKPvpOMQSbx5tm9UGVvyGuDoEcQAR7WJMo7iQiYh9pL+A@mail.gmail.com \
--to=paul.richard.thomas@gmail.com \
--cc=anlauf@gmx.de \
--cc=fortran@gcc.gnu.org \
--cc=gcc-patches@gcc.gnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
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).