From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from simark.ca by simark.ca with LMTP id bd8VNLQCxmoYrAwAWB0awg (envelope-from ) for ; Wed, 07 Oct 2026 04:28:36 -0400 Authentication-Results: simark.ca; dkim=pass (2048-bit key; unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=Lb07GG5Z; dkim-atps=neutral Received: by simark.ca (Postfix, from userid 112) id B99631E04E; Wed, 07 Oct 2026 04:28:36 -0400 (EDT) X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-25) on simark.ca X-Spam-Level: X-Spam-Status: No, score=-3.4 required=5.0 tests=ARC_SIGNED,ARC_VALID,BAYES_00, DKIMWL_WL_HIGH,DKIM_SIGNED,DKIM_VALID,DKIM_VALID_AU,MAILING_LIST_MULTI, RCVD_IN_DNSWL_MED,RCVD_IN_VALIDITY_CERTIFIED_BLOCKED, RCVD_IN_VALIDITY_RPBL_BLOCKED,RCVD_IN_VALIDITY_SAFE_BLOCKED autolearn=ham autolearn_force=no version=4.0.1 Received: from vm01.sourceware.org (vm01.sourceware.org [38.145.34.32]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange x25519 server-signature ECDSA (prime256v1) server-digest SHA256) (No client certificate requested) by simark.ca (Postfix) with ESMTPS id 21B131E04E for ; Wed, 07 Oct 2026 04:28:35 -0400 (EDT) Received: from vm01.sourceware.org (localhost [IPv6:::1]) by sourceware.org (Postfix) with ESMTP id 8664A4BA2E14 for ; Wed, 7 Oct 2026 08:28:28 +0000 (GMT) DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 8664A4BA2E14 Authentication-Results: sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=Lb07GG5Z Received: from mgamail.intel.com (mgamail.intel.com [192.198.163.18]) by sourceware.org (Postfix) with ESMTPS id 83DB04BA540B for ; Wed, 7 Oct 2026 08:28:00 +0000 (GMT) DMARC-Filter: OpenDMARC Filter v1.4.2 sourceware.org 83DB04BA540B 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 83DB04BA540B Authentication-Results: sourceware.org; arc=none smtp.remote-ip=192.198.163.18 ARC-Seal: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1791361680; cv=none; b=Ra5dXsIYKMYvBZinD1LE/tw7tkeveQ8+veTveBHFatKvpyuk2qiINYET8NL1fBiiMzQ+XxFtns5UzO+RsbUy+LyJe7UvdI5bUrHTOHRuxp2adIOGo86n1CkNQGXCF4i0LKcPenmEghC4dwu4OEkzxxISWynPymzYv3kiP6sfHTM= ARC-Message-Signature: i=1; a=rsa-sha256; d=sourceware.org; s=key; t=1791361680; c=relaxed/simple; bh=oSYZvEqVQG8xGlcg7fzQeCjghccQyYeGBV0ZOVJNi6s=; h=DKIM-Signature:From:To:Subject:Date:Message-ID:MIME-Version; b=qiVQkBIj/J24rxulLIEKyZH2AONEqDs0VE9yooF0E6G44hocjDzEZOYbIxx56dwWM+mnVE9Wc61NSAVdF95UW6W5Nz1b5YahksUYRWJBwruHtnOv0dhIJzJv85VpnT8eSNHtTXGHJDBVaD5fSpDEe208kGmkEFukHIfSY8XT1So= ARC-Authentication-Results: i=1; sourceware.org; dkim=pass (2048-bit key, unprotected) header.d=intel.com header.i=@intel.com header.a=rsa-sha256 header.s=Intel header.b=Lb07GG5Z DKIM-Filter: OpenDKIM Filter v2.11.0 sourceware.org 83DB04BA540B DKIM-Signature: v=1; a=rsa-sha256; c=relaxed/simple; d=intel.com; i=@intel.com; q=dns/txt; s=Intel; t=1791361680; x=1822897680; h=from:to:subject:date:message-id:mime-version: content-transfer-encoding; bh=oSYZvEqVQG8xGlcg7fzQeCjghccQyYeGBV0ZOVJNi6s=; b=Lb07GG5ZGWHqvqbJypEqI+06LDWeKKJxN3g0Jtbjx1gioxDOl2f2cOwY sHQpzBVymvJ/5NCWNTsFBI6mOjWtxkU7xLZWAZxbyLuHmaY3569RnTPd+ PkNYfLSjMoPf26nSIrDWHs0szrhqb87WzBiOZPElz1uA/0nEcodGIOWVB 3P7duyGyVwlDzuX4wU3nKOO6q/7gihnxWv74DEKbGHebSiEthn06lhY3+ kqSpy/Upr9JGYmY9UtuqkaAuuNvmi4GFC6Eg001LoKr134YJfZxtNlZqK 76U1jgqt9lVjMgkWDgApuRUS4rxts5zL+fm1xNqRPiwD/2woMY55V0SrU w==; X-CSE-ConnectionGUID: zqtfBRN0Rkau/nQJrto2BQ== X-CSE-MsgGUID: jRE7e3O9Scak8NujaGuvdQ== X-IronPort-AV: E=McAfee;i="6800,10657,11927"; a="124829" X-IronPort-AV: E=Sophos;i="6.27,144,1787036400"; d="scan'208";a="124829" Received: from fmviesa013.fm.intel.com ([10.60.135.153]) by fmvoesa112.fm.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Oct 2026 01:27:59 -0700 X-CSE-ConnectionGUID: +d/zZrDXSGOjJ9zs83ppXQ== X-CSE-MsgGUID: 6SGTJ+7aRs2/3edrqLeIeA== X-ExtLoop1: 1 X-IronPort-AV: E=Sophos;i="6.27,144,1787036400"; d="scan'208";a="1409058" Received: from dut1048pvc.igk.intel.com (HELO localhost) ([10.211.177.228]) by smtpauth.intel.com with ESMTP/TLS/ECDHE-RSA-AES256-GCM-SHA384; 07 Oct 2026 01:27:58 -0700 From: Stephan Rohr To: gdb-patches@sourceware.org Subject: [PATCH] gdb: fix path expression for anonymous union members Date: Wed, 7 Oct 2026 08:27:31 +0000 Message-ID: <20261007082731.728382-1-stephan.rohr@intel.com> X-Mailer: git-send-email 2.43.0 MIME-Version: 1.0 Content-Type: text/plain; charset="us-ascii" Content-Transfer-Encoding: 7bit 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~public-inbox=simark.ca@sourceware.org From: "Bobko, Sergey" Consider the following structure: struct SBase {}; class S : SBase { private: int a; public: int b; union { int c; }; }; S s; When we create a variable object for variable "s", path expression for the field "s.c" is not computed correctly: interpret mi "-var-info-path-expression var1.public.1_anonymous.public.c" ^done,path_expr="(().c)" To compute a path expression for a struct member, GDB looks up to the parent var object. If the parent has a valid expression, GDB uses it to build the expression for the child. Otherwise, it goes one level up to check the parent->parent, until the valid parent expression is found. The reason for "(().c)" is that the check c_is_path_expr_parent incorrectly returns "true" for the anonymous union parent. Then the path expression of the anonymous union, which is "", is used to compute the result. Inside the check, it takes the type field name by the index of the var-object. The index of the var object is the child index within its parent var-object. However, there are artificial layers for access-levels, e.g., public, private or protected. So the indexing of the child var object might be done within an artificial layer, while the type fields are indexed as a flat list of all fields, including the base types. For the struct above, the var-object tree is as follows: var1 -> index -1 var1.SBase -> index 0 var1.public -> index 1 var1.public.b -> index 0 var1.public.1_anonymous -> index 1 var1.public.1_anonymous.public -> index 0 var1.public.1_anonymous.public.c -> index 0 var1.private -> index 2 var1.private.a -> index 0 Note, that the base type member is the direct child of var1, and the other fields have an artificial access parent. The fields of type S are indexed as: SBase -> 0 a -> 1 b -> 2 "" -> 3 where "" is the anonymous union. Extract the required logic from cplus_describe_child and use it to get the correct index of the field within the parent type. With this change the path expression is computed correctly: interpret mi "-var-info-path-expression var1.public.1_anonymous.public.c" ^done,path_expr="((s).c)" I modified the related test to include both base type and access layers. However, to correctly parse the base types within the MI var tree I had to introduce a heuristic that if the child's type is equal to child's name then it is a base type, and the path expression is different in this case. --- gdb/c-varobj.c | 89 +++++++++++++++++++----------- gdb/testsuite/gdb.mi/mi-var-cp.cc | 18 +++++- gdb/testsuite/gdb.mi/mi-var-cp.exp | 17 ++++++ gdb/testsuite/lib/mi-support.exp | 4 ++ 4 files changed, 96 insertions(+), 32 deletions(-) diff --git a/gdb/c-varobj.c b/gdb/c-varobj.c index 5312eccdaca..dc88ce6e29a 100644 --- a/gdb/c-varobj.c +++ b/gdb/c-varobj.c @@ -22,6 +22,10 @@ static void cplus_class_num_children (struct type *type, int children[3]); +static int +type_field_num_from_child_index (int index, const varobj *parent, + type *parent_type); + /* The names of varobjs representing anonymous structs or unions. */ #define ANONYMOUS_STRUCT_NAME _("") #define ANONYMOUS_UNION_NAME _("") @@ -163,8 +167,12 @@ c_is_path_expr_parent (const struct varobj *var) { const char *field_name; - gdb_assert (var->index < parent_type->num_fields ()); - field_name = parent_type->field (var->index).name (); + int type_index = type_field_num_from_child_index (var->index, + var->parent, + parent_type); + + gdb_assert (type_index < parent_type->num_fields ()); + field_name = parent_type->field (type_index).name (); return !(field_name == NULL || *field_name == '\0'); } } @@ -669,6 +677,51 @@ cplus_name_of_variable (const struct varobj *parent) return c_name_of_variable (parent); } +/* Return the type-field index within the PARENT_TYPE for the child with + the var-index INDEX in the PARENT var object. */ + +static int +type_field_num_from_child_index (int index, const varobj *parent, + type *parent_type) +{ + gdb_assert (parent_type->code () == TYPE_CODE_STRUCT + || parent_type->code () == TYPE_CODE_UNION); + + /* If the parent is not an artificial layer, just return the index. */ + if (!CPLUS_FAKE_CHILD (parent)) + return index; + + /* The fields of the class type are ordered as they + appear in the class. We are given an index for a + particular access control type ("public","protected", + or "private"). We must skip over fields that don't + have the access control we are looking for to properly + find the indexed field. */ + int type_index = TYPE_N_BASECLASSES (parent_type); + int vptr_fieldno; + type *basetype = nullptr; + enum accessibility acc = accessibility::PUBLIC; + + if (parent->name == "private") + acc = accessibility::PRIVATE; + else if (parent->name == "protected") + acc = accessibility::PROTECTED; + + vptr_fieldno = get_vptr_fieldno (parent_type, &basetype); + while (index >= 0) + { + if ((parent_type == basetype && type_index == vptr_fieldno) + || parent_type->field (type_index).is_artificial ()) + ; /* ignore vptr */ + else if (parent_type->field (type_index).accessibility () == acc) + --index; + ++type_index; + } + --type_index; + + return type_index; +} + static void cplus_describe_child (const struct varobj *parent, int index, std::string *cname, struct value **cvalue, struct type **ctype, @@ -710,38 +763,12 @@ cplus_describe_child (const struct varobj *parent, int index, if (CPLUS_FAKE_CHILD (parent)) { - /* The fields of the class type are ordered as they - appear in the class. We are given an index for a - particular access control type ("public","protected", - or "private"). We must skip over fields that don't - have the access control we are looking for to properly - find the indexed field. */ - int type_index = TYPE_N_BASECLASSES (type); - enum accessibility acc = accessibility::PUBLIC; - int vptr_fieldno; - struct type *basetype = NULL; - const char *field_name; - - vptr_fieldno = get_vptr_fieldno (type, &basetype); - if (parent->name == "private") - acc = accessibility::PRIVATE; - else if (parent->name == "protected") - acc = accessibility::PROTECTED; - - while (index >= 0) - { - if ((type == basetype && type_index == vptr_fieldno) - || type->field (type_index).is_artificial ()) - ; /* ignore vptr */ - else if (type->field (type_index).accessibility () == acc) - --index; - ++type_index; - } - --type_index; + int type_index = type_field_num_from_child_index (index, parent, + type); /* If the type is anonymous and the field has no name, set an appropriate name. */ - field_name = type->field (type_index).name (); + const char *field_name = type->field (type_index).name (); if (field_name == NULL || *field_name == '\0') { if (cname) diff --git a/gdb/testsuite/gdb.mi/mi-var-cp.cc b/gdb/testsuite/gdb.mi/mi-var-cp.cc index 624ddce325c..39b1294b4c1 100644 --- a/gdb/testsuite/gdb.mi/mi-var-cp.cc +++ b/gdb/testsuite/gdb.mi/mi-var-cp.cc @@ -205,7 +205,8 @@ int path_expression () /*: END: path_expression :*/ } -class Anonymous +class AnonymousBase {}; +class Anonymous : AnonymousBase { public: struct { /* index: 0 */ @@ -229,8 +230,23 @@ public: int i; char j; }; + struct { + int k; + private: + union { + int l; + char m; + }; + } with_name; }; }; + + /* The vptr is an artificial private field and must not be listed + among the private children. */ + virtual ~Anonymous () {} + +private: + int priv = 9; }; /* Test anonymous structs and unions. */ diff --git a/gdb/testsuite/gdb.mi/mi-var-cp.exp b/gdb/testsuite/gdb.mi/mi-var-cp.exp index fb850ad51db..ce2fd368000 100644 --- a/gdb/testsuite/gdb.mi/mi-var-cp.exp +++ b/gdb/testsuite/gdb.mi/mi-var-cp.exp @@ -56,6 +56,7 @@ mi_execute_to "exec-continue" "breakpoint-hit" \ set tree { Anonymous a { + AnonymousBase AnonymousBase {} {} public { anonymous struct { {} public { @@ -90,11 +91,27 @@ set tree { char j {} } } + "struct {...}" with_name { + {} public { + int k {} + } + {} private { + anonymous union { + {} public { + int l {} + char m {} + } + } + } + } } } } } } + {} private { + int priv {} + } } } diff --git a/gdb/testsuite/lib/mi-support.exp b/gdb/testsuite/lib/mi-support.exp index cd7e0a61189..465cf3fd69c 100644 --- a/gdb/testsuite/lib/mi-support.exp +++ b/gdb/testsuite/lib/mi-support.exp @@ -2401,6 +2401,10 @@ namespace eval ::varobj_tree { set is_compound 0 } + if {$type eq $name} { + # This is the base type. + return "((class $type) $path_parent(path_expr))" + } if {[string index $parent(type) end] == "\]"} { # Parent is an array. return "($path_parent(path_expr))\[$name\]" -- 2.43.0 ________________________________________ Intel Deutschland GmbH Registered Address: Dornacher Strasse 1, 85622 Feldkirchen, Germany Tel: +49 (89) 99143-0 www.intel.de Managing Directors: Candice Moore, Jeffrey Schneiderman, Ramachandran Sitaraman Chairperson of the Supervisory Board: Sonja Pierer Registered Seat: Munich Commercial Register B: Amtsgericht Munich HRB 186928 This e-mail and any attachments may contain confidential material for the sole use of the intended recipient(s). Any review or distribution by others is strictly prohibited. If you are not the intended recipient, please contact the sender and delete all copies.