}
}
+/* 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 <unnnamed0>, <unnamed1>, ... 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 = "<unnamed" + std::to_string (nth_unnamed) + ">";
+ return cu->per_objfile->objfile->intern (name_str.c_str ());
+}
+
/* Get name of a die, return NULL if not found. */
static const char *
&& 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)
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:
--- /dev/null
+/* 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 <http://www.gnu.org/licenses/>. */
+
+template<typename first, typename second>
+class template_var1
+{
+ first me;
+ second me2;
+};
+
+template<typename first, typename second>
+class template_var2
+{
+ first me;
+ second me2;
+};
+
+template<int val1, typename first, int val2, typename second>
+class template_var3
+{
+ first me;
+ second me2;
+};
+
+template<typename, typename second>
+class template_var1;
+
+template<typename, typename>
+class template_var2;
+
+template<int, typename, int, typename>
+class template_var3;
+
+int
+main (int argc, char **argv)
+{
+ asm ("main_label: .globl main_label");
+
+ template_var1<int, float> var1;
+ template_var2<int, float> var2;
+ template_var3<0, int, 11, float> var3;
+
+ return 0;
+}
--- /dev/null
+# 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 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<int, 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_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<int, 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_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<int, float> \\\[with <unnamed0> = int, second = float\\\] {" \
+ " <unnamed0> me;" \
+ " second me2;" \
+ "}"]
+
+gdb_test "ptype var2" [multi_line \
+ "type = class template_var2<int, float> \\\[with <unnamed0> = int, <unnamed1> = float\\\] {" \
+ " <unnamed0> me;" \
+ " <unnamed1> me2;" \
+ "}"]
+
+gdb_test "ptype var3" [multi_line \
+ "type = struct template_var3<0, int, 11, float> \\\[with <unnamed1> = int, <unnamed3> = float\\\] {" \
+ " <unnamed1> me;" \
+ " <unnamed3> me2;" \
+ "}"]