From patchwork Mon Dec 29 15:15:16 2025 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: "Schimpe, Christina" X-Patchwork-Id: 127186 Return-Path: X-Original-To: patchwork@sourceware.org Delivered-To: patchwork@sourceware.org Received: from vm01.sourceware.org (localhost [127.0.0.1]) by sourceware.org (Postfix) with ESMTP id C6DCE4BA2E04 for ; Mon, 29 Dec 2025 15:17:21 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org C6DCE4BA2E04 Authentication-Results: sourceware.org; dkim=fail reason="signature verification failed" (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=dIOh7CQu X-Original-To: gdb-patches@sourceware.org Delivered-To: gdb-patches@sourceware.org Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.16]) by sourceware.org (Postfix) with ESMTPS id 93F264BA2E2B for ; Mon, 29 Dec 2025 15:16:27 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 93F264BA2E2B Authentication-Results: sourceware.org; dmarc=pass (p=none dis=none) header.from=intel.com Authentication-Results: sourceware.org; spf=pass smtp.mailfrom=intel.com ARC-Filter: OpenARC Filter v1.0.0 sourceware.org 93F264BA2E2B Authentication-Results: server2.sourceware.org; arc=none smtp.remote-ip=192.198.163.16 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1767021387; cv=none; b=L+nwXdccgVNlLfsVXI2Q6Zl1ISx/0qtW7bwoI40nFPDWufSnf8COxpQBLuGkBwBwNalVHuu8TVlFPDP58q87+C5P3ooOH7kJzQaLN9b/n8I6nRaujSZVyetWXOrSvnKvVF7GZ7kM4m/PXwAX66ZjYN3X9hxhmTW4zIL9CGkMtTk= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1767021387; c=relaxed/simple; bh=6CDd3E7pzgP4EqJ8haffUVi04tBEfJ5L6oRuL15LPQk=; h=DKIM-Signature:MIME-Version:From:To:Subject:Date:Message-Id: MIME-Version; b=hzBIE7yT6yT5KktVOUW059KDepuBtc2Ua/XOaglMlgsShz6NPtNsIRGYJ0ytML1xu0QKxmE21W88kH7MwIRfRlT6yuMA1t5xm/baNJm6pkkpGfZ7pVy2L9le4FOLrVaXcv9d5zE7M9YdjCfskaStvICd8vRsUCGb/Z2KHtLT3TA= ARC-Authentication-Results: i=1; server2.sourceware.org DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 93F264BA2E2B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1767021388; x=1798557388; h=from:to:subject:date:message-id:in-reply-to:references; bh=6CDd3E7pzgP4EqJ8haffUVi04tBEfJ5L6oRuL15LPQk=; b=dIOh7CQusR0IaVJPu1fQvd3uI103+8WmlNT2ax2VxyQfF/yLz/D00ee2 7cp/zlc55l/YxZ+6SIxb2kfNH/No/nA7V56Nlo1mtFk9o8Xzw2rClr+CV nEOGU8uROwFoTsCC+518j5Rddn9RFe9Mx56Qv/4ULPB+tWfbxd1JAOoeZ i4rDZtplYqiC99gJtNA+15HTo5eOstKVvAS0pJ1+A4MVjh1l4E+cM+rag vM8NRP70ez+xddlm8qiNJSxGvNuKbrOopD+rtTNEw/z382H0zVwKmqKgl KSFdfqsJvHv9VyNxgW0nnLAkARN6qvRYK6XW6YI7bpF6rPSf2t9yhYNdH g==; X-CSE-ConnectionGUID: 7MZZPS+eSyiIO+9mCgdphg== X-CSE-MsgGUID: ZqEENPuRSqmqCsP1yx5jCw== X-IronPort-AV: E=McAfee;i="6800,10657,11656"; a="56199810" X-IronPort-AV: E=Sophos;i="6.21,186,1763452800"; d="scan'208";a="56199810" MIME-Version: 1.0 Received: from orviesa006.jf.intel.com ([10.64.159.146]) by fmvoesa110.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Dec 2025 07:16:27 -0800 X-CSE-ConnectionGUID: FZuA24WvQbi1OQYJovYN+Q== X-CSE-MsgGUID: GbYIwZXrS1G6TjFjwJVKrg== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.21,186,1763452800"; d="scan'208";a="200066813" Received: from gkldtt-dev-004.igk.intel.com (HELO localhost) ([10.123.221.202]) by orviesa006-auth.jf.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 29 Dec 2025 07:16:25 -0800 From: Christina Schimpe To: gdb-patches@sourceware.org Subject: [PATCH 3/5] gdb: Enable correct template type resolution. Date: Mon, 29 Dec 2025 15:15:16 +0000 Message-Id: <20251229151518.475440-4-christina.schimpe@intel.com> X-Mailer: git-send-email 2.34.1 In-Reply-To: <20251229151518.475440-1-christina.schimpe@intel.com> References: <20251229151518.475440-1-christina.schimpe@intel.com> MIME-Version: 1.0 X-Spam-Status: No, score=-10.2 required=5.0 tests=BAYES_00, DKIMWL_WL_HIGH, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, DKIM_VALID_EF, GIT_PATCH_0, HTML_MESSAGE, KAM_SHORT, RCVD_IN_DNSWL_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED, RCVD_IN_VALIDITY_SAFE_BLOCKED, SPF_HELO_NONE, SPF_NONE, TXREP, URIBL_BLOCKED autolearn=ham autolearn_force=no version=3.4.6 X-Spam-Checker-Version: SpamAssassin 3.4.6 (2021-04-09) on sourceware.org X-BeenThere: gdb-patches@sourceware.org X-Mailman-Version: 2.1.30 Precedence: list List-Id: Gdb-patches mailing list List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Errors-To: gdb-patches-bounces~patchwork=sourceware.org@sourceware.org This patch addresses the GDB bug: https://sourceware.org/bugzilla/show_bug.cgi?id=20540 Curently GDB resolves a templated class such as ~~~ template struct A { A () : t_val (), i_val () { } T t_val; int i_val; }; int main () { A a; a.t_val = 1; a.i_val = 3; /* Break here. */ return 0; } ~~~ as follows: ~~~ 14 a.i_val = 3; /* Break here. */ (gdb) ptype a type = struct A [with T = int] { T t_val; T i_val; A(void); ~~~ The DWARF produced by clang $ clang --version Ubuntu clang version 14.0.0-1ubuntu1.1 and extracted with $ llvm-dwarfdump --version Ubuntu LLVM version 14.0.0 currently looks as follows: ~~~ [...] 0x0000000c: DW_TAG_compile_unit DW_AT_producer ("Ubuntu clang version 14.0.0-1ubuntu1.1") DW_AT_language (DW_LANG_C_plus_plus_14) [...] 0x0000002b: DW_TAG_structure_type DW_AT_calling_convention (DW_CC_pass_by_value) DW_AT_name ("A") DW_AT_byte_size (0x08) DW_AT_decl_file ("/tmp/sample.cc") DW_AT_decl_line (2) 0x00000031: DW_TAG_template_type_parameter DW_AT_type (0x00000054 "int") DW_AT_name ("T") 0x00000037: DW_TAG_member DW_AT_name ("t_val") DW_AT_type (0x00000054 "int") DW_AT_decl_file ("/tmp/sample.cc") DW_AT_decl_line (5) DW_AT_data_member_location (0x00) 0x00000040: DW_TAG_member DW_AT_name ("i_val") DW_AT_type (0x00000054 "int") DW_AT_decl_file ("/tmp/sample.cc") DW_AT_decl_line (6) DW_AT_data_member_location (0x04) 0x00000049: DW_TAG_subprogram DW_AT_name ("A") DW_AT_decl_file ("/tmp/sample.cc") DW_AT_decl_line (4) DW_AT_declaration (true) DW_AT_external (true) 0x0000004d: DW_TAG_formal_parameter DW_AT_type (0x00000058 "A *") DW_AT_artificial (true) 0x00000052: NULL 0x00000053: NULL [...] ~~~ The issue is that type references of DIEs that describe source entities referring to the formal template parameter reference the underlying type DIE and not the DW_TAG_template_type_parameter DIE. An example is the DIE describing t_val. For t_val there is no way how a debugger could distinguish this type from a normal member of type int (i_val in the example above). GDB's current template type resolution is based on a typedef_hash_table-based substitution of template type parameters in gdb/c-typeprint.c:c_print_type_1. Due to that map, GDB prints the template type for any member of type int or of the actual templated type. This patch enables correct template type resolution for such cases in case the debuggee supports the new DWARF defined by the DWARF 5 spec. The detailed format has already been described in the former commit "gdb: Support new DWARF for template type parameters.". In case GDB detects the old DWARF format, the template type resolution falls back to the typedef_hash_table-based substitution, so current template type tests will continue to work as before. The dwarf tests gdb.dwarf2/template-type-resolution.exp is extended to verify the correct template type resolution for this new DWARF. For better readability a new test gdb.cp/template-type-parameters.exp is added which focuses on the resolution of template type parameters only. It contains approriate xfails, which refer to the compiler ticket for the new DWARF format: https://gcc.gnu.org/bugzilla/show_bug.cgi?id=57006 --- gdb/c-typeprint.c | 10 +- gdb/cp-valprint.c | 6 + gdb/dwarf2/read.c | 25 +- gdb/gdbtypes.h | 8 + .../gdb.cp/template-type-parameters.cc | 95 +++++ .../gdb.cp/template-type-parameters.exp | 195 ++++++++++ .../gdb.dwarf2/template-type-resolution.cc | 9 +- .../gdb.dwarf2/template-type-resolution.exp | 339 +++++++++++++++++- gdb/typeprint.c | 9 +- gdb/typeprint.h | 9 +- 10 files changed, 684 insertions(+), 21 deletions(-) create mode 100644 gdb/testsuite/gdb.cp/template-type-parameters.cc create mode 100644 gdb/testsuite/gdb.cp/template-type-parameters.exp diff --git a/gdb/c-typeprint.c b/gdb/c-typeprint.c index 12b69ed6ebe..50dbb47b82c 100644 --- a/gdb/c-typeprint.c +++ b/gdb/c-typeprint.c @@ -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; diff --git a/gdb/cp-valprint.c b/gdb/cp-valprint.c index 252072b66dd..ffbf619e0ab 100644 --- a/gdb/cp-valprint.c +++ b/gdb/cp-valprint.c @@ -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) { diff --git a/gdb/dwarf2/read.c b/gdb/dwarf2/read.c index 1525e8e4d39..297e01a343b 100644 --- a/gdb/dwarf2/read.c +++ b/gdb/dwarf2/read.c @@ -11489,8 +11489,31 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu) struct field_info fi; std::vector 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 ()) diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 3ae5a1ef484..c9a67210cff 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -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] diff --git a/gdb/testsuite/gdb.cp/template-type-parameters.cc b/gdb/testsuite/gdb.cp/template-type-parameters.cc new file mode 100644 index 00000000000..9cb0a25062b --- /dev/null +++ b/gdb/testsuite/gdb.cp/template-type-parameters.cc @@ -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 . */ + +template +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 +struct B { + T t_val; + + template + struct C { + U u_val; + }; + + C c; +}; + +int +main () +{ + A a; + a.t_val = 1; + a.u_val = 2; + a.i_val = 3; + a.f_val = 4.0f; + + A b; + b.t_val = 1; + b.u_val = 2.0f; + b.i_val = 3; + b.f_val = 4.0f; + + A c; + c.t_val = 1.0; + c.u_val = 2; + c.i_val = 3; + c.f_val = 4.0f; + + A, A> d; + d.t_val = c; + d.u_val = b; + d.i_val = 3; + d.f_val = 4.0f; + + A, A> e; + e.t_val = b; + e.u_val = b; + e.i_val = 3; + e.f_val = 4.0f; + + B f; + f.t_val = 1; + + B> g; + g.t_val = f; + + return 0; /* Break here. */ +} diff --git a/gdb/testsuite/gdb.cp/template-type-parameters.exp b/gdb/testsuite/gdb.cp/template-type-parameters.exp new file mode 100644 index 00000000000..173a09f4b3c --- /dev/null +++ b/gdb/testsuite/gdb.cp/template-type-parameters.exp @@ -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 . +# +# 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 \\\[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 \\\[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 \\\[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 > \\\[with T = A, U = A\\\] {" \ + ".*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 > \\\[with T = A, U = A\\\] {" \ + ".*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 \\\[with T = int\\\] {" \ + ".*T t_val;.*" \ + ".*B::C c;.*" ] + +setup_xfail gcc/57006 "*-*-*" +gdb_test "ptype f.t_val" "type = T" + +gdb_test "ptype f.c" \ + [multi_line "type = struct B::C \\\[with U = int\\\] {" \ + ".*U u_val;.*" ] + +gdb_test "ptype g" \ + [multi_line "type = struct B > \\\[with T = B\\\] {" \ + ".*T t_val;.*" \ + ".*B::C c;.*" ] + +setup_xfail gcc/57006 "*-*-*" +gdb_test "ptype g.t_val" "type = T" + +gdb_test "ptype g.c" \ + [multi_line "type = struct B >::C > \\\[with U = B\\\] {" \ + ".*U u_val;.*" ] + diff --git a/gdb/testsuite/gdb.dwarf2/template-type-resolution.cc b/gdb/testsuite/gdb.dwarf2/template-type-resolution.cc index 56d9f490fe2..881617f8a63 100644 --- a/gdb/testsuite/gdb.dwarf2/template-type-resolution.cc +++ b/gdb/testsuite/gdb.dwarf2/template-type-resolution.cc @@ -15,10 +15,13 @@ You should have received a copy of the GNU General Public License along with this program. If not, see . */ -template +template 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 var = {0}; +A var = {0, 0, 0.0f, 0.0f}; +A, A> nestedvar + = {{0.0f, 0, 0.0f, 0.0f}, 0, {0.0f, 0, 0.0f, 0.0f}, 0.0f}; int main () diff --git a/gdb/testsuite/gdb.dwarf2/template-type-resolution.exp b/gdb/testsuite/gdb.dwarf2/template-type-resolution.exp index 4e9cc70d0fe..82788bdfda2 100644 --- a/gdb/testsuite/gdb.dwarf2/template-type-resolution.exp +++ b/gdb/testsuite/gdb.dwarf2/template-type-resolution.exp @@ -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" + gdb_test "ptype var" [multi_line \ - "type = struct A \\\[with T = int\\\] {" \ - " T me_t;.*" \ +"type = struct A \\\[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" + 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" + 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 \\\[with = int, second = float\\\] {" \ + " me;" \ + " second me2;" \ + "}"] + +gdb_test "ptype unnamed_var1.me" "type = " +gdb_test "ptype unnamed_var1.me2" "type = second" + +gdb_test "ptype unnamed_var2" [multi_line \ + "type = class template_var2 \\\[with = int, = float\\\] {" \ + " me;" \ + " me2;" \ + "}"] + +gdb_test "ptype unnamed_var2.me" "type = " +gdb_test "ptype unnamed_var2.me2" "type = " + +gdb_test "ptype unnamed_var3" [multi_line \ + "type = struct template_var3<0, int, 11, float> \\\[with = 0, = int, = 11, = float\\\] {" \ + " me;" \ + " me2;" \ + "}"] +gdb_test "ptype unnamed_var3.me" "type = " +gdb_test "ptype unnamed_var3.me2" "type = " diff --git a/gdb/typeprint.c b/gdb/typeprint.c index 4ba7a1aabfb..a30fe37edc8 100644 --- a/gdb/typeprint.c +++ b/gdb/typeprint.c @@ -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; diff --git a/gdb/typeprint.h b/gdb/typeprint.h index 21931e7a589..d0d6397070f 100644 --- a/gdb/typeprint.h +++ b/gdb/typeprint.h @@ -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 {