From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: by sourceware.org (Postfix, from userid 7862) id A39AF38582AC; Thu, 10 Nov 2022 13:52:32 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org A39AF38582AC DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/relaxed; d=sourceware.org; s=default; t=1668088352; bh=4hhf4Vw3nL4fYad/wj+K7wcCGcLOqMoaNWl+BCGzgIw=; h=From:To:Subject:Date:From; b=RtUWDk6Ho064zKzSEmt8lJ1EsVyjenjzXMenghTROGWXcJCM3ESVqQb1lH5LQQWRv 50Qre5wYX5BFQl+OfXZcdQqlwqYn9B5sBGTUcZgko065qDYuDmJE268mvowntdxfit P7JpM7NR/bUcKxGjrGYCMcaQSO8cdMt6SKt4yhpk= Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable From: Bruno Larsen To: gdb-cvs@sourceware.org Subject: [binutils-gdb] gdb/c++: Improve error messages in overload resolution X-Act-Checkin: binutils-gdb X-Git-Author: Bruno Larsen X-Git-Refname: refs/heads/master X-Git-Oldrev: 2acccd0a59af7a04e341d31f68b370486d5fc474 X-Git-Newrev: 041de3d73aa121f2ff0c077213598963bfb34b79 Message-Id: <20221110135232.A39AF38582AC@sourceware.org> Date: Thu, 10 Nov 2022 13:52:32 +0000 (GMT) List-Id: https://sourceware.org/git/gitweb.cgi?p=3Dbinutils-gdb.git;h=3D041de3d73aa1= 21f2ff0c077213598963bfb34b79 commit 041de3d73aa121f2ff0c077213598963bfb34b79 Author: Bruno Larsen Date: Wed Oct 5 14:22:56 2022 +0200 gdb/c++: Improve error messages in overload resolution =20 When resolving overloaded functions, GDB relies on knowing relationships between types, i.e. if a type inherits from another. However, some compilers may not add complete information for given types as a way to reduce unnecessary debug information. In these cases, GDB would just say that it couldn't resolve the method or function, with no extra information. =20 The problem is that sometimes the user may not know that the type information is incomplete, and may just assume that there is a bug in GDB. To improve the user experience, we attempt to detect if the overload match failed because of an incomplete type, and warn the user of this. =20 This commit also adds a testcase confirming that the message is only triggered in the correct scenario. This test was not developed as an expansion of gdb.cp/overload.cc because it needed the dwarf assembler, and porting all of overload.cc seemed unnecessary. =20 Approved-By: Tom Tromey Diff: --- gdb/testsuite/gdb.cp/incomplete-type-overload.cc | 45 ++++++ gdb/testsuite/gdb.cp/incomplete-type-overload.exp | 183 ++++++++++++++++++= ++++ gdb/valops.c | 53 ++++++- 3 files changed, 277 insertions(+), 4 deletions(-) diff --git a/gdb/testsuite/gdb.cp/incomplete-type-overload.cc b/gdb/testsui= te/gdb.cp/incomplete-type-overload.cc new file mode 100644 index 00000000000..a7b85c92bbe --- /dev/null +++ b/gdb/testsuite/gdb.cp/incomplete-type-overload.cc @@ -0,0 +1,45 @@ +/* This testcase is part of GDB, the GNU debugger. + + Copyright 2022 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 . = */ +class +base { +public: + int member; +}; + +class complete: public base { }; + +class incomplete: public base { }; + +complete comp; +complete *cp =3D ∁ +incomplete *inc; +int *ip; + +int +foo (base* b) +{ + asm ("foo_label: .globl foo_label"); + return 1; +} + +int +main (void) +{ + asm("main_label: .globl main_label"); + comp.member =3D 0; + return 0; +} diff --git a/gdb/testsuite/gdb.cp/incomplete-type-overload.exp b/gdb/testsu= ite/gdb.cp/incomplete-type-overload.exp new file mode 100644 index 00000000000..96ed25dd5d1 --- /dev/null +++ b/gdb/testsuite/gdb.cp/incomplete-type-overload.exp @@ -0,0 +1,183 @@ +# Copyright 2022 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 . + +# This file is part of GDB's testsuite. + +# This test intends to check the error message that GDB emits when unable +# to determine the correct overloaded function due to incomplete types. + +load_lib dwarf.exp + +if { [skip_cplus_tests] } { return } + +if { ![dwarf2_support] } { return } + +standard_testfile .cc .S +set asm_file [standard_output_file ${srcfile2}] + +if [prepare_for_testing "failed to prepare" $testfile $srcfile {debug c++}= ] { + return +} + +if {[test_compiler_info clang-*-*]} { + untested "gcc is required for dwarf assembler tests" + return +} + +if ![runto_main] { + return +} + +# Get important sizes to create fake dwarf for the test +set int_size [get_sizeof "int" -1] +set addr_size [get_sizeof "void *" -1] +set struct_base_size [get_sizeof "base" 4] +set struct_complete_size [get_sizeof "complete" 4] +get_func_info foo + +# Create fake DWARF for the .cc file. +# This is the best way to ensure we have an incomplete type. +Dwarf::assemble ${asm_file} { + global srcdir subdir srcfile srcfile2 foo_start foo_end + global int_size addr_size struct_base_size struct_complete_size + declare_labels L + + cu {} { + DW_TAG_compile_unit { + {DW_AT_language @DW_LANG_C_plus_plus} + {name $srcfile} + {stmt_list $L DW_FORM_sec_offset} + } { + declare_labels int_label base_label complete_label incomplete_label + declare_labels ptr_base_label ptr_inc_label ptr_comp_label ptr_int_la= bel + + int_label: DW_TAG_base_type { + {DW_AT_byte_size $int_size DW_FORM_sdata} + {DW_AT_encoding @DW_ATE_signed} + {DW_AT_name "int"} + } + + base_label: DW_TAG_class_type { + {DW_AT_byte_size $struct_base_size DW_FORM_sdata} + {DW_AT_name "base"} + } { + DW_TAG_member { + {DW_AT_name "member"} + {DW_AT_type :$int_label} + {DW_AT_data_member_location 0 DW_FORM_sdata} + } + } + + complete_label: DW_TAG_class_type { + {DW_AT_byte_size $struct_complete_size DW_FORM_sdata} + {DW_AT_name "complete"} + } { + DW_TAG_inheritance { + {DW_AT_type :$base_label} + {DW_AT_data_member_location 0 DW_FORM_sdata} + {DW_AT_accessibility 1 DW_FORM_data1} + } + } + + incomplete_label: DW_TAG_class_type { + {DW_AT_name "incomplete"} + {DW_AT_declaration 1 DW_FORM_flag_present} + } + + ptr_base_label: DW_TAG_pointer_type { + {DW_AT_byte_size $addr_size DW_FORM_udata} + {DW_AT_type :$base_label} + } + + ptr_inc_label: DW_TAG_pointer_type { + {DW_AT_byte_size $addr_size DW_FORM_udata} + {DW_AT_type :$incomplete_label} + } + + ptr_comp_label: DW_TAG_pointer_type { + {DW_AT_byte_size $addr_size DW_FORM_udata} + {DW_AT_type :$complete_label} + } + + ptr_int_label: DW_TAG_pointer_type { + {DW_AT_byte_size $addr_size DW_FORM_udata} + {DW_AT_type :$int_label} + } + + DW_TAG_variable { + {DW_AT_name "comp"} + {DW_AT_type :$complete_label} + {DW_AT_location {DW_OP_addr [gdb_target_symbol "comp"]} SPECIAL_expr} + {DW_AT_external 1 DW_FORM_flag} + } + + DW_TAG_variable { + {DW_AT_name "cp"} + {DW_AT_type :$ptr_comp_label} + {DW_AT_location {DW_OP_addr [gdb_target_symbol "cp"]} SPECIAL_expr} + {DW_AT_external 1 DW_FORM_flag} + } + + DW_TAG_variable { + {DW_AT_name "inc"} + {DW_AT_type :$ptr_inc_label} + {DW_AT_location {DW_OP_addr [gdb_target_symbol "inc"]} SPECIAL_expr} + {DW_AT_external 1 DW_FORM_flag} + } + + DW_TAG_variable { + {DW_AT_name "ip"} + {DW_AT_type :$ptr_int_label} + {DW_AT_location {DW_OP_addr [gdb_target_symbol "ip"]} SPECIAL_expr} + {DW_AT_external 1 DW_FORM_flag} + } + + DW_TAG_subprogram { + {MACRO_AT_func {"main"}} + {DW_AT_external 1 flag} + } + DW_TAG_subprogram { + {MACRO_AT_func {"foo"}} + {DW_AT_type :$int_label} + {DW_AT_external 1 flag} + } { formal_parameter { + {DW_AT_name "b"} + {DW_AT_type :$ptr_base_label} + } + } + } + } + + lines {version 2} L { + include_dir "$srcdir/$subdir" + file_name $srcfile 1 + } +} + +if [prepare_for_testing "failed to prepare" $testfile [list $asm_file $src= file] {}] { + return +} + +if ![runto_main] { + return +} + +gdb_test "print foo(cp)" "=3D 1" "successful invocation" +gdb_test "print foo(inc)"\ + "The type. 'incomplete .' isn't fully known to GDB.*"\ + "unsuccessful because declaration" +gdb_test "print foo(ip)"\ + "Cannot resolve function foo to any overloaded instance."\ + "unsuccessful because incorrect" diff --git a/gdb/valops.c b/gdb/valops.c index ecfceed199a..2b789cd76f4 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -41,6 +41,7 @@ #include "extension.h" #include "gdbtypes.h" #include "gdbsupport/byte-vector.h" +#include "typeprint.h" =20 /* Local functions. */ =20 @@ -2617,6 +2618,49 @@ value_find_oload_method_list (struct value **argp, c= onst char *method, basetype, boffset); } =20 +/* Helper function for find_overload_match. If no matches were + found, this function may generate a hint for the user that some + of the relevant types are incomplete, so GDB can't evaluate + type relationships to properly evaluate overloads. + + If no incomplete types are present, an empty string is returned. */ +static std::string +incomplete_type_hint (gdb::array_view args) +{ + int incomplete_types =3D 0; + std::string incomplete_arg_names; + for (const struct value *arg : args) + { + struct type *t =3D value_type (arg); + while (t->code () =3D=3D TYPE_CODE_PTR) + t =3D t->target_type (); + if (t->is_stub ()) + { + string_file buffer; + if (incomplete_types > 0) + incomplete_arg_names +=3D ", "; + + current_language->print_type (value_type (arg), "", &buffer, + -1, 0, &type_print_raw_options); + + incomplete_types++; + incomplete_arg_names +=3D buffer.string (); + } + } + std::string hint; + if (incomplete_types > 1) + hint =3D string_printf (_("\nThe types: '%s' aren't fully known to GDB= ." + " Please cast them directly to the desired" + " typed in the function call."), + incomplete_arg_names.c_str ()); + else if (incomplete_types =3D=3D 1) + hint =3D string_printf (_("\nThe type: '%s' isn't fully known to GDB." + " Please cast it directly to the desired" + " typed in the function call."), + incomplete_arg_names.c_str ()); + return hint; +} + /* Given an array of arguments (ARGS) (which includes an entry for "this" in the case of C++ methods), the NAME of a function, and whether it's a method or not (METHOD), find the best function that @@ -2933,14 +2977,15 @@ find_overload_match (gdb::array_view args, =20 if (match_quality =3D=3D INCOMPATIBLE) { + std::string hint =3D incomplete_type_hint (args); if (method =3D=3D METHOD) - error (_("Cannot resolve method %s%s%s to any overloaded instance"), + error (_("Cannot resolve method %s%s%s to any overloaded instance.%s"), obj_type_name, (obj_type_name && *obj_type_name) ? "::" : "", - name); + name, hint.c_str ()); else - error (_("Cannot resolve function %s to any overloaded instance"), - func_name); + error (_("Cannot resolve function %s to any overloaded instance.%s"), + func_name, hint.c_str ()); } else if (match_quality =3D=3D NON_STANDARD) {