diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 6c6ca96f8d9..08dd0b76b23 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -21921,6 +21921,41 @@ typename_concat (struct obstack *obs, const char *prefix, const char *suffix, } } +/* Return a generic name for a DW_TAG_template_type_param or + DW_TAG_template_value_param tag, missing a DW_AT_name attribute. We do this + per parent, so each function/class/struct template will have their own set + of template parameters named , , ... where the + enumeration starts at 0 and represents the position of the template tag in + the list of unnamed template tags for this parent, counting both, type and + value tags. */ + +static const char * +unnamed_template_tag_name (die_info *die, dwarf2_cu *cu) +{ + if (die->parent == nullptr) + return nullptr; + + /* Count the parent types unnamed template type and value children until, we + arrive at our entry. */ + size_t nth_unnamed = 0; + + die_info *child = die->parent->child; + while (child != die) + { + gdb_assert (child != nullptr); + if (child->tag == DW_TAG_template_type_param + || child->tag == DW_TAG_template_value_param) + { + if (dwarf2_attr (child, DW_AT_name, cu) == nullptr) + ++nth_unnamed; + } + child = child->sibling; + } + + const std::string name_str = ""; + return cu->per_objfile->objfile->intern (name_str.c_str ()); +} + /* Get name of a die, return NULL if not found. */ static const char * @@ -21956,7 +21991,9 @@ dwarf2_name (struct die_info *die, struct dwarf2_cu *cu) && die->tag != DW_TAG_interface_type && die->tag != DW_TAG_structure_type && die->tag != DW_TAG_namelist - && die->tag != DW_TAG_union_type) + && die->tag != DW_TAG_union_type + && die->tag != DW_TAG_template_type_param + && die->tag != DW_TAG_template_value_param) return NULL; switch (die->tag) @@ -21976,6 +22013,12 @@ dwarf2_name (struct die_info *die, struct dwarf2_cu *cu) return attr_name; return CP_ANONYMOUS_NAMESPACE_STR; + /* DWARF does not actually require template tags to have a name. */ + case DW_TAG_template_type_param: + case DW_TAG_template_value_param: + if (attr_name == nullptr) + return unnamed_template_tag_name (die, cu); + /* FALLTHROUGH. */ case DW_TAG_class_type: case DW_TAG_interface_type: case DW_TAG_structure_type: diff --git a/gdb/testsuite/gdb.dwarf2/missing-type-name-for-templates.cc b/gdb/testsuite/gdb.dwarf2/missing-type-name-for-templates.cc new file mode 100644 index 00000000000..06746b533fd --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/missing-type-name-for-templates.cc @@ -0,0 +1,58 @@ +/* Copyright (C) 2022 Free Software Foundation, Inc. + + This file is part of GDB. + + 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 . */ + +template +class template_var1 +{ + first me; + second me2; +}; + +template +class template_var2 +{ + first me; + second me2; +}; + +template +class template_var3 +{ + first me; + second me2; +}; + +template +class template_var1; + +template +class template_var2; + +template +class template_var3; + +int +main (int argc, char **argv) +{ + asm ("main_label: .globl main_label"); + + template_var1 var1; + template_var2 var2; + template_var3<0, int, 11, float> var3; + + return 0; +} diff --git a/gdb/testsuite/gdb.dwarf2/missing-type-name-for-templates.exp b/gdb/testsuite/gdb.dwarf2/missing-type-name-for-templates.exp new file mode 100644 index 00000000000..14339c86ded --- /dev/null +++ b/gdb/testsuite/gdb.dwarf2/missing-type-name-for-templates.exp @@ -0,0 +1,170 @@ +# 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 tests GDB's handling of DW_TAG_template_type_parameter and +# DW_TAG_template_value_parameter tags that do not have a DW_AT_name attribute. +# The attribute is optional for the tags and a bug about GDB not recording +# the respective symbols (because of the missing name) was reported in PR +# gdb/28396. + +load_lib dwarf.exp + +if {![dwarf2_support]} { + return 0 +} + +standard_testfile .cc .S + +set asm_file [standard_output_file $srcfile2] +Dwarf::assemble $asm_file { + cu {} { + DW_TAG_compile_unit { + {DW_AT_language @DW_LANG_C_plus_plus} + } { + declare_labels int float template_var1 template_var2 template_var3 + + int: DW_TAG_base_type { + {DW_AT_name "int"} + {DW_AT_byte_size 4 DW_FORM_data1} + {DW_AT_encoding @DW_ATE_signed} + } + + float: base_type { + {DW_AT_name float} + {DW_AT_byte_size 4 DW_FORM_sdata} + {DW_AT_encoding @DW_ATE_float} + } + + DW_TAG_subprogram { + {DW_AT_name "main"} + {MACRO_AT_range "main"} + {DW_AT_type :$int} + {DW_AT_external 1 DW_FORM_flag} + } { + DW_TAG_variable { + {DW_AT_name "var1"} + {DW_AT_type :$template_var1} + } + DW_TAG_variable { + {DW_AT_name "var2"} + {DW_AT_type :$template_var2} + } + DW_TAG_variable { + {DW_AT_name "var3"} + {DW_AT_type :$template_var3} + } + } + + # A variable whose type is a template instantiation with two + # template parameters, one unnamed. + template_var1: DW_TAG_structure_type { + {DW_AT_name "template_var1"} + } { + DW_TAG_member { + {DW_AT_name "me"} + {DW_AT_type :$int} + } + DW_TAG_member { + {DW_AT_name "me2"} + {DW_AT_type :$float} + } + DW_TAG_template_type_param { + {DW_AT_type :$int} + } + DW_TAG_template_type_param { + {DW_AT_name "second"} + {DW_AT_type :$float} + } + } + + # A variable whose type is a template instantiation with two + # template parameters, both unnamed. + template_var2: DW_TAG_class_type { + {DW_AT_name "template_var2"} + } { + DW_TAG_member { + {DW_AT_name "me"} + {DW_AT_type :$int} + } + DW_TAG_member { + {DW_AT_name "me2"} + {DW_AT_type :$float} + } + DW_TAG_template_type_param { + {DW_AT_type :$int} + } + DW_TAG_template_type_param { + {DW_AT_type :$float} + } + } + + # A variable whose type is a template instantiation with four + # template arguments, two types, two values, all unnamed. + template_var3: DW_TAG_structure_type { + {DW_AT_name "template_var3<0, int, 11, float>"} + } { + DW_TAG_member { + {DW_AT_name "me"} + {DW_AT_type :$int} + } + DW_TAG_member { + {DW_AT_name "me2"} + {DW_AT_type :$float} + } + DW_TAG_template_value_param { + {DW_AT_type :$int} + {DW_AT_const_value 0 DW_FORM_sdata} + } + DW_TAG_template_type_param { + {DW_AT_type :$int} + } + DW_TAG_template_value_param { + {DW_AT_type :$int} + {DW_AT_const_value 11 DW_FORM_sdata} + } + DW_TAG_template_type_param { + {DW_AT_type :$float} + } + } + } + } +} + +if { [prepare_for_testing "failed to prepare" ${testfile} \ + [list $srcfile $asm_file] {nodebug c++}] } { + return -1 +} + +if ![runto_main] { + return -1 +} + +gdb_test "ptype var1" [multi_line \ + "type = struct template_var1 \\\[with = int, second = float\\\] {" \ + " me;" \ + " second me2;" \ + "}"] + +gdb_test "ptype var2" [multi_line \ + "type = class template_var2 \\\[with = int, = float\\\] {" \ + " me;" \ + " me2;" \ + "}"] + +gdb_test "ptype var3" [multi_line \ + "type = struct template_var3<0, int, 11, float> \\\[with = int, = float\\\] {" \ + " me;" \ + " me2;" \ + "}"]