diff options
-rw-r--r-- | gdb/testsuite/gdb.cp/incomplete-type-overload.cc | 45 | ||||
-rw-r--r-- | gdb/testsuite/gdb.cp/incomplete-type-overload.exp | 183 | ||||
-rw-r--r-- | gdb/valops.c | 53 |
3 files changed, 277 insertions, 4 deletions
diff --git a/gdb/testsuite/gdb.cp/incomplete-type-overload.cc b/gdb/testsuite/gdb.cp/incomplete-type-overload.cc new file mode 100644 index 0000000..a7b85c9 --- /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 <http://www.gnu.org/licenses/>. */ +class +base { +public: + int member; +}; + +class complete: public base { }; + +class incomplete: public base { }; + +complete comp; +complete *cp = ∁ +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 = 0; + return 0; +} diff --git a/gdb/testsuite/gdb.cp/incomplete-type-overload.exp b/gdb/testsuite/gdb.cp/incomplete-type-overload.exp new file mode 100644 index 0000000..96ed25d --- /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 <http://www.gnu.org/licenses/>. + +# 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_label + + 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 $srcfile] {}] { + return +} + +if ![runto_main] { + return +} + +gdb_test "print foo(cp)" "= 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 ecfceed..2b789cd 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" /* Local functions. */ @@ -2617,6 +2618,49 @@ value_find_oload_method_list (struct value **argp, const char *method, basetype, boffset); } +/* 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<value *> args) +{ + int incomplete_types = 0; + std::string incomplete_arg_names; + for (const struct value *arg : args) + { + struct type *t = value_type (arg); + while (t->code () == TYPE_CODE_PTR) + t = t->target_type (); + if (t->is_stub ()) + { + string_file buffer; + if (incomplete_types > 0) + incomplete_arg_names += ", "; + + current_language->print_type (value_type (arg), "", &buffer, + -1, 0, &type_print_raw_options); + + incomplete_types++; + incomplete_arg_names += buffer.string (); + } + } + std::string hint; + if (incomplete_types > 1) + hint = 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 == 1) + hint = 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<value *> args, if (match_quality == INCOMPATIBLE) { + std::string hint = incomplete_type_hint (args); if (method == 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 == NON_STANDARD) { |