From patchwork Tue Feb 20 19:06:11 2018 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Tom Tromey X-Patchwork-Id: 25980 Received: (qmail 52258 invoked by alias); 20 Feb 2018 19:06:19 -0000 Mailing-List: contact gdb-patches-help@sourceware.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Subscribe: List-Archive: List-Post: List-Help: , Sender: gdb-patches-owner@sourceware.org Delivered-To: mailing list gdb-patches@sourceware.org Received: (qmail 52214 invoked by uid 89); 20 Feb 2018 19:06:18 -0000 Authentication-Results: sourceware.org; auth=none X-Virus-Found: No X-Spam-SWARE-Status: No, score=-25.7 required=5.0 tests=AWL, BAYES_00, GIT_PATCH_0, GIT_PATCH_1, GIT_PATCH_2, GIT_PATCH_3, RCVD_IN_DNSWL_NONE, SPF_HELO_PASS autolearn=ham version=3.3.2 spammy=sk:discrim X-HELO: gateway31.websitewelcome.com Received: from gateway31.websitewelcome.com (HELO gateway31.websitewelcome.com) (192.185.143.5) by sourceware.org (qpsmtpd/0.93/v0.84-503-g423c35a) with ESMTP; Tue, 20 Feb 2018 19:06:16 +0000 Received: from cm16.websitewelcome.com (cm16.websitewelcome.com [100.42.49.19]) by gateway31.websitewelcome.com (Postfix) with ESMTP id 927402D608A for ; Tue, 20 Feb 2018 13:06:15 -0600 (CST) Received: from box5379.bluehost.com ([162.241.216.53]) by cmsmtp with SMTP id oDF1eBcFtODN4oDF1e3QhB; Tue, 20 Feb 2018 13:06:15 -0600 Received: from 174-29-60-18.hlrn.qwest.net ([174.29.60.18]:50132 helo=pokyo.Home) by box5379.bluehost.com with esmtpsa (TLSv1.2:ECDHE-RSA-AES256-GCM-SHA384:256) (Exim 4.89) (envelope-from ) id 1eoDF1-004Bux-Bh; Tue, 20 Feb 2018 13:06:15 -0600 From: Tom Tromey To: gdb-patches@sourceware.org Cc: Tom Tromey Subject: [RFA 1/3] Initial support for variant parts Date: Tue, 20 Feb 2018 12:06:11 -0700 Message-Id: <20180220190613.24148-2-tom@tromey.com> In-Reply-To: <20180220190613.24148-1-tom@tromey.com> References: <20180220190613.24148-1-tom@tromey.com> X-BWhitelist: no X-Source-L: No X-Exim-ID: 1eoDF1-004Bux-Bh X-Source-Sender: 174-29-60-18.hlrn.qwest.net (pokyo.Home) [174.29.60.18]:50132 X-Source-Auth: tom+tromey.com X-Email-Count: 2 X-Source-Cap: ZWx5bnJvYmk7ZWx5bnJvYmk7Ym94NTM3OS5ibHVlaG9zdC5jb20= X-Local-Domain: yes This adds some initial support for variant parts to gdbtypes.h. A variant part is represented as a union. The union has a flag indicating that it has a discriminant, and information about the discriminant is attached using the dynamic property system. 2018-02-19 Tom Tromey * value.h (value_union_variant): Declare. * valops.c (value_union_variant): New function. * gdbtypes.h (TYPE_FLAG_DISCRIMINATED_UNION): New macro. (struct discriminant_info): New. (enum dynamic_prop_node_kind) : New enumerator. (struct main_type) : New field. --- gdb/ChangeLog | 10 ++++++++++ gdb/gdbtypes.h | 51 +++++++++++++++++++++++++++++++++++++++++++++++++++ gdb/valops.c | 41 +++++++++++++++++++++++++++++++++++++++++ gdb/value.h | 8 ++++++++ 4 files changed, 110 insertions(+) diff --git a/gdb/ChangeLog b/gdb/ChangeLog index eac1572280..28990a4ec6 100644 --- a/gdb/ChangeLog +++ b/gdb/ChangeLog @@ -1,3 +1,13 @@ +2018-02-19 Tom Tromey + + * value.h (value_union_variant): Declare. + * valops.c (value_union_variant): New function. + * gdbtypes.h (TYPE_FLAG_DISCRIMINATED_UNION): New macro. + (struct discriminant_info): New. + (enum dynamic_prop_node_kind) : New + enumerator. + (struct main_type) : New field. + 2018-02-20 Markus Metzger * gnulib/update-gnulib.sh (IMPORTED_GNULIB_MODULES): Add mkstemp. diff --git a/gdb/gdbtypes.h b/gdb/gdbtypes.h index 613257c47d..62cd8b6f82 100644 --- a/gdb/gdbtypes.h +++ b/gdb/gdbtypes.h @@ -304,6 +304,14 @@ DEF_ENUM_FLAGS_TYPE (enum type_instance_flag_value, type_instance_flags); #define TYPE_FLAG_ENUM(t) (TYPE_MAIN_TYPE (t)->flag_flag_enum) +/* * True if this type is a discriminated union type. Only valid for + TYPE_CODE_UNION. A discriminated union stores a reference to the + discriminant field along with the discriminator values in a dynamic + property. */ + +#define TYPE_FLAG_DISCRIMINATED_UNION(t) \ + (TYPE_MAIN_TYPE (t)->flag_discriminated_union) + /* * Constant type. If this is set, the corresponding type has a const modifier. */ @@ -373,6 +381,39 @@ DEF_ENUM_FLAGS_TYPE (enum type_instance_flag_value, type_instance_flags); #define TYPE_ADDRESS_CLASS_ALL(t) (TYPE_INSTANCE_FLAGS(t) \ & TYPE_INSTANCE_FLAG_ADDRESS_CLASS_ALL) +/* * Information needed for a discriminated union. A discriminated + union is handled somewhat differently from an ordinary union. + + One field is designated as the discriminant. Only one other field + is active at a time; which one depends on the value of the + discriminant and the data in this structure. + + Additionally, it is possible to have a univariant discriminated + union. In this case, the union has just a single field, which is + assumed to be the only active variant -- in this case no + discriminant is provided. */ + +struct discriminant_info +{ + /* * The index of the discriminant field. If -1, then this union + must have just a single field. */ + + int discriminant_index; + + /* * The index of the default branch of the union. If -1, then + there is no default branch. */ + + int default_index; + + /* * The discriminant values corresponding to each branch. This has + a number of entries equal to the number of fields in this union. + If discriminant_index is not -1, then that entry in this array is + not used. If default_index is not -1, then that entry in this + array is not used. */ + + ULONGEST discriminants[1]; +}; + enum dynamic_prop_kind { PROP_UNDEFINED, /* Not defined. */ @@ -431,6 +472,9 @@ enum dynamic_prop_node_kind /* A property providing an array's byte stride. */ DYN_PROP_BYTE_STRIDE, + + /* A property holding information about a discriminated union. */ + DYN_PROP_DISCRIMINATED, }; /* * List for dynamic type attributes. */ @@ -650,6 +694,13 @@ struct main_type unsigned int flag_flag_enum : 1; + /* * True if this type is a discriminated union type. Only valid + for TYPE_CODE_UNION. A discriminated union stores a reference to + the discriminant field along with the discriminator values in a + dynamic property. */ + + unsigned int flag_discriminated_union : 1; + /* * A discriminant telling us which field of the type_specific union is being used for this type, if any. */ diff --git a/gdb/valops.c b/gdb/valops.c index e038c04fd1..2d31762b8a 100644 --- a/gdb/valops.c +++ b/gdb/valops.c @@ -2257,6 +2257,47 @@ value_struct_elt_bitpos (struct value **argp, int bitpos, struct type *ftype, return NULL; } +/* See value.h. */ + +int +value_union_variant (struct type *union_type, const gdb_byte *contents) +{ + gdb_assert (TYPE_CODE (union_type) == TYPE_CODE_UNION + && TYPE_FLAG_DISCRIMINATED_UNION (union_type)); + + struct dynamic_prop *discriminant_prop + = get_dyn_prop (DYN_PROP_DISCRIMINATED, union_type); + gdb_assert (discriminant_prop != nullptr); + + struct discriminant_info *info + = (struct discriminant_info *) discriminant_prop->data.baton; + gdb_assert (info != nullptr); + + /* If this is a univariant union, just return the sole field. */ + if (TYPE_NFIELDS (union_type) == 1) + return 0; + /* This should only happen for univariants, which we already dealt + with. */ + gdb_assert (info->discriminant_index != -1); + + /* Compute the discriminant. */ + ULONGEST discriminant = unpack_field_as_long (union_type, contents, + info->discriminant_index); + + for (int i = 0; i < TYPE_NFIELDS (union_type); ++i) + { + if (i != info->default_index + && i != info->discriminant_index + && discriminant == info->discriminants[i]) + return i; + } + + if (info->default_index == -1) + error (_("Could not find variant corresponding to discriminant %s"), + pulongest (discriminant)); + return info->default_index; +} + /* Search through the methods of an object (and its bases) to find a specified method. Return the pointer to the fn_field list FN_LIST of overloaded instances defined in the source language. If available diff --git a/gdb/value.h b/gdb/value.h index e0ea22d4e5..4386be4135 100644 --- a/gdb/value.h +++ b/gdb/value.h @@ -1169,4 +1169,12 @@ extern struct type *result_type_of_xmethod (struct value *method, extern struct value *call_xmethod (struct value *method, int argc, struct value **argv); +/* Given a discriminated union type and some corresponding value + contents, this will return the field index of the currently active + variant. This will throw an exception if no active variant can be + found. */ + +extern int value_union_variant (struct type *union_type, + const gdb_byte *contents); + #endif /* !defined (VALUE_H) */