@@ -970,13 +970,15 @@ c_type_print_base_struct_union (struct type *type, struct ui_file *stream,
c_type_print_template_args (&local_flags, type, stream, language);
- /* Add in template parameters when printing derivation info. */
- if (local_flags.local_typedefs != NULL)
+ if (local_flags.local_typedefs != nullptr
+ && !HAS_TEMPLATE_TYPE_MEMBER (type))
local_flags.local_typedefs->add_template_parameters (type);
cp_type_print_derivation_info (stream, type, &local_flags);
- /* This holds just the global typedefs and the template
- parameters. */
+ /* This holds just the global typedefs, and the template type
+ parameters in case the condition HAS_TEMPLATE_TYPE_MEMBER
+ (type) is not fulfilled. */
+
struct type_print_options semi_local_flags = *flags;
semi_local_flags.local_typedefs = NULL;
@@ -131,6 +131,12 @@ cp_print_value_fields (struct value *val, struct ui_file *stream,
static int last_set_recurse = -1;
struct type *type = check_typedef (val->type ());
+
+ /* For templated types we want to print the value based on its target
+ type. */
+ if (val->type ()->code () == TYPE_CODE_TEMPLATE_TYPE_PARAM
+ && val->type ()->target_type () != nullptr)
+ type = type->target_type ();
if (recurse == 0)
{
@@ -11489,8 +11489,31 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
struct field_info fi;
std::vector<struct symbol *> template_args;
+ if (cu->lang () == language_cplus)
+ {
+ if (!HAVE_CPLUS_STRUCT (type))
+ ALLOCATE_CPLUS_STRUCT_TYPE (type);
+ HAS_TEMPLATE_TYPE_MEMBER (type) = false;
+ }
+
for (die_info *child_die : die->children ())
- handle_struct_member_die (child_die, type, &fi, &template_args, cu);
+ {
+ handle_struct_member_die (child_die, type, &fi, &template_args, cu);
+
+ /* This is a heuristic to detect when DWARF actually references
+ template type parameter DIEs. */
+ if (!template_args.empty () && !HAS_TEMPLATE_TYPE_MEMBER (type))
+ {
+ attribute *type_attr = dwarf2_attr (child_die, DW_AT_type, cu);
+ if (type_attr != nullptr && type_attr->form_is_ref ())
+ {
+ die_info *type_die
+ = follow_die_ref (child_die, type_attr, &cu);
+ if (type_die->tag == DW_TAG_template_type_param)
+ HAS_TEMPLATE_TYPE_MEMBER (type) = true;
+ }
+ }
+ }
/* Attach template arguments to type. */
if (!template_args.empty ())
@@ -1783,6 +1783,12 @@ struct cplus_struct_type
classes. */
struct symbol **template_arguments;
+
+ /* Flag used in the heuristic to detect a specific DWARF format for
+ type DIEs describing source entities referring to the formal template
+ type parameter. This flag is true if such type DIEs refer to a
+ DW_TAG_template_type_parameter DIE, otherwise it is set to false. */
+ bool has_template_type_member;
};
/* * Struct used to store conversion rankings. */
@@ -1991,6 +1997,8 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
TYPE_CPLUS_SPECIFIC (thistype)->n_template_arguments
#define TYPE_TEMPLATE_ARGUMENTS(thistype) \
TYPE_CPLUS_SPECIFIC (thistype)->template_arguments
+#define HAS_TEMPLATE_TYPE_MEMBER(thistype) \
+ TYPE_CPLUS_SPECIFIC (thistype)->has_template_type_member
#define TYPE_TEMPLATE_ARGUMENT(thistype, n) \
TYPE_CPLUS_SPECIFIC (thistype)->template_arguments[n]
new file mode 100644
@@ -0,0 +1,95 @@
+/* This testcase is part of GDB, the GNU debugger.
+
+ Copyright (C) 2025 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/>. */
+
+template <typename T, typename U>
+struct A
+{
+ A () : t_val (), u_val (), i_val (), f_val () { }
+ T t_val;
+ U u_val;
+ int i_val;
+ float f_val;
+
+ T tfunc (T tval, U uval)
+ {
+ return tval;
+ }
+
+ int ifunc (int ival, T tval)
+ {
+ return ival;
+ }
+
+ float ffunc (float fval, U uval)
+ {
+ return fval;
+ }
+};
+
+template<typename T>
+struct B {
+ T t_val;
+
+ template<typename U>
+ struct C {
+ U u_val;
+ };
+
+ C<T> c;
+};
+
+int
+main ()
+{
+ A<int, int> a;
+ a.t_val = 1;
+ a.u_val = 2;
+ a.i_val = 3;
+ a.f_val = 4.0f;
+
+ A<float, float> b;
+ b.t_val = 1;
+ b.u_val = 2.0f;
+ b.i_val = 3;
+ b.f_val = 4.0f;
+
+ A<float, int> c;
+ c.t_val = 1.0;
+ c.u_val = 2;
+ c.i_val = 3;
+ c.f_val = 4.0f;
+
+ A<A<float, int>, A<float, float>> d;
+ d.t_val = c;
+ d.u_val = b;
+ d.i_val = 3;
+ d.f_val = 4.0f;
+
+ A<A<float, float>, A<float, float>> e;
+ e.t_val = b;
+ e.u_val = b;
+ e.i_val = 3;
+ e.f_val = 4.0f;
+
+ B<int> f;
+ f.t_val = 1;
+
+ B<B<int>> g;
+ g.t_val = f;
+
+ return 0; /* Break here. */
+}
new file mode 100644
@@ -0,0 +1,195 @@
+# Copyright 2025 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/>.
+#
+# Test extended template type resolution for a DWARF format which allows
+# GDB to differentiate between template types and normal types, which have
+# the same target type.
+#
+# This test is only supported in case a compiler is used which supports a
+# specific DWARF format for type references of DIEs that describe source
+# entities referring to the formal template parameter.
+# They must reference the DW_TAG_template_type_parameter DIE, and not the
+# underlying type DIE.
+#
+# This format is described in the DWARF 5 spec:
+# "A template type parameter is represented by a debugging information
+# entry with the tag DW_TAG_template_type_parameter."
+# which also lists the following example (Figure D.51):
+# ! DWARF description
+# !
+# 11$: DW_TAG_structure_type
+# DW_AT_name("wrapper")
+#
+# 12$: DW_TAG_template_type_parameter
+# DW_AT_name("T")
+# DW_AT_type(reference to "int")
+#
+# 13$: DW_TAG_member
+# DW_AT_name("comp")
+# DW_AT_type(reference to 12$)
+#
+# 14$: DW_TAG_variable
+# DW_AT_name("obj")
+# DW_AT_type(reference to 11$)
+#
+# For current versions of GCC and Clang this test will fail.
+
+standard_testfile .cc
+
+if { [prepare_for_testing "failed to prepare" $testfile $srcfile {debug} ] } {
+ return
+}
+
+if { ![runto_main] } {
+ return
+}
+
+gdb_breakpoint [gdb_get_line_number "Break here."]
+gdb_continue_to_breakpoint "Break here."
+
+# Test same target type int.
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype a" \
+ [multi_line "type = struct A<int, int> \\\[with T = int, U = int\\\] {" \
+ ".*T t_val;.*" \
+ ".*U u_val;.*" \
+ ".*int i_val;.*" \
+ ".*float f_val;.*" \
+ ".*A\\(void\\);.*" \
+ ".*T tfunc\\(T, U\\);.*" \
+ ".*int ifunc\\(int, T\\);.*" \
+ ".*float ffunc\\(float, U\\);.*" ]
+
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype a.t_val" "type = T"
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype a.u_val" "type = U"
+gdb_test "ptype a.i_val" "type = int"
+gdb_test "ptype a.f_val" "type = float"
+
+set val "{t_val = 1, u_val = 2, i_val = 3, f_val = 4}"
+gdb_test "print a" "$val"
+
+# Test same target type float.
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype b" \
+ [multi_line "type = struct A<float, float> \\\[with T = float, U = float\\\] {" \
+ ".*T t_val;.*" \
+ ".*U u_val;.*" \
+ ".*int i_val;.*" \
+ ".*float f_val;.*" \
+ ".*A\\(void\\);.*" \
+ ".*T tfunc\\(T, U\\);.*" \
+ ".*int ifunc\\(int, T\\);.*" \
+ ".*float ffunc\\(float, U\\);.*" ]
+
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype b.t_val" "type = T"
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype b.u_val" "type = U"
+gdb_test "ptype b.i_val" "type = int"
+gdb_test "ptype b.f_val" "type = float"
+
+gdb_test "print b" "$val"
+
+# Test different target types.
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype c" \
+ [multi_line "type = struct A<float, int> \\\[with T = float, U = int\\\] {" \
+ ".*T t_val;.*" \
+ ".*U u_val;.*" \
+ ".*int i_val;.*" \
+ ".*float f_val;.*" \
+ ".*A\\(void\\);.*" \
+ ".*T tfunc\\(T, U\\);.*" \
+ ".*int ifunc\\(int, T\\);.*" \
+ ".*float ffunc\\(float, U\\);.*" ]
+
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype c.t_val" "type = T"
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype c.u_val" "type = U"
+gdb_test "ptype c.i_val" "type = int"
+gdb_test "ptype c.f_val" "type = float"
+
+gdb_test "print c" "$val"
+
+# Test nested template types: d
+gdb_test "ptype d" \
+ [multi_line "type = struct A<A<float, int>, A<float, float> > \\\[with T = A<float, int>, U = A<float, float>\\\] {" \
+ ".*T t_val;.*" \
+ ".*U u_val;.*" \
+ ".*int i_val;.*" \
+ ".*float f_val;.*" \
+ ".*A\\(void\\);.*" \
+ ".*T tfunc\\(T, U\\);.*" \
+ ".*int ifunc\\(int, T\\);.*" \
+ ".*float ffunc\\(float, U\\);.*" ]
+
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype d.t_val" "type = T"
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype d.u_val" "type = U"
+gdb_test "ptype d.i_val" "type = int"
+gdb_test "ptype d.f_val" "type = float"
+
+gdb_test "print d" "{t_val = $val, u_val = $val, i_val = 3, f_val = 4}"
+
+# Test nested template types: e
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype e" \
+ [multi_line "type = struct A<A<float, float>, A<float, float> > \\\[with T = A<float, float>, U = A<float, float>\\\] {" \
+ ".*T t_val;.*" \
+ ".*U u_val;.*" \
+ ".*int i_val;.*" \
+ ".*float f_val;.*" \
+ ".*A\\(void\\);.*" \
+ ".*T tfunc\\(T, U\\);.*" \
+ ".*int ifunc\\(int, T\\);.*" \
+ ".*float ffunc\\(float, U\\);.*" ]
+
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype e.t_val" "type = T"
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype e.u_val" "type = U"
+gdb_test "ptype e.i_val" "type = int"
+gdb_test "ptype e.f_val" "type = float"
+
+gdb_test "print e" "{t_val = $val, u_val = $val, i_val = 3, f_val = 4}"
+
+gdb_test "ptype f" \
+ [multi_line "type = struct B<int> \\\[with T = int\\\] {" \
+ ".*T t_val;.*" \
+ ".*B<T>::C<T> c;.*" ]
+
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype f.t_val" "type = T"
+
+gdb_test "ptype f.c" \
+ [multi_line "type = struct B<int>::C<int> \\\[with U = int\\\] {" \
+ ".*U u_val;.*" ]
+
+gdb_test "ptype g" \
+ [multi_line "type = struct B<B<int> > \\\[with T = B<int>\\\] {" \
+ ".*T t_val;.*" \
+ ".*B<T>::C<T> c;.*" ]
+
+setup_xfail gcc/57006 "*-*-*"
+gdb_test "ptype g.t_val" "type = T"
+
+gdb_test "ptype g.c" \
+ [multi_line "type = struct B<B<int> >::C<B<int> > \\\[with U = B<int>\\\] {" \
+ ".*U u_val;.*" ]
+
@@ -15,10 +15,13 @@
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 T>
+template <typename T, typename U>
struct A
{
T me_t;
+ int me_int;
+ U me_u;
+ float me_float;
T t_func (T tval)
{
@@ -27,7 +30,9 @@ struct A
};
-A<int> var = {0};
+A<int, float> var = {0, 0, 0.0f, 0.0f};
+A<A<float, float>, A<float, float>> nestedvar
+ = {{0.0f, 0, 0.0f, 0.0f}, 0, {0.0f, 0, 0.0f, 0.0f}, 0.0f};
int
main ()
@@ -57,16 +57,21 @@ if { ![runto_main] } {
}
set int_size [get_sizeof "int" -1]
+set float_size [get_sizeof "float" -1]
set asm_file1 [standard_output_file $srcfile2]
Dwarf::assemble $asm_file1 {
- global int_size
+ global int_size float_size
cu {} {
DW_TAG_compile_unit {
DW_AT_language @DW_LANG_C_plus_plus
} {
- declare_labels int
- declare_labels A template_type_int template_pointer1
+ declare_labels int float
+ declare_labels A template_type_float template_type_int
+ declare_labels template_pointer1 template_pointer2 template_pointer3
+ declare_labels nestedvar_type template_type_floatfloat
+ declare_labels template_type_float2 template_type_float3
+ declare_labels template_type_float4 template_type_float5
int: DW_TAG_base_type {
DW_AT_name "int"
@@ -74,22 +79,44 @@ Dwarf::assemble $asm_file1 {
DW_AT_encoding @DW_ATE_signed
}
+ float: DW_TAG_base_type {
+ DW_AT_name "float"
+ DW_AT_byte_size 4 DW_FORM_sdata
+ DW_AT_encoding @DW_ATE_float
+ }
+
DW_TAG_subprogram {
MACRO_AT_func "main"
}
A: DW_TAG_structure_type {
DW_AT_name "A"
- DW_AT_byte_size $int_size DW_FORM_sdata
+ DW_AT_byte_size 2*$int_size+2*$float_size DW_FORM_sdata
} {
template_type_int: DW_TAG_template_type_param {
DW_AT_type :$int
DW_AT_name "T"
}
+ template_type_float: DW_TAG_template_type_param {
+ DW_AT_type :$float
+ DW_AT_name "U"
+ }
DW_TAG_member {
DW_AT_name "me_t"
DW_AT_type :$template_type_int
}
+ DW_TAG_member {
+ DW_AT_name "me_int"
+ DW_AT_type :$int
+ }
+ DW_TAG_member {
+ DW_AT_name "me_u"
+ DW_AT_type :$template_type_float
+ }
+ DW_TAG_member {
+ DW_AT_name "me_float"
+ DW_AT_type :$float
+ }
DW_TAG_subprogram {
DW_AT_external 1 DW_FORM_flag
@@ -109,6 +136,7 @@ Dwarf::assemble $asm_file1 {
}
template_pointer1: DW_TAG_pointer_type {
+ DW_AT_byte_size 8 DW_FORM_data8
DW_AT_type :$A
}
@@ -120,6 +148,117 @@ Dwarf::assemble $asm_file1 {
} SPECIAL_expr
DW_AT_external 1 DW_FORM_flag
}
+
+ template_type_floatfloat: DW_TAG_structure_type {
+ DW_AT_name "A"
+ DW_AT_byte_size 2*$int_size+2*$float_size DW_FORM_sdata
+ } {
+ template_type_float2: DW_TAG_template_type_param {
+ DW_AT_type :$float
+ DW_AT_name "T"
+ }
+ template_type_float3: DW_TAG_template_type_param {
+ DW_AT_type :$float
+ DW_AT_name "U"
+ }
+ DW_TAG_member {
+ DW_AT_name "me_t"
+ DW_AT_type :$template_type_float2
+ }
+ DW_TAG_member {
+ DW_AT_name "me_int"
+ DW_AT_type :$int
+ }
+ DW_TAG_member {
+ DW_AT_name "me_u"
+ DW_AT_type :$template_type_float3
+ }
+ DW_TAG_member {
+ DW_AT_name "me_float"
+ DW_AT_type :$float
+ }
+
+ DW_TAG_subprogram {
+ DW_AT_external 1 DW_FORM_flag
+ DW_AT_name "t_func"
+ DW_AT_type :$template_type_float2
+ DW_AT_declaration 1 DW_FORM_flag
+ } {
+ DW_TAG_formal_parameter {
+ DW_AT_type :$template_pointer2
+ DW_AT_artificial 1 DW_FORM_flag
+ }
+
+ DW_TAG_formal_parameter {
+ DW_AT_type :$template_type_float2
+ }
+ }
+ }
+
+ template_pointer2: DW_TAG_pointer_type {
+ DW_AT_byte_size 8 DW_FORM_data8
+ DW_AT_type :$template_type_floatfloat
+ }
+
+ nestedvar_type: DW_TAG_structure_type {
+ DW_AT_name "A"
+ DW_AT_byte_size 2*$int_size+2*$float_size DW_FORM_sdata
+ } {
+ template_type_float4: DW_TAG_template_type_param {
+ DW_AT_type :$template_type_floatfloat
+ DW_AT_name "T"
+ }
+ template_type_float5: DW_TAG_template_type_param {
+ DW_AT_type :$template_type_floatfloat
+ DW_AT_name "U"
+ }
+ DW_TAG_member {
+ DW_AT_name "me_t"
+ DW_AT_type :$template_type_float4
+ }
+ DW_TAG_member {
+ DW_AT_name "me_int"
+ DW_AT_type :$int
+ }
+ DW_TAG_member {
+ DW_AT_name "me_u"
+ DW_AT_type :$template_type_float5
+ }
+ DW_TAG_member {
+ DW_AT_name "me_float"
+ DW_AT_type :$float
+ }
+
+ DW_TAG_subprogram {
+ DW_AT_external 1 DW_FORM_flag
+ DW_AT_name "t_func"
+ DW_AT_type :$template_type_float4
+ DW_AT_declaration 1 DW_FORM_flag
+ } {
+ DW_TAG_formal_parameter {
+ DW_AT_type :$template_pointer3
+ DW_AT_artificial 1 DW_FORM_flag
+ }
+
+ DW_TAG_formal_parameter {
+ DW_AT_type :$template_type_float4
+ }
+ }
+ }
+
+ template_pointer3: DW_TAG_pointer_type {
+ DW_AT_byte_size 8 DW_FORM_data8
+ DW_AT_type :$nestedvar_type
+ }
+
+ DW_TAG_variable {
+ DW_AT_name "nestedvar"
+ DW_AT_type :$nestedvar_type
+ DW_AT_location {
+ DW_OP_addr [gdb_target_symbol "nestedvar"]
+ } SPECIAL_expr
+ DW_AT_external 1 DW_FORM_flag
+ }
}
}
}
@@ -133,12 +272,196 @@ if { ![runto_main] } {
return
}
+# Setup strings used in the tests below.
+set var "{me_t = 0, me_int = 0, me_u = 0, me_float = 0}"
+set tfloatfloat "A<float, float>"
+
gdb_test "ptype var" [multi_line \
- "type = struct A<int> \\\[with T = int\\\] {" \
- " T me_t;.*" \
+"type = struct A<int, float> \\\[with T = int, U = float\\\] {" \
+ " T me_t;" \
+ " int me_int;" \
+ " U me_u;" \
+ " float me_float;.*" \
" T t_func\\\(T\\\);.*" \
- "}"]
+"}"]
gdb_test "ptype var.me_t" "type = T"
-gdb_test "print var" "\\\{me_t = 0\\\}"
+gdb_test "ptype var.me_int" "type = int"
+gdb_test "ptype var.me_u" "type = U"
+gdb_test "ptype var.me_float" "type = float"
+
+gdb_test "print var" "$var"
+
+gdb_test "ptype nestedvar" [multi_line \
+ "type = struct A<$tfloatfloat, $tfloatfloat > \\\[with T = $tfloatfloat, U = $tfloatfloat\\\] {" \
+ " T me_t;" \
+ " int me_int;" \
+ " U me_u;" \
+ " float me_float;.*" \
+ " T t_func\\\(T\\\);.*" \
+"}"]
+gdb_test "ptype nestedvar.me_t" "type = T"
+gdb_test "ptype nestedvar.me_int" "type = int"
+gdb_test "ptype nestedvar.me_u" "type = U"
+gdb_test "ptype nestedvar.me_float" "type = float"
+
+gdb_test "print nestedvar" "{me_t = $var, me_int = 0, me_u = $var, me_float = 0}"
+
+# Tests for unnamed_var1-unnamed_var3 are basically the same as in
+# missing-type-name-for-template, but with the DWARF format described above.
+
+set asm_file_unnamed_templates [standard_output_file $srcfile2]
+Dwarf::assemble $asm_file_unnamed_templates {
+ global int_size float_size
+ cu {} {
+ DW_TAG_compile_unit {
+ DW_AT_language @DW_LANG_C_plus_plus
+ } {
+ declare_labels int float
+ declare_labels template_var1 template_type_float1 template_type_int1
+ declare_labels template_var2 template_type_float2 template_type_int2
+ declare_labels template_var3 template_type_float3 template_type_int3
+
+ int: DW_TAG_base_type {
+ DW_AT_name "int"
+ DW_AT_byte_size 4 DW_FORM_data1
+ DW_AT_encoding @DW_ATE_signed
+ }
+
+ float: DW_TAG_base_type {
+ DW_AT_name "float"
+ DW_AT_byte_size 4 DW_FORM_sdata
+ DW_AT_encoding @DW_ATE_float
+ }
+
+ DW_TAG_subprogram {
+ MACRO_AT_func "main"
+ }
+
+ # 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_AT_byte_size $int_size+$float_size DW_FORM_sdata
+ } {
+ template_type_int1: DW_TAG_template_type_param {
+ DW_AT_type :$int
+ }
+ DW_TAG_member {
+ DW_AT_name "me"
+ DW_AT_type :$template_type_int1
+ }
+ template_type_float1: DW_TAG_template_type_param {
+ DW_AT_name "second"
+ DW_AT_type :$float
+ }
+ DW_TAG_member {
+ DW_AT_name "me2"
+ DW_AT_type :$template_type_float1
+ }
+ }
+ DW_TAG_variable {
+ DW_AT_name "unnamed_var1"
+ DW_AT_type :$template_var1
+ }
+
+ # 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_AT_byte_size $int_size+$float_size DW_FORM_sdata
+ } {
+ template_type_int2: DW_TAG_template_type_param {
+ DW_AT_type :$int
+ }
+ DW_TAG_member {
+ DW_AT_name "me"
+ DW_AT_type :$template_type_int2
+ }
+ template_type_float2: DW_TAG_template_type_param {
+ DW_AT_type :$float
+ }
+ DW_TAG_member {
+ DW_AT_name "me2"
+ DW_AT_type :$template_type_float2
+ }
+ }
+ DW_TAG_variable {
+ DW_AT_name "unnamed_var2"
+ DW_AT_type :$template_var2
+ }
+
+ # 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"
+ DW_AT_byte_size $int_size+$float_size DW_FORM_sdata
+ } {
+ DW_TAG_member {
+ DW_AT_name "me"
+ DW_AT_type :$template_type_int3
+ }
+ DW_TAG_template_value_param {
+ DW_AT_type :$int
+ DW_AT_const_value 0 DW_FORM_sdata
+ }
+ template_type_int3: 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
+ }
+ template_type_float3: DW_TAG_template_type_param {
+ DW_AT_type :$float
+ }
+ DW_TAG_member {
+ DW_AT_name "me2"
+ DW_AT_type :$template_type_float3
+ }
+ }
+ DW_TAG_variable {
+ DW_AT_name "unnamed_var3"
+ DW_AT_type :$template_var3
+ }
+ }
+ }
+}
+
+set srcfile3 [file join $srcdir $subdir "missing-type-name-for-templates.cc"]
+
+if { [prepare_for_testing "failed to prepare" ${testfile} \
+ [list $srcfile3 $asm_file_unnamed_templates] {debug c++}] } {
+ return
+}
+
+if { ![runto_main] } {
+ return
+}
+
+gdb_test "ptype unnamed_var1" [multi_line \
+ "type = struct template_var1<int, float> \\\[with <unnamed0> = int, second = float\\\] {" \
+ " <unnamed0> me;" \
+ " second me2;" \
+ "}"]
+
+gdb_test "ptype unnamed_var1.me" "type = <unnamed0>"
+gdb_test "ptype unnamed_var1.me2" "type = second"
+
+gdb_test "ptype unnamed_var2" [multi_line \
+ "type = class template_var2<int, float> \\\[with <unnamed0> = int, <unnamed1> = float\\\] {" \
+ " <unnamed0> me;" \
+ " <unnamed1> me2;" \
+ "}"]
+
+gdb_test "ptype unnamed_var2.me" "type = <unnamed0>"
+gdb_test "ptype unnamed_var2.me2" "type = <unnamed1>"
+
+gdb_test "ptype unnamed_var3" [multi_line \
+ "type = struct template_var3<0, int, 11, float> \\\[with <unnamed0> = 0, <unnamed1> = int, <unnamed2> = 11, <unnamed3> = float\\\] {" \
+ " <unnamed1> me;" \
+ " <unnamed3> me2;" \
+ "}"]
+gdb_test "ptype unnamed_var3.me" "type = <unnamed1>"
+gdb_test "ptype unnamed_var3.me2" "type = <unnamed3>"
@@ -224,12 +224,11 @@ typedef_hash_table::add_template_parameters (struct type *t)
tf = XOBNEW (&m_storage, struct decl_field);
tf->name = TYPE_TEMPLATE_ARGUMENT (t, i)->linkage_name ();
type *arg_type = TYPE_TEMPLATE_ARGUMENT (t, i)->type ();
+
+ /* Skip self-referential template type parameters for the
+ hashmap based substitution of template type parameters. */
if (arg_type == nullptr)
- {
- /* Skip self-referential template type parameters for the
- hashmap based substitution of template type parameters. */
- continue;
- }
+ continue;
tf->type = arg_type;
@@ -119,7 +119,14 @@ extern const struct type_print_options type_print_raw_options;
/* A hash table holding decl_field objects. This is more complicated than an
ordinary hash because it must also track the lifetime of some -- but not all
- -- of the contained objects. */
+ -- of the contained objects.
+ Once common compilers such as gcc and clang support DWARF format with DIE
+ type references describing source entities referring to the formal template
+ parameter that reference the DW_TAG_template_type_parameter, the usage of
+ this table for template type parameters is obsolete and can be removed.
+ However, as long as such DIE type references reference the underlying type
+ DIE this table can still be used, but will result in the issue desribed in
+ https://sourceware.org/bugzilla/show_bug.cgi?id=20540. */
class typedef_hash_table
{