From: Andrew Burgess <andrew.burgess@embecosm.com>
To: gdb-patches@sourceware.org
Subject: Re: [PATCH] gdb/fortran: handle dynamic types within arrays and structures
Date: Wed, 31 Mar 2021 21:13:32 +0100 [thread overview]
Message-ID: <20210331201332.GE5391@embecosm.com> (raw)
In-Reply-To: <20210317225843.3686644-1-andrew.burgess@embecosm.com>
Ping!
Any feedback?
Thanks,
Andrew
* Andrew Burgess <andrew.burgess@embecosm.com> [2021-03-17 22:58:43 +0000]:
> This commit replaces this patch:
>
> https://sourceware.org/pipermail/gdb-patches/2021-January/174933.html
>
> which was itself a replacement for this patch:
>
> https://sourceware.org/pipermail/gdb-patches/2020-July/170335.html
>
> The motivation behind the original patch can be seen in the new test,
> which currently gives a GDB session like this:
>
> (gdb) ptype var8
> type = Type type6
> PTR TO -> ( Type type2 :: ptr_1 )
> PTR TO -> ( Type type2 :: ptr_2 )
> End Type type6
> (gdb) ptype var8%ptr_2
> type = PTR TO -> ( Type type2
> integer(kind=4) :: spacer
> Type type1, allocatable :: t2_array(:) <------ Issue #1
> End Type type2 )
> (gdb) ptype var8%ptr_2%t2_array
> Cannot access memory at address 0x38 <------ Issue #2
> (gdb)
>
> Issue #1: Here we see the abstract dynamic type, rather than the
> resolved concrete type. Though in some cases the user might be
> interested in the abstract dynamic type, I think that in most cases
> showing the resolved concrete type will be of more use. Plus, the
> user can always figure out the dynamic type (by source code inspection
> if nothing else) given the concrete type, but it is much harder to
> figure out the concrete type given only the dynamic type.
>
> Issue #2: In this example, GDB evaluates the expression in
> EVAL_AVOID_SIDE_EFFECTS mode (due to ptype). The value returned for
> var8%ptr_2 will be a non-lazy, zero value of the correct dynamic
> type. However, when GDB asks about the type of t2_array this requires
> GDB to access the value of var8%ptr_2 in order to read the dynamic
> properties. As this value was forced to zero (thanks to the use of
> EVAL_AVOID_SIDE_EFFECTS) then GDB ends up accessing memory at a base
> of zero plus some offset.
>
> Both this patch, and my previous two attempts, have all tried to
> resolve this problem by stopping EVAL_AVOID_SIDE_EFFECTS replacing the
> result value with a zero value in some cases.
>
> This new patch is influenced by how Ada handles its tagged typed.
> There are plenty of examples in ada-lang.c, but one specific case is
> ada_structop_operation::evaluate. When GDB spots that we are dealing
> with a tagged (dynamic) type, and we're in EVAL_AVOID_SIDE_EFFECTS
> mode, then GDB re-evaluates the child operation in EVAL_NORMAL mode.
>
> This commit handles two cases like this specifically for Fortran, a
> new fortran_structop_operation, and the already existing
> fortran_undetermined, which is where we handle array accesses.
>
> In these two locations we spot when we are dealing with a dynamic type
> and re-evaluate the child operation in EVAL_NORMAL mode so that we
> are able to access the dynamic properties of the type.
>
> The rest of this commit message is my attempt to record why my
> previous patches failed.
>
> To understand my second patch, and why it failed lets consider two
> expressions, this Fortran expression:
>
> (gdb) ptype var8%ptr_2%t2_array --<A>
> Operation: STRUCTOP_STRUCT --(1)
> Operation: STRUCTOP_STRUCT --(2)
> Operation: OP_VAR_VALUE --(3)
> Symbol: var8
> Block: 0x3980ac0
> String: ptr_2
> String: t2_array
>
> And this C expression:
>
> (gdb) ptype ptr && ptr->a == 3 --<B>
> Operation: BINOP_LOGICAL_AND --(4)
> Operation: OP_VAR_VALUE --(5)
> Symbol: ptr
> Block: 0x45a2a00
> Operation: BINOP_EQUAL --(6)
> Operation: STRUCTOP_PTR --(7)
> Operation: OP_VAR_VALUE --(8)
> Symbol: ptr
> Block: 0x45a2a00
> String: a
> Operation: OP_LONG --(9)
> Type: int
> Constant: 0x0000000000000003
>
> In expression <A> we should assume that t2_array is of dynamic type.
> Nothing has dynamic type in expression <B>.
>
> This is how GDB currently handles expression <A>, in all cases,
> EVAL_AVOID_SIDE_EFFECTS or EVAL_NORMAL, an OP_VAR_VALUE operation
> always returns the real value of the symbol, this is not forced to a
> zero value even in EVAL_AVOID_SIDE_EFFECTS mode. This means that (3),
> (5), and (8) will always return a real lazy value for the symbol.
>
> However a STRUCTOP_STRUCT will always replace its result with a
> non-lazy, zero value with the same type as its result. So (2) will
> lookup the field ptr_2 and create a zero value with that type. In
> this case the type is a pointer to a dynamic type.
>
> Then, when we evaluate (1) to figure out the resolved type of
> t2_array, we need to read the types dynamic properties. These
> properties are stored in memory relative to the objects base address,
> and the base address is in var8%ptr_2, which we already figured out
> has the value zero. GDB then evaluates the DWARF expressions that
> take the base address, add an offset and dereference. GDB then ends
> up trying to access addresses like 0x16, 0x8, etc.
>
> To fix this, I proposed changing STRUCTOP_STRUCT so that instead of
> returning a zero value we instead returned the actual value
> representing the structure's field in the target. My thinking was
> that GDB would not try to access the value's contents unless it needed
> it to resolve a dynamic type. This belief was incorrect.
>
> Consider expression <B>. We already know that (5) and (8) will return
> real values for the symbols being referenced. The BINOP_LOGICAL_AND,
> operation (4) will evaluate both of its children in
> EVAL_AVOID_SIDE_EFFECTS in order to get the types, this is required
> for C++ operator lookup. This means that even if the value of (5)
> would result in the BINOP_LOGICAL_AND returning false (say, ptr is
> NULL), we still evaluate (6) in EVAL_AVOID_SIDE_EFFECTS mode.
>
> Operation (6) will evaluate both children in EVAL_AVOID_SIDE_EFFECTS
> mode, operation (9) is easy, it just returns a value with the constant
> packed into it, but (7) is where the problem lies. Currently in GDB
> this STRUCTOP_STRUCT will always return a non-lazy zero value of the
> correct type.
>
> When the results of (7) and (9) are back in the BINOP_LOGICAL_AND
> operation (6), the two values are passed to value_equal which performs
> the comparison and returns a result. Note, the two things compared
> here are the immediate value (9), and a non-lazy zero value from (7).
>
> However, with my proposed patch operation (7) no longer returns a zero
> value, instead it returns a lazy value representing the actual value
> in target memory. When we call value_equal in (6) this code causes
> GDB to try and fetch the actual value from target memory. If `ptr` is
> NULL then this will cause GDB to access some invalid address at an
> offset from zero, this will most likely fail, and cause GDB to throw
> an error instead of returning the expected type.
>
> And so, we can now describe the problem that we're facing. The way
> GDB's expression evaluator is currently written we assume, when in
> EVAL_AVOID_SIDE_EFFECTS mode, that any value returned from a child
> operation can safely have its content read without throwing an
> error. If child operations start returning real values (instead of
> the fake zero values), then this is simply not true.
>
> If we wanted to work around this then we would need to rewrite almost
> all operations (I would guess) so that EVAL_AVOID_SIDE_EFFECTS mode
> does not cause evaluation of an operation to try and read the value of
> a child operation. As an example, consider this current GDB code from
> eval.c:
>
> struct value *
> eval_op_equal (struct type *expect_type, struct expression *exp,
> enum noside noside, enum exp_opcode op,
> struct value *arg1, struct value *arg2)
> {
> if (binop_user_defined_p (op, arg1, arg2))
> {
> return value_x_binop (arg1, arg2, op, OP_NULL, noside);
> }
> else
> {
> binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
> int tem = value_equal (arg1, arg2);
> struct type *type = language_bool_type (exp->language_defn,
> exp->gdbarch);
> return value_from_longest (type, (LONGEST) tem);
> }
> }
>
> We could change this function to be this:
>
> struct value *
> eval_op_equal (struct type *expect_type, struct expression *exp,
> enum noside noside, enum exp_opcode op,
> struct value *arg1, struct value *arg2)
> {
> if (binop_user_defined_p (op, arg1, arg2))
> {
> return value_x_binop (arg1, arg2, op, OP_NULL, noside);
> }
> else
> {
> struct type *type = language_bool_type (exp->language_defn,
> exp->gdbarch);
> if (noside == EVAL_AVOID_SIDE_EFFECTS)
> return value_zero (type, VALUE_LVAL (arg1));
> else
> {
> binop_promote (exp->language_defn, exp->gdbarch, &arg1, &arg2);
> int tem = value_equal (arg1, arg2);
> return value_from_longest (type, (LONGEST) tem);
> }
> }
> }
>
> Now we don't call value_equal unless we really need to. However, we
> would need to make the same, or similar change to almost all
> operations, which would be a big task, and might not be a direction we
> wanted to take GDB in.
>
> So, for now, I'm proposing we go with the more targeted, Fortran
> specific solution, that does the minimal required in order to
> correctly resolve the dynamic types.
>
> gdb/ChangeLog:
>
> * f-exp.h (class fortran_structop_operation): New class.
> * f-exp.y (exp): Create fortran_structop_operation instead of the
> generic structop_operation.
> * f-lang.c (fortran_undetermined::evaluate): Re-evaluate
> expression as EVAL_NORMAL if the result type was dynamic so we can
> extract the actual array bounds.
> (fortran_structop_operation::evaluate): New function.
>
> gdb/testsuite/ChangeLog:
>
> * gdb.fortran/dynamic-ptype-whatis.exp: New file.
> * gdb.fortran/dynamic-ptype-whatis.f90: New file.
> ---
> gdb/ChangeLog | 16 ++
> gdb/f-exp.h | 16 ++
> gdb/f-exp.y | 9 +-
> gdb/f-lang.c | 40 +++++
> gdb/testsuite/ChangeLog | 5 +
> .../gdb.fortran/dynamic-ptype-whatis.exp | 158 ++++++++++++++++++
> .../gdb.fortran/dynamic-ptype-whatis.f90 | 93 +++++++++++
> 7 files changed, 333 insertions(+), 4 deletions(-)
> create mode 100644 gdb/testsuite/gdb.fortran/dynamic-ptype-whatis.exp
> create mode 100644 gdb/testsuite/gdb.fortran/dynamic-ptype-whatis.f90
>
> diff --git a/gdb/f-exp.h b/gdb/f-exp.h
> index b3d0e0e9d54..955d1873f51 100644
> --- a/gdb/f-exp.h
> +++ b/gdb/f-exp.h
> @@ -273,6 +273,22 @@ class fortran_bound_2arg
> { return std::get<0> (m_storage); }
> };
>
> +/* Implement STRUCTOP_STRUCT for Fortran. */
> +class fortran_structop_operation
> + : public structop_base_operation
> +{
> +public:
> +
> + using structop_base_operation::structop_base_operation;
> +
> + value *evaluate (struct type *expect_type,
> + struct expression *exp,
> + enum noside noside) override;
> +
> + enum exp_opcode opcode () const override
> + { return STRUCTOP_STRUCT; }
> +};
> +
> } /* namespace expr */
>
> #endif /* FORTRAN_EXP_H */
> diff --git a/gdb/f-exp.y b/gdb/f-exp.y
> index ce11b09b18e..6608831a9a5 100644
> --- a/gdb/f-exp.y
> +++ b/gdb/f-exp.y
> @@ -492,7 +492,7 @@ exp : '(' type ')' exp %prec UNARY
>
> exp : exp '%' name
> {
> - pstate->push_new<structop_operation>
> + pstate->push_new<fortran_structop_operation>
> (pstate->pop (), copy_name ($3));
> }
> ;
> @@ -500,8 +500,8 @@ exp : exp '%' name
> exp : exp '%' name COMPLETE
> {
> structop_base_operation *op
> - = new structop_operation (pstate->pop (),
> - copy_name ($3));
> + = new fortran_structop_operation (pstate->pop (),
> + copy_name ($3));
> pstate->mark_struct_expression (op);
> pstate->push (operation_up (op));
> }
> @@ -510,7 +510,8 @@ exp : exp '%' name COMPLETE
> exp : exp '%' COMPLETE
> {
> structop_base_operation *op
> - = new structop_operation (pstate->pop (), "");
> + = new fortran_structop_operation (pstate->pop (),
> + "");
> pstate->mark_struct_expression (op);
> pstate->push (operation_up (op));
> }
> diff --git a/gdb/f-lang.c b/gdb/f-lang.c
> index 0c49420e1f1..7e921b99517 100644
> --- a/gdb/f-lang.c
> +++ b/gdb/f-lang.c
> @@ -1405,6 +1405,9 @@ fortran_undetermined::evaluate (struct type *expect_type,
> enum noside noside)
> {
> value *callee = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
> + if (noside == EVAL_AVOID_SIDE_EFFECTS
> + && is_dynamic_type (value_type (callee)))
> + callee = std::get<0> (m_storage)->evaluate (nullptr, exp, EVAL_NORMAL);
> struct type *type = check_typedef (value_type (callee));
> enum type_code code = type->code ();
>
> @@ -1490,6 +1493,43 @@ fortran_bound_2arg::evaluate (struct type *expect_type,
> return fortran_bounds_for_dimension (lbound_p, exp->gdbarch, arg1, arg2);
> }
>
> +/* Implement STRUCTOP_STRUCT for Fortran. See operation::evaluate in
> + expression.h for argument descriptions. */
> +
> +value *
> +fortran_structop_operation::evaluate (struct type *expect_type,
> + struct expression *exp,
> + enum noside noside)
> +{
> + value *arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, noside);
> + const char *str = std::get<1> (m_storage).c_str ();
> + if (noside == EVAL_AVOID_SIDE_EFFECTS)
> + {
> + struct type *type = lookup_struct_elt_type (value_type (arg1), str, 1);
> +
> + if (type != nullptr && is_dynamic_type (type))
> + arg1 = std::get<0> (m_storage)->evaluate (nullptr, exp, EVAL_NORMAL);
> + }
> +
> + value *elt = value_struct_elt (&arg1, NULL, str, NULL, "structure");
> +
> + if (noside == EVAL_AVOID_SIDE_EFFECTS)
> + {
> + struct type *elt_type = value_type (elt);
> + if (is_dynamic_type (elt_type))
> + {
> + const gdb_byte *valaddr = value_contents_for_printing (elt);
> + CORE_ADDR address = value_address (elt);
> + gdb::array_view<const gdb_byte> view
> + = gdb::make_array_view (valaddr, TYPE_LENGTH (elt_type));
> + elt_type = resolve_dynamic_type (elt_type, view, address);
> + }
> + elt = value_zero (elt_type, VALUE_LVAL (elt));
> + }
> +
> + return elt;
> +}
> +
> } /* namespace expr */
>
> /* See language.h. */
> diff --git a/gdb/testsuite/gdb.fortran/dynamic-ptype-whatis.exp b/gdb/testsuite/gdb.fortran/dynamic-ptype-whatis.exp
> new file mode 100644
> index 00000000000..d2ffd6d73f7
> --- /dev/null
> +++ b/gdb/testsuite/gdb.fortran/dynamic-ptype-whatis.exp
> @@ -0,0 +1,158 @@
> +# Copyright 2021 Free Software Foundation, Inc.
> +
> +# This program is free software; you can redistribute it and/or modify
> +# it under the terms of the GNU General Public License as published by
> +# the Free Software Foundation; either version 3 of the License, or
> +# (at your option) any later version.
> +#
> +# This program is distributed in the hope that it will be useful,
> +# but WITHOUT ANY WARRANTY; without even the implied warranty of
> +# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +# GNU General Public License for more details.
> +#
> +# You should have received a copy of the GNU General Public License
> +# along with this program. If not, see <http://www.gnu.org/licenses/> .
> +
> +# Test using whatis and ptype on different configurations of dynamic
> +# types.
> +
> +if {[skip_fortran_tests]} { return -1 }
> +
> +standard_testfile ".f90"
> +load_lib fortran.exp
> +
> +if {[prepare_for_testing ${testfile}.exp ${testfile} ${srcfile} \
> + {debug f90}]} {
> + return -1
> +}
> +
> +if {![fortran_runto_main]} {
> + perror "Could not run to main."
> + continue
> +}
> +
> +gdb_breakpoint [gdb_get_line_number "Break Here"]
> +gdb_continue_to_breakpoint "Break Here"
> +
> +gdb_test "whatis var1" "type = real\\(kind=4\\) \\(3\\)"
> +gdb_test "whatis var2" "type = real\\(kind=4\\), allocatable \\(4\\)"
> +gdb_test "whatis var3" "type = Type type1"
> +gdb_test "whatis var4" "type = Type type2"
> +gdb_test "whatis var5" "type = Type type3"
> +gdb_test "whatis var6" "type = Type type4"
> +gdb_test "whatis var7" "type = Type type5"
> +gdb_test "ptype var1" "type = real\\(kind=4\\) \\(3\\)"
> +gdb_test "ptype var2" "type = real\\(kind=4\\), allocatable \\(4\\)"
> +gdb_test "ptype var3" \
> + [ multi_line "type = Type type1" \
> + " integer\\(kind=4\\) :: spacer" \
> + " integer\\(kind=4\\) :: t1_i" \
> + "End Type type1" ]
> +gdb_test "ptype var4" \
> + [multi_line "type = Type type2" \
> + " integer\\(kind=4\\) :: spacer" \
> + " Type type1, allocatable :: t2_array\\(3\\)" \
> + "End Type type2"]
> +gdb_test "ptype var5" \
> + [ multi_line "type = Type type3" \
> + " integer\\(kind=4\\) :: spacer" \
> + " Type type1 :: t3_array\\(3\\)"\
> + "End Type type3" ]
> +gdb_test "ptype var6" \
> + [ multi_line "type = Type type4" \
> + " integer\\(kind=4\\) :: spacer" \
> + " Type type2, allocatable :: t4_array\\(3\\)" \
> + "End Type type4" ]
> +gdb_test "ptype var7" \
> + [ multi_line "type = Type type5" \
> + " integer\\(kind=4\\) :: spacer" \
> + " Type type2 :: t5_array\\(4\\)" \
> + "End Type type5" ]
> +gdb_test "whatis var3%t1_i" "type = integer\\(kind=4\\)"
> +gdb_test "whatis var4%t2_array" "type = Type type1, allocatable \\(3\\)"
> +gdb_test "whatis var5%t3_array" "type = Type type1 \\(3\\)"
> +gdb_test "whatis var6%t4_array" "type = Type type2, allocatable \\(3\\)"
> +gdb_test "whatis var7%t5_array" "type = Type type2 \\(4\\)"
> +gdb_test "ptype var3%t1_i" [ multi_line "type = integer\\(kind=4\\)" ]
> +gdb_test "ptype var4%t2_array" [ multi_line "type = Type type1" \
> + " integer\\(kind=4\\) :: spacer" \
> + " integer\\(kind=4\\) :: t1_i" \
> + "End Type type1, allocatable \\(3\\)" ]
> +gdb_test "ptype var5%t3_array" [ multi_line "type = Type type1" \
> + " integer\\(kind=4\\) :: spacer" \
> + " integer\\(kind=4\\) :: t1_i" \
> + "End Type type1 \\(3\\)" ]
> +gdb_test "ptype var6%t4_array" \
> + [ multi_line "type = Type type2" \
> + " integer\\(kind=4\\) :: spacer" \
> + " Type type1, allocatable :: t2_array\\(:\\)" \
> + "End Type type2, allocatable \\(3\\)" ]
> +gdb_test "ptype var7%t5_array" \
> + [ multi_line "type = Type type2" \
> + " integer\\(kind=4\\) :: spacer" \
> + " Type type1, allocatable :: t2_array\\(:\\)" \
> + "End Type type2 \\(4\\)" ]
> +gdb_test "whatis var4%t2_array(1)" "type = Type type1"
> +gdb_test "whatis var5%t3_array(1)" "type = Type type1"
> +gdb_test "whatis var6%t4_array(1)" "type = Type type2"
> +gdb_test "whatis var7%t5_array(1)" "type = Type type2"
> +gdb_test "ptype var4%t2_array(1)" \
> + [ multi_line "type = Type type1" \
> + " integer\\(kind=4\\) :: spacer" \
> + " integer\\(kind=4\\) :: t1_i" \
> + "End Type type1" ]
> +gdb_test "ptype var5%t3_array(1)" \
> + [ multi_line "type = Type type1" \
> + " integer\\(kind=4\\) :: spacer" \
> + " integer\\(kind=4\\) :: t1_i" \
> + "End Type type1" ]
> +gdb_test "ptype var6%t4_array(1)" \
> + [ multi_line "type = Type type2" \
> + " integer\\(kind=4\\) :: spacer" \
> + " Type type1, allocatable :: t2_array\\(2\\)" \
> + "End Type type2" ]
> +gdb_test "ptype var7%t5_array(1)" \
> + [ multi_line "type = Type type2" \
> + " integer\\(kind=4\\) :: spacer" \
> + " Type type1, allocatable :: t2_array\\(2\\)" \
> + "End Type type2" ]
> +gdb_test "whatis var4%t2_array(1)%t1_i" "type = integer\\(kind=4\\)"
> +gdb_test "whatis var5%t3_array(1)%t1_i" "type = integer\\(kind=4\\)"
> +gdb_test "whatis var6%t4_array(1)%t2_array" \
> + "type = Type type1, allocatable \\(2\\)"
> +gdb_test "whatis var7%t5_array(1)%t2_array" \
> + "type = Type type1, allocatable \\(2\\)"
> +gdb_test "ptype var4%t2_array(1)%t1_i" "type = integer\\(kind=4\\)"
> +gdb_test "ptype var5%t3_array(1)%t1_i" "type = integer\\(kind=4\\)"
> +gdb_test "ptype var6%t4_array(1)%t2_array" \
> + [ multi_line "type = Type type1" \
> + " integer\\(kind=4\\) :: spacer" \
> + " integer\\(kind=4\\) :: t1_i" \
> + "End Type type1, allocatable \\(2\\)" ]
> +gdb_test "ptype var7%t5_array(1)%t2_array" \
> + [ multi_line "type = Type type1" \
> + " integer\\(kind=4\\) :: spacer" \
> + " integer\\(kind=4\\) :: t1_i" \
> + "End Type type1, allocatable \\(2\\)" ]
> +gdb_test "whatis var6%t4_array(1)%t2_array(1)" \
> + "type = Type type1"
> +gdb_test "whatis var7%t5_array(1)%t2_array(1)" \
> + "type = Type type1"
> +gdb_test "ptype var6%t4_array(1)%t2_array(1)" \
> + [ multi_line \
> + "type = Type type1" \
> + " integer\\(kind=4\\) :: spacer" \
> + " integer\\(kind=4\\) :: t1_i" \
> + "End Type type1" ]
> +gdb_test "ptype var7%t5_array(1)%t2_array(1)" \
> + [ multi_line \
> + "type = Type type1" \
> + " integer\\(kind=4\\) :: spacer" \
> + " integer\\(kind=4\\) :: t1_i" \
> + "End Type type1" ]
> +gdb_test "ptype var8%ptr_1%t2_array" \
> + [ multi_line \
> + "type = Type type1" \
> + " integer\\(kind=4\\) :: spacer" \
> + " integer\\(kind=4\\) :: t1_i" \
> + "End Type type1, allocatable \\(3\\)" ]
> diff --git a/gdb/testsuite/gdb.fortran/dynamic-ptype-whatis.f90 b/gdb/testsuite/gdb.fortran/dynamic-ptype-whatis.f90
> new file mode 100644
> index 00000000000..e56bf7952dc
> --- /dev/null
> +++ b/gdb/testsuite/gdb.fortran/dynamic-ptype-whatis.f90
> @@ -0,0 +1,93 @@
> +! Copyright 2021 Free Software Foundation, Inc.
> +!
> +! This program is free software; you can redistribute it and/or modify
> +! it under the terms of the GNU General Public License as published by
> +! the Free Software Foundation; either version 3 of the License, or
> +! (at your option) any later version.
> +!
> +! This program is distributed in the hope that it will be useful,
> +! but WITHOUT ANY WARRANTY; without even the implied warranty of
> +! MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
> +! GNU General Public License for more details.
> +!
> +! You should have received a copy of the GNU General Public License
> +! along with this program. If not, see <http://www.gnu.org/licenses/>.
> +
> +program main
> +
> + ! A non-dynamic type.
> + type type1
> + integer(kind=4) :: spacer
> + integer(kind=4) t1_i
> + end type type1
> +
> + ! A first dynamic type. The array is of a static type.
> + type type2
> + integer(kind=4) :: spacer
> + type(type1), allocatable :: t2_array(:)
> + end type type2
> +
> + ! Another dynamic type, the array is again a static type.
> + type type3
> + integer(kind=4) :: spacer
> + type(type1), pointer :: t3_array(:)
> + end type type3
> +
> + ! A dynamic type, this time the array contains a dynamic type.
> + type type4
> + integer(kind=4) :: spacer
> + type(type2), allocatable :: t4_array(:)
> + end type type4
> +
> + ! A static type, the array though contains dynamic types.
> + type type5
> + integer(kind=4) :: spacer
> + type(type2) :: t5_array (4)
> + end type type5
> +
> + ! A static type containing pointers to a type that contains a
> + ! dynamic array.
> + type type6
> + type(type2), pointer :: ptr_1
> + type(type2), pointer :: ptr_2
> + end type type6
> +
> + real, dimension(:), pointer :: var1
> + real, dimension(:), allocatable :: var2
> + type(type1) :: var3
> + type(type2), target :: var4
> + type(type3) :: var5
> + type(type4) :: var6
> + type(type5) :: var7
> + type(type6) :: var8
> +
> + allocate (var1 (3))
> +
> + allocate (var2 (4))
> +
> + allocate (var4%t2_array(3))
> +
> + allocate (var5%t3_array(3))
> +
> + allocate (var6%t4_array(3))
> + allocate (var6%t4_array(1)%t2_array(2))
> + allocate (var6%t4_array(2)%t2_array(5))
> + allocate (var6%t4_array(3)%t2_array(4))
> +
> + allocate (var7%t5_array(1)%t2_array(2))
> + allocate (var7%t5_array(2)%t2_array(5))
> + allocate (var7%t5_array(3)%t2_array(4))
> + allocate (var7%t5_array(4)%t2_array(1))
> +
> + var8%ptr_1 => var4
> + var8%ptr_2 => var4
> +
> + print *, var1 ! Break Here
> + print *, var2
> + print *, var3
> + print *, var4%t2_array(1)
> + print *, var5%t3_array(2)
> + print *, var6%t4_array(1)%t2_array(1)
> + print *, var7%t5_array(1)%t2_array(1)
> +
> +end program main
> --
> 2.25.4
>
next prev parent reply other threads:[~2021-03-31 20:13 UTC|newest]
Thread overview: 7+ messages / expand[flat|nested] mbox.gz Atom feed top
2021-03-17 22:58 Andrew Burgess
2021-03-31 20:13 ` Andrew Burgess [this message]
2021-04-01 19:27 ` Tom Tromey
2021-03-22 17:44 Andrew Burgess
2021-03-24 18:56 ` Andrew Burgess
2021-03-31 20:12 ` Andrew Burgess
2021-03-31 20:14 ` Andrew Burgess
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=20210331201332.GE5391@embecosm.com \
--to=andrew.burgess@embecosm.com \
--cc=gdb-patches@sourceware.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).