From: Tom de Vries <tdevries@suse.de>
To: Tom Tromey <tromey@adacore.com>, gdb-patches@sourceware.org
Subject: Re: [PATCH] Check record types for compatibility in ada_type_match
Date: Thu, 27 Aug 2026 16:17:47 +0200 [thread overview]
Message-ID: <8c8a38de-5db7-4857-95d1-4abf2a010d54@suse.de> (raw)
In-Reply-To: <20260826201312.1120857-1-tromey@adacore.com>
On 8/26/26 10:13 PM, Tom Tromey wrote:
> While investigating some gdb test suite failures when run against
> gnat-llvm, I found this oddity in operator_call.exp:
>
> (gdb) print p < p
> Multiple matches for "<"
> [0] cancel
> [1] system.dwarf_lines."<" (system.dwarf_lines.search_entry; system.dwarf_lines.search_entry) return boolean at s-dwalin.adb:265
> [2] twovecs."<" (twovecs.twovec; twovecs.twovec) return boolean at twovecs.adb:61
>
> While operator_call.exp generally doesn't work yet with gnat-llvm,
> this particular failure seemed wrong, because the types here aren't
> even remotely related or compatible -- that is, this call should not
> be ambiguous.
>
> Looking into this, I found that ada_type_match assumes that all record
> types are identical.
>
> I think gdb can do a bit better than this, without trying to implement
> full Ada overload resolution (which IIUC would require type
> inferencing as well).
>
> In particular we can at least filter out the matches that are wholly
> unsuitable. That is what this patch does.
Hi Tom,
this sounds like a good idea to me.
I have just one question below.
> ---
> gdb/ada-lang.c | 58 ++++++++++++++-
> gdb/testsuite/gdb.ada/record-overloads.exp | 70 +++++++++++++++++++
> .../gdb.ada/record-overloads/pck.adb | 43 ++++++++++++
> .../gdb.ada/record-overloads/pck.ads | 50 +++++++++++++
> .../gdb.ada/record-overloads/prog.adb | 32 +++++++++
> 5 files changed, 252 insertions(+), 1 deletion(-)
> create mode 100644 gdb/testsuite/gdb.ada/record-overloads.exp
> create mode 100644 gdb/testsuite/gdb.ada/record-overloads/pck.adb
> create mode 100644 gdb/testsuite/gdb.ada/record-overloads/pck.ads
> create mode 100644 gdb/testsuite/gdb.ada/record-overloads/prog.adb
>
> diff --git a/gdb/ada-lang.c b/gdb/ada-lang.c
> index 174e04af04c..f1aa13fff97 100644
> --- a/gdb/ada-lang.c
> +++ b/gdb/ada-lang.c
> @@ -4029,6 +4029,57 @@ ada_type_match_arrays (struct type *ftype, struct type *atype)
> return ada_type_match (f_elt_type, a_elt_type);
> }
>
> +/* Helper for ada_type_match that checks that two record types are
> + compatible. As with that function, FTYPE is the formal type and
> + ATYPE is the actual type.
> +
> + Note that it is ok if this function is not precise, as long as
> + there aren't too many false negatives. That is, it's better to
> + return 'true', because that will result in a menu being presented
> + to the user. */
> +
I don't fully understand the reasoning here. AFAIU, if there is only
one match, no menu will be presented. In that case, is returning true
still a conservative choice?
Thanks,
- Tom
> +static bool
> +ada_type_match_records (type *ftype, type *atype)
> +{
> + /* In the case of tagged types, we look through the parent types;
> + hence the loop. */
> + while (atype != nullptr)
> + {
> + if (ftype == atype)
> + return true;
> +
> + /* Note that the formal type might be dynamic in some way. So,
> + the checks we can do easily are fairly limited. However, in
> + Ada simply checking the name should be sufficient, because
> + Ada doesn't allow anonymous record types; nor does it allow
> + two record types with the same name. And, if this is somehow
> + violated (through shared library shenanigans or something),
> + then it's fine to conservatively return 'true'. Note we use
> + the safe name here, because although Ada doesn't allow
> + anonymous types, with a little effort the user could arrange
> + for any type as the actual type. */
> + if (streq (ftype->safe_name (), atype->safe_name ()))
> + return true;
> +
> + /* Currently, gdb does not implement dispatching calls, and
> + class-wide types aren't well-represented in the DWARF anyway.
> + So as a heuristic, return true if the formal type is a parent
> + of the actual type. This works out OK because gdb finds the
> + true runtime type of the actual parameter.
> +
> + This could be improved by further examining the overload set
> + for a best match. However this isn't done today, which is
> + why the heuristic is needed. */
> + if (!ada_is_tagged_type (atype, false))
> + break;
> +
> + /* If this returns nullptr, the loop will stop. */
> + atype = ada_parent_type (atype);
> + }
> +
> + return false;
> +}
> +
> /* Return non-zero if formal type FTYPE matches actual type ATYPE.
> The term "match" here is rather loose. The match is heuristic and
> liberal -- while it tries to reject matches that are obviously
> @@ -4046,6 +4097,10 @@ ada_type_match (struct type *ftype, struct type *atype)
> if (atype->code () == TYPE_CODE_REF)
> atype = ada_check_typedef (atype->target_type ());
>
> + /* Also remove aligner types. */
> + ftype = ada_aligned_type (ftype);
> + atype = ada_aligned_type (atype);
> +
> switch (ftype->code ())
> {
> default:
> @@ -4074,7 +4129,8 @@ ada_type_match (struct type *ftype, struct type *atype)
> case TYPE_CODE_STRUCT:
> if (!ada_is_array_descriptor_type (ftype))
> return (atype->code () == TYPE_CODE_STRUCT
> - && !ada_is_array_descriptor_type (atype));
> + && !ada_is_array_descriptor_type (atype)
> + && ada_type_match_records (ftype, atype));
>
> [[fallthrough]];
> case TYPE_CODE_ARRAY:
> diff --git a/gdb/testsuite/gdb.ada/record-overloads.exp b/gdb/testsuite/gdb.ada/record-overloads.exp
> new file mode 100644
> index 00000000000..05318cedd30
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/record-overloads.exp
> @@ -0,0 +1,70 @@
> +# Copyright 2026 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/>.
> +
> +load_lib "ada.exp"
> +
> +require allow_ada_tests
> +
> +standard_ada_testfile prog
> +
> +foreach_gnat_encoding scenario flags {all minimal} {
> + lappend flags debug
> +
> + if {[gdb_compile_ada "${srcfile}" "${binfile}-${scenario}" \
> + executable $flags] != ""} {
> + return
> + }
> +
> + clean_restart ${testfile}-${scenario}
> +
> + set bp_location [gdb_get_line_number "START" ${testdir}/prog.adb]
> + runto "prog.adb:$bp_location"
> +
> + gdb_test "print oload(r1)" [quotemeta {@DECIMAL = 0}]
> + gdb_test "print oload(r2)" [quotemeta {@DECIMAL = 1}]
> +
> + # This one is not ambiguous.
> + gdb_test "print oload(rb)" [quotemeta {@DECIMAL = 2}]
> +
> + # Neither is this one, because gdb can see that RCB's runtime type
> + # is Rec_Base.
> + gdb_test "print oload(rcb)" [quotemeta {@DECIMAL = 2}]
> +
> + gdb_test "print oload(rcf)" [quotemeta {@DECIMAL = 4}]
> +
> + proc test_menu {var} {
> + set menu [multi_line "Multiple matches for oload" \
> + "\\\[0\\\] cancel" \
> + "\\\[1\\\] pck.oload (.*rec_base).*" \
> + "\\\[2\\\] pck.oload (.*rec_derived).*" \
> + "> $"]
> + gdb_test_multiple "print oload($var)" "menu for $var" {
> + -re "$menu" {
> + pass "$gdb_test_name"
> + }
> + default {
> + fail "$gdb_test_name"
> + }
> + }
> + # Cancel the call.
> + gdb_test 0 cancelled "cancel call for $var"
> + }
> +
> + # These should not be ambiguous, but currently are: RD because gdb
> + # can't tell the difference between a type and a class-wide type;
> + # and RCD because gdb does not implement dispatching.
> + test_menu rd
> + test_menu rcd
> +}
> diff --git a/gdb/testsuite/gdb.ada/record-overloads/pck.adb b/gdb/testsuite/gdb.ada/record-overloads/pck.adb
> new file mode 100644
> index 00000000000..e4cad65d8b2
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/record-overloads/pck.adb
> @@ -0,0 +1,43 @@
> +-- Copyright 2026 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/>.
> +
> +package body Pck is
> +
> + function Oload (C : Rec_1) return Integer is
> + begin
> + return 0;
> + end Oload;
> +
> + function Oload (C : Rec_2) return Integer is
> + begin
> + return 1;
> + end Oload;
> +
> + function Oload (C : Rec_Base) return Integer is
> + begin
> + return 2;
> + end Oload;
> +
> + function Oload (C : Rec_Derived) return Integer is
> + begin
> + return 3;
> + end Oload;
> +
> + function Oload (C : Rec_Dyn) return Integer is
> + begin
> + return 4;
> + end Oload;
> +
> +end Pck;
> diff --git a/gdb/testsuite/gdb.ada/record-overloads/pck.ads b/gdb/testsuite/gdb.ada/record-overloads/pck.ads
> new file mode 100644
> index 00000000000..2863637e008
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/record-overloads/pck.ads
> @@ -0,0 +1,50 @@
> +-- Copyright 2026 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/>.
> +
> +package Pck is
> +
> + type Rec_1 is record
> + X : Integer;
> + end record;
> +
> + type Rec_2 is record
> + X : Integer;
> + end record;
> +
> + function Oload (C : Rec_1) return Integer;
> + function Oload (C : Rec_2) return Integer;
> +
> + type Rec_Base is tagged record
> + X : Integer;
> + end record;
> +
> + function Oload (C : Rec_Base) return Integer;
> +
> + type Rec_Derived is new Rec_Base with null record;
> +
> + function Oload (C : Rec_Derived) return Integer;
> +
> + type Rec_Dyn (Cond : Boolean := True) is record
> + case Cond is
> + when True =>
> + TV : Integer;
> + when False =>
> + FV : Integer;
> + end case;
> + end record;
> +
> + function Oload (C : Rec_Dyn) return Integer;
> +
> +end Pck;
> diff --git a/gdb/testsuite/gdb.ada/record-overloads/prog.adb b/gdb/testsuite/gdb.ada/record-overloads/prog.adb
> new file mode 100644
> index 00000000000..2951845ccb0
> --- /dev/null
> +++ b/gdb/testsuite/gdb.ada/record-overloads/prog.adb
> @@ -0,0 +1,32 @@
> +-- Copyright 2026 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/>.
> +
> +with Pck; use Pck;
> +
> +procedure Prog is
> +
> + R1 : Rec_1 := (X => 23);
> + R2 : Rec_2 := (X => 23);
> + RB : Rec_Base := (X => 23);
> + RD : Rec_Derived := (X => 23);
> +
> + RCB : Rec_Base'Class := RB;
> + RCD : Rec_Base'Class := RD;
> +
> + RCF : Rec_Dyn := (Cond => False, FV => 23);
> +
> +begin
> + null; -- START
> +end Prog;
>
> base-commit: 625a5c311e6df32aa28214d017c65303bb5d6451
next prev parent reply other threads:[~2026-08-27 14:18 UTC|newest]
Thread overview: 3+ messages / expand[flat|nested] mbox.gz Atom feed top
2026-08-26 20:13 Tom Tromey
2026-08-27 14:17 ` Tom de Vries [this message]
2026-08-27 16:08 ` Tom Tromey
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=8c8a38de-5db7-4857-95d1-4abf2a010d54@suse.de \
--to=tdevries@suse.de \
--cc=gdb-patches@sourceware.org \
--cc=tromey@adacore.com \
/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