Record nested types
GDB currently does not track types defined in classes. Consider: class A { public: class B { public: class C { }; }; }; (gdb) ptype A type = class A { <no data fields> } This patch changes this behavior so that GDB records these nested types and displays them to the user when he has set the (new) "print type" option "nested-type-limit." Example: (gdb) set print type nested-type-limit 1 (gdb) ptype A type = class A { <no data fields> class A::B { <no data fields> }; } (gdb) set print type nested-type-limit 2 type = class A { <no data fields> class A::B { <no data fields> class A::B::C { <no data fields> }; }; } By default, the code maintains the status quo, that is, it will not print any nested type definitions at all. Testing is carried out via cp_ptype_class which required quite a bit of modification to permit recursive calling (for the nested types). This was most easily facilitated by turning the ptype command output into a queue. Upshot: the test suite now has stack and queue data structures that may be used by test writers. gdb/ChangeLog * NEWS (New commands): Mention set/show print type nested-type-limit. * c-typeprint.c (c_type_print_base): Print out nested types. * dwarf2read.c (struct typedef_field_list): Rename to ... (struct decl_field_list): ... this. Change all uses. (struct field_info) <nested_types_list, nested_types_list_count>: New fields. (add_partial_symbol): Look for nested type definitions in C++, too. (dwarf2_add_typedef): Rename to ... (dwarf2_add_type_defn): ... this. (type_can_define_types): New function. Update assertion to use type_can_define_types. Permit NULL for a field's name. (process_structure_scope): Handle child DIEs of types that can define types. Copy the list of nested types into the type struct. * gdbtypes.h (struct typedef_field): Rename to ... (struct decl_field): ... this. Change all uses. [is_protected, is_private]: New fields. (struct cplus_struct_type) <nested_types, nested_types_count>: New fields. (TYPE_NESTED_TYPES_ARRAY, TYPE_NESTED_TYPES_FIELD) (TYPE_NESTED_TYPES_FIELD_NAME, TYPE_NESTED_TYPES_FIELD_TYPE) (TYPE_NESTED_TYPES_COUNT, TYPE_NESTED_TYPES_FIELD_PROTECTED) (TYPE_NESTED_TYPES_FIELD_PRIVATE): New macros. * typeprint.c (type_print_raw_options, default_ptype_flags): Add default value for print_nested_type_limit. (print_nested_type_limit): New static variable. (set_print_type_nested_types, show_print_type_nested_types): New functions. (_initialize_typeprint): Register new commands for set/show `print-nested-type-limit'. * typeprint.h (struct type_print_options) [print_nested_type_limit]: New field. gdb/testsuite/ChangeLog * gdb.cp/nested-types.cc: New file. * gdb.cp/nested-types.exp: New file. * lib/cp-support.exp: Load data-structures.exp library. (debug_cp_test_ptype_class): New global. (cp_ptype_class_verbose, next_line): New procedures. (cp_test_ptype_class): Add and document new parameter `recursive_qid'. Add and document new return value. Switch the list of lines to a queue. Add support for new `type' key for nested type definitions. Add debugging/troubleshooting messages. * lib/data-structures.exp: New file. gdb/doc/ChangeLog * gdb.texinfo (Symbols): Document "set print type nested-type-limit" and "show print type nested-type-limit".
This commit is contained in:
parent
ec72db3ef4
commit
883fd55ab1
|
@ -1,3 +1,39 @@
|
|||
2017-12-07 Keith Seitz <keiths@redhat.com>
|
||||
|
||||
* NEWS (New commands): Mention set/show print type nested-type-limit.
|
||||
* c-typeprint.c (c_type_print_base): Print out nested types.
|
||||
* dwarf2read.c (struct typedef_field_list): Rename to ...
|
||||
(struct decl_field_list): ... this. Change all uses.
|
||||
(struct field_info) <nested_types_list, nested_types_list_count>:
|
||||
New fields.
|
||||
(add_partial_symbol): Look for nested type definitions in C++, too.
|
||||
(dwarf2_add_typedef): Rename to ...
|
||||
(dwarf2_add_type_defn): ... this.
|
||||
(type_can_define_types): New function.
|
||||
Update assertion to use type_can_define_types.
|
||||
Permit NULL for a field's name.
|
||||
(process_structure_scope): Handle child DIEs of types that can
|
||||
define types.
|
||||
Copy the list of nested types into the type struct.
|
||||
* gdbtypes.h (struct typedef_field): Rename to ...
|
||||
(struct decl_field): ... this. Change all uses.
|
||||
[is_protected, is_private]: New fields.
|
||||
(struct cplus_struct_type) <nested_types, nested_types_count>: New
|
||||
fields.
|
||||
(TYPE_NESTED_TYPES_ARRAY, TYPE_NESTED_TYPES_FIELD)
|
||||
(TYPE_NESTED_TYPES_FIELD_NAME, TYPE_NESTED_TYPES_FIELD_TYPE)
|
||||
(TYPE_NESTED_TYPES_COUNT, TYPE_NESTED_TYPES_FIELD_PROTECTED)
|
||||
(TYPE_NESTED_TYPES_FIELD_PRIVATE): New macros.
|
||||
* typeprint.c (type_print_raw_options, default_ptype_flags): Add
|
||||
default value for print_nested_type_limit.
|
||||
(print_nested_type_limit): New static variable.
|
||||
(set_print_type_nested_types, show_print_type_nested_types): New
|
||||
functions.
|
||||
(_initialize_typeprint): Register new commands for set/show
|
||||
`print-nested-type-limit'.
|
||||
* typeprint.h (struct type_print_options) [print_nested_type_limit]:
|
||||
New field.
|
||||
|
||||
2017-12-07 Tom Tromey <tom@tromey.com>
|
||||
|
||||
PR breakpoints/22511:
|
||||
|
|
4
gdb/NEWS
4
gdb/NEWS
|
@ -205,6 +205,10 @@ maint info selftests
|
|||
starti
|
||||
Start the debugged program stopping at the first instruction.
|
||||
|
||||
set|show print type nested-type-limit
|
||||
Set and show the limit of nesting level for nested types that the
|
||||
type printer will show.
|
||||
|
||||
* TUI Single-Key mode now supports two new shortcut keys: `i' for stepi and
|
||||
`o' for nexti.
|
||||
|
||||
|
|
|
@ -1327,11 +1327,31 @@ c_type_print_base (struct type *type, struct ui_file *stream,
|
|||
}
|
||||
}
|
||||
|
||||
/* Print out nested types. */
|
||||
if (TYPE_NESTED_TYPES_COUNT (type) != 0
|
||||
&& semi_local_flags.print_nested_type_limit != 0)
|
||||
{
|
||||
if (semi_local_flags.print_nested_type_limit > 0)
|
||||
--semi_local_flags.print_nested_type_limit;
|
||||
|
||||
if (TYPE_NFIELDS (type) != 0 || TYPE_NFN_FIELDS (type) != 0)
|
||||
fprintf_filtered (stream, "\n");
|
||||
|
||||
for (i = 0; i < TYPE_NESTED_TYPES_COUNT (type); ++i)
|
||||
{
|
||||
print_spaces_filtered (level + 4, stream);
|
||||
c_print_type (TYPE_NESTED_TYPES_FIELD_TYPE (type, i),
|
||||
"", stream, show, level + 4, &semi_local_flags);
|
||||
fprintf_filtered (stream, ";\n");
|
||||
}
|
||||
}
|
||||
|
||||
/* Print typedefs defined in this class. */
|
||||
|
||||
if (TYPE_TYPEDEF_FIELD_COUNT (type) != 0 && flags->print_typedefs)
|
||||
{
|
||||
if (TYPE_NFIELDS (type) != 0 || TYPE_NFN_FIELDS (type) != 0)
|
||||
if (TYPE_NFIELDS (type) != 0 || TYPE_NFN_FIELDS (type) != 0
|
||||
|| TYPE_NESTED_TYPES_COUNT (type) != 0)
|
||||
fprintf_filtered (stream, "\n");
|
||||
|
||||
for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (type); i++)
|
||||
|
|
|
@ -1,3 +1,8 @@
|
|||
2017-12-07 Keith Seitz <keiths@redhat.com>
|
||||
|
||||
* gdb.texinfo (Symbols): Document "set print type nested-type-limit"
|
||||
and "show print type nested-type-limit".
|
||||
|
||||
2017-12-07 Phil Muldoon <pmuldoon@redhat.com>
|
||||
|
||||
* python.texi (Breakpoints In Python): Add text relating
|
||||
|
|
|
@ -17071,6 +17071,19 @@ cause @value{GDBN} to omit the methods.
|
|||
This command shows the current setting of method display when printing
|
||||
classes.
|
||||
|
||||
@kindex set print type nested-type-limit
|
||||
@item set print type nested-type-limit @var{limit}
|
||||
@itemx set print type nested-type-limit unlimited
|
||||
Set the limit of displayed nested types that the type printer will
|
||||
show. A @var{limit} of @code{unlimited} or @code{-1} will show all
|
||||
nested definitions. By default, the type printer will not show any nested
|
||||
types defined in classes.
|
||||
|
||||
@kindex show print type nested-type-limit
|
||||
@item show print type nested-type-limit
|
||||
This command shows the current display limit of nested types when
|
||||
printing classes.
|
||||
|
||||
@kindex set print type typedefs
|
||||
@item set print type typedefs
|
||||
@itemx set print type typedefs on
|
||||
|
|
|
@ -1529,10 +1529,10 @@ struct fnfieldlist
|
|||
struct nextfnfield *head;
|
||||
};
|
||||
|
||||
struct typedef_field_list
|
||||
struct decl_field_list
|
||||
{
|
||||
struct typedef_field field;
|
||||
struct typedef_field_list *next;
|
||||
struct decl_field field;
|
||||
struct decl_field_list *next;
|
||||
};
|
||||
|
||||
/* The routines that read and process dies for a C struct or C++ class
|
||||
|
@ -1562,8 +1562,13 @@ struct field_info
|
|||
|
||||
/* typedefs defined inside this class. TYPEDEF_FIELD_LIST contains head of
|
||||
a NULL terminated list of TYPEDEF_FIELD_LIST_COUNT elements. */
|
||||
struct typedef_field_list *typedef_field_list;
|
||||
struct decl_field_list *typedef_field_list;
|
||||
unsigned typedef_field_list_count;
|
||||
|
||||
/* Nested types defined by this class and the number of elements in this
|
||||
list. */
|
||||
struct decl_field_list *nested_types_list;
|
||||
unsigned nested_types_list_count;
|
||||
};
|
||||
|
||||
/* One item on the queue of compilation units to read in full symbols
|
||||
|
@ -13988,28 +13993,44 @@ dwarf2_add_field (struct field_info *fip, struct die_info *die,
|
|||
}
|
||||
}
|
||||
|
||||
/* Add a typedef defined in the scope of the FIP's class. */
|
||||
/* Can the type given by DIE define another type? */
|
||||
|
||||
static bool
|
||||
type_can_define_types (const struct die_info *die)
|
||||
{
|
||||
switch (die->tag)
|
||||
{
|
||||
case DW_TAG_typedef:
|
||||
case DW_TAG_class_type:
|
||||
case DW_TAG_structure_type:
|
||||
case DW_TAG_union_type:
|
||||
case DW_TAG_enumeration_type:
|
||||
return true;
|
||||
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
/* Add a type definition defined in the scope of the FIP's class. */
|
||||
|
||||
static void
|
||||
dwarf2_add_typedef (struct field_info *fip, struct die_info *die,
|
||||
struct dwarf2_cu *cu)
|
||||
dwarf2_add_type_defn (struct field_info *fip, struct die_info *die,
|
||||
struct dwarf2_cu *cu)
|
||||
{
|
||||
struct typedef_field_list *new_field;
|
||||
struct typedef_field *fp;
|
||||
struct decl_field_list *new_field;
|
||||
struct decl_field *fp;
|
||||
|
||||
/* Allocate a new field list entry and link it in. */
|
||||
new_field = XCNEW (struct typedef_field_list);
|
||||
new_field = XCNEW (struct decl_field_list);
|
||||
make_cleanup (xfree, new_field);
|
||||
|
||||
gdb_assert (die->tag == DW_TAG_typedef);
|
||||
gdb_assert (type_can_define_types (die));
|
||||
|
||||
fp = &new_field->field;
|
||||
|
||||
/* Get name of field. */
|
||||
/* Get name of field. NULL is okay here, meaning an anonymous type. */
|
||||
fp->name = dwarf2_name (die, cu);
|
||||
if (fp->name == NULL)
|
||||
return;
|
||||
|
||||
fp->type = read_type_die (die, cu);
|
||||
|
||||
/* Save accessibility. */
|
||||
|
@ -14035,9 +14056,18 @@ dwarf2_add_typedef (struct field_info *fip, struct die_info *die,
|
|||
_("Unhandled DW_AT_accessibility value (%x)"), accessibility);
|
||||
}
|
||||
|
||||
new_field->next = fip->typedef_field_list;
|
||||
fip->typedef_field_list = new_field;
|
||||
fip->typedef_field_list_count++;
|
||||
if (die->tag == DW_TAG_typedef)
|
||||
{
|
||||
new_field->next = fip->typedef_field_list;
|
||||
fip->typedef_field_list = new_field;
|
||||
fip->typedef_field_list_count++;
|
||||
}
|
||||
else
|
||||
{
|
||||
new_field->next = fip->nested_types_list;
|
||||
fip->nested_types_list = new_field;
|
||||
fip->nested_types_list_count++;
|
||||
}
|
||||
}
|
||||
|
||||
/* Create the vector of fields, and attach it to the type. */
|
||||
|
@ -14660,8 +14690,8 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
|
|||
/* C++ base class field. */
|
||||
dwarf2_add_field (&fi, child_die, cu);
|
||||
}
|
||||
else if (child_die->tag == DW_TAG_typedef)
|
||||
dwarf2_add_typedef (&fi, child_die, cu);
|
||||
else if (type_can_define_types (child_die))
|
||||
dwarf2_add_type_defn (&fi, child_die, cu);
|
||||
else if (child_die->tag == DW_TAG_template_type_param
|
||||
|| child_die->tag == DW_TAG_template_value_param)
|
||||
{
|
||||
|
@ -14768,14 +14798,14 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
|
|||
|
||||
ALLOCATE_CPLUS_STRUCT_TYPE (type);
|
||||
TYPE_TYPEDEF_FIELD_ARRAY (type)
|
||||
= ((struct typedef_field *)
|
||||
= ((struct decl_field *)
|
||||
TYPE_ALLOC (type, sizeof (TYPE_TYPEDEF_FIELD (type, 0)) * i));
|
||||
TYPE_TYPEDEF_FIELD_COUNT (type) = i;
|
||||
|
||||
/* Reverse the list order to keep the debug info elements order. */
|
||||
while (--i >= 0)
|
||||
{
|
||||
struct typedef_field *dest, *src;
|
||||
struct decl_field *dest, *src;
|
||||
|
||||
dest = &TYPE_TYPEDEF_FIELD (type, i);
|
||||
src = &fi.typedef_field_list->field;
|
||||
|
@ -14784,6 +14814,30 @@ process_structure_scope (struct die_info *die, struct dwarf2_cu *cu)
|
|||
}
|
||||
}
|
||||
|
||||
/* Copy fi.nested_types_list linked list elements content into the
|
||||
allocated array TYPE_NESTED_TYPES_ARRAY (type). */
|
||||
if (fi.nested_types_list != NULL && cu->language != language_ada)
|
||||
{
|
||||
int i = fi.nested_types_list_count;
|
||||
|
||||
ALLOCATE_CPLUS_STRUCT_TYPE (type);
|
||||
TYPE_NESTED_TYPES_ARRAY (type)
|
||||
= ((struct decl_field *)
|
||||
TYPE_ALLOC (type, sizeof (struct decl_field) * i));
|
||||
TYPE_NESTED_TYPES_COUNT (type) = i;
|
||||
|
||||
/* Reverse the list order to keep the debug info elements order. */
|
||||
while (--i >= 0)
|
||||
{
|
||||
struct decl_field *dest, *src;
|
||||
|
||||
dest = &TYPE_NESTED_TYPES_FIELD (type, i);
|
||||
src = &fi.nested_types_list->field;
|
||||
fi.nested_types_list = fi.nested_types_list->next;
|
||||
*dest = *src;
|
||||
}
|
||||
}
|
||||
|
||||
do_cleanups (back_to);
|
||||
}
|
||||
|
||||
|
|
|
@ -863,7 +863,7 @@ struct fn_field
|
|||
|
||||
};
|
||||
|
||||
struct typedef_field
|
||||
struct decl_field
|
||||
{
|
||||
/* * Unqualified name to be prefixed by owning class qualified
|
||||
name. */
|
||||
|
@ -978,10 +978,17 @@ struct cplus_struct_type
|
|||
/* * typedefs defined inside this class. typedef_field points to
|
||||
an array of typedef_field_count elements. */
|
||||
|
||||
struct typedef_field *typedef_field;
|
||||
struct decl_field *typedef_field;
|
||||
|
||||
unsigned typedef_field_count;
|
||||
|
||||
/* * The nested types defined by this type. nested_types points to
|
||||
an array of nested_types_count elements. */
|
||||
|
||||
struct decl_field *nested_types;
|
||||
|
||||
unsigned nested_types_count;
|
||||
|
||||
/* * The template arguments. This is an array with
|
||||
N_TEMPLATE_ARGUMENTS elements. This is NULL for non-template
|
||||
classes. */
|
||||
|
@ -1424,6 +1431,21 @@ extern void set_type_vptr_basetype (struct type *, struct type *);
|
|||
#define TYPE_TYPEDEF_FIELD_PRIVATE(thistype, n) \
|
||||
TYPE_TYPEDEF_FIELD (thistype, n).is_private
|
||||
|
||||
#define TYPE_NESTED_TYPES_ARRAY(thistype) \
|
||||
TYPE_CPLUS_SPECIFIC (thistype)->nested_types
|
||||
#define TYPE_NESTED_TYPES_FIELD(thistype, n) \
|
||||
TYPE_CPLUS_SPECIFIC (thistype)->nested_types[n]
|
||||
#define TYPE_NESTED_TYPES_FIELD_NAME(thistype, n) \
|
||||
TYPE_NESTED_TYPES_FIELD (thistype, n).name
|
||||
#define TYPE_NESTED_TYPES_FIELD_TYPE(thistype, n) \
|
||||
TYPE_NESTED_TYPES_FIELD (thistype, n).type
|
||||
#define TYPE_NESTED_TYPES_COUNT(thistype) \
|
||||
TYPE_CPLUS_SPECIFIC (thistype)->nested_types_count
|
||||
#define TYPE_NESTED_TYPES_FIELD_PROTECTED(thistype, n) \
|
||||
TYPE_NESTED_TYPES_FIELD (thistype, n).is_protected
|
||||
#define TYPE_NESTED_TYPES_FIELD_PRIVATE(thistype, n) \
|
||||
TYPE_NESTED_TYPES_FIELD (thistype, n).is_private
|
||||
|
||||
#define TYPE_IS_OPAQUE(thistype) \
|
||||
(((TYPE_CODE (thistype) == TYPE_CODE_STRUCT) \
|
||||
|| (TYPE_CODE (thistype) == TYPE_CODE_UNION)) \
|
||||
|
|
|
@ -1,3 +1,17 @@
|
|||
2017-12-07 Keith Seitz <keiths@redhat.com>
|
||||
|
||||
* gdb.cp/nested-types.cc: New file.
|
||||
* gdb.cp/nested-types.exp: New file.
|
||||
* lib/cp-support.exp: Load data-structures.exp library.
|
||||
(debug_cp_test_ptype_class): New global.
|
||||
(cp_ptype_class_verbose, next_line): New procedures.
|
||||
(cp_test_ptype_class): Add and document new parameter `recursive_qid'.
|
||||
Add and document new return value.
|
||||
Switch the list of lines to a queue.
|
||||
Add support for new `type' key for nested type definitions.
|
||||
Add debugging/troubleshooting messages.
|
||||
* lib/data-structures.exp: New file.
|
||||
|
||||
2017-12-07 Simon Marchi <simon.marchi@ericsson.com>
|
||||
|
||||
* gdb.python/py-breakpoint.exp (test_bkpt_explicit_loc): Define
|
||||
|
|
|
@ -0,0 +1,628 @@
|
|||
/* Code in this file is generated. -*- buffer-read-only: t -*- vi:set ro:
|
||||
See the procedure `make_source' in nested-types.exp. */
|
||||
|
||||
/* This testcase is part of GDB, the GNU debugger.
|
||||
|
||||
Copyright 2017 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/>. */
|
||||
|
||||
struct S10 {
|
||||
enum E10 {A10, B10, C10};
|
||||
union U10 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i10;
|
||||
E10 e10;
|
||||
U10 u10;
|
||||
|
||||
struct S11 {
|
||||
enum E11 {A11, B11, C11};
|
||||
union U11 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i11;
|
||||
E11 e11;
|
||||
U11 u11;
|
||||
|
||||
struct S12 {
|
||||
enum E12 {A12, B12, C12};
|
||||
union U12 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i12;
|
||||
E12 e12;
|
||||
U12 u12;
|
||||
|
||||
struct S13 {
|
||||
enum E13 {A13, B13, C13};
|
||||
union U13 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i13;
|
||||
E13 e13;
|
||||
U13 u13;
|
||||
|
||||
struct S14 {
|
||||
enum E14 {A14, B14, C14};
|
||||
union U14 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i14;
|
||||
E14 e14;
|
||||
U14 u14;
|
||||
|
||||
struct S15 {
|
||||
enum E15 {A15, B15, C15};
|
||||
union U15 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i15;
|
||||
E15 e15;
|
||||
U15 u15;
|
||||
|
||||
struct S16 {
|
||||
enum E16 {A16, B16, C16};
|
||||
union U16 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i16;
|
||||
E16 e16;
|
||||
U16 u16;
|
||||
|
||||
struct S17 {
|
||||
enum E17 {A17, B17, C17};
|
||||
union U17 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i17;
|
||||
E17 e17;
|
||||
U17 u17;
|
||||
|
||||
struct S18 {
|
||||
enum E18 {A18, B18, C18};
|
||||
union U18 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i18;
|
||||
E18 e18;
|
||||
U18 u18;
|
||||
|
||||
struct S19 {
|
||||
enum E19 {A19, B19, C19};
|
||||
union U19 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i19;
|
||||
E19 e19;
|
||||
U19 u19;
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
struct S21 {
|
||||
enum E21 {A21, B21, C21};
|
||||
union U21 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i21;
|
||||
E21 e21;
|
||||
U21 u21;
|
||||
|
||||
struct S22 {
|
||||
enum E22 {A22, B22, C22};
|
||||
union U22 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i22;
|
||||
E22 e22;
|
||||
U22 u22;
|
||||
|
||||
struct S23 {
|
||||
enum E23 {A23, B23, C23};
|
||||
union U23 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i23;
|
||||
E23 e23;
|
||||
U23 u23;
|
||||
|
||||
struct S24 {
|
||||
enum E24 {A24, B24, C24};
|
||||
union U24 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i24;
|
||||
E24 e24;
|
||||
U24 u24;
|
||||
|
||||
struct S25 {
|
||||
enum E25 {A25, B25, C25};
|
||||
union U25 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i25;
|
||||
E25 e25;
|
||||
U25 u25;
|
||||
|
||||
struct S26 {
|
||||
enum E26 {A26, B26, C26};
|
||||
union U26 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i26;
|
||||
E26 e26;
|
||||
U26 u26;
|
||||
|
||||
struct S27 {
|
||||
enum E27 {A27, B27, C27};
|
||||
union U27 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i27;
|
||||
E27 e27;
|
||||
U27 u27;
|
||||
|
||||
struct S28 {
|
||||
enum E28 {A28, B28, C28};
|
||||
union U28 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i28;
|
||||
E28 e28;
|
||||
U28 u28;
|
||||
|
||||
struct S29 {
|
||||
enum E29 {A29, B29, C29};
|
||||
union U29 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i29;
|
||||
E29 e29;
|
||||
U29 u29;
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
struct S31 {
|
||||
enum E31 {A31, B31, C31};
|
||||
union U31 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i31;
|
||||
E31 e31;
|
||||
U31 u31;
|
||||
|
||||
struct S32 {
|
||||
enum E32 {A32, B32, C32};
|
||||
union U32 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i32;
|
||||
E32 e32;
|
||||
U32 u32;
|
||||
|
||||
struct S33 {
|
||||
enum E33 {A33, B33, C33};
|
||||
union U33 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i33;
|
||||
E33 e33;
|
||||
U33 u33;
|
||||
|
||||
struct S34 {
|
||||
enum E34 {A34, B34, C34};
|
||||
union U34 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i34;
|
||||
E34 e34;
|
||||
U34 u34;
|
||||
|
||||
struct S35 {
|
||||
enum E35 {A35, B35, C35};
|
||||
union U35 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i35;
|
||||
E35 e35;
|
||||
U35 u35;
|
||||
|
||||
struct S36 {
|
||||
enum E36 {A36, B36, C36};
|
||||
union U36 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i36;
|
||||
E36 e36;
|
||||
U36 u36;
|
||||
|
||||
struct S37 {
|
||||
enum E37 {A37, B37, C37};
|
||||
union U37 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i37;
|
||||
E37 e37;
|
||||
U37 u37;
|
||||
|
||||
struct S38 {
|
||||
enum E38 {A38, B38, C38};
|
||||
union U38 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i38;
|
||||
E38 e38;
|
||||
U38 u38;
|
||||
|
||||
struct S39 {
|
||||
enum E39 {A39, B39, C39};
|
||||
union U39 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i39;
|
||||
E39 e39;
|
||||
U39 u39;
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
struct S41 {
|
||||
enum E41 {A41, B41, C41};
|
||||
union U41 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i41;
|
||||
E41 e41;
|
||||
U41 u41;
|
||||
|
||||
struct S42 {
|
||||
enum E42 {A42, B42, C42};
|
||||
union U42 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i42;
|
||||
E42 e42;
|
||||
U42 u42;
|
||||
|
||||
struct S43 {
|
||||
enum E43 {A43, B43, C43};
|
||||
union U43 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i43;
|
||||
E43 e43;
|
||||
U43 u43;
|
||||
|
||||
struct S44 {
|
||||
enum E44 {A44, B44, C44};
|
||||
union U44 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i44;
|
||||
E44 e44;
|
||||
U44 u44;
|
||||
|
||||
struct S45 {
|
||||
enum E45 {A45, B45, C45};
|
||||
union U45 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i45;
|
||||
E45 e45;
|
||||
U45 u45;
|
||||
|
||||
struct S46 {
|
||||
enum E46 {A46, B46, C46};
|
||||
union U46 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i46;
|
||||
E46 e46;
|
||||
U46 u46;
|
||||
|
||||
struct S47 {
|
||||
enum E47 {A47, B47, C47};
|
||||
union U47 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i47;
|
||||
E47 e47;
|
||||
U47 u47;
|
||||
|
||||
struct S48 {
|
||||
enum E48 {A48, B48, C48};
|
||||
union U48 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i48;
|
||||
E48 e48;
|
||||
U48 u48;
|
||||
|
||||
struct S49 {
|
||||
enum E49 {A49, B49, C49};
|
||||
union U49 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i49;
|
||||
E49 e49;
|
||||
U49 u49;
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
struct S51 {
|
||||
enum E51 {A51, B51, C51};
|
||||
union U51 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i51;
|
||||
E51 e51;
|
||||
U51 u51;
|
||||
|
||||
struct S52 {
|
||||
enum E52 {A52, B52, C52};
|
||||
union U52 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i52;
|
||||
E52 e52;
|
||||
U52 u52;
|
||||
|
||||
struct S53 {
|
||||
enum E53 {A53, B53, C53};
|
||||
union U53 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i53;
|
||||
E53 e53;
|
||||
U53 u53;
|
||||
|
||||
struct S54 {
|
||||
enum E54 {A54, B54, C54};
|
||||
union U54 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i54;
|
||||
E54 e54;
|
||||
U54 u54;
|
||||
|
||||
struct S55 {
|
||||
enum E55 {A55, B55, C55};
|
||||
union U55 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i55;
|
||||
E55 e55;
|
||||
U55 u55;
|
||||
|
||||
struct S56 {
|
||||
enum E56 {A56, B56, C56};
|
||||
union U56 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i56;
|
||||
E56 e56;
|
||||
U56 u56;
|
||||
|
||||
struct S57 {
|
||||
enum E57 {A57, B57, C57};
|
||||
union U57 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i57;
|
||||
E57 e57;
|
||||
U57 u57;
|
||||
|
||||
struct S58 {
|
||||
enum E58 {A58, B58, C58};
|
||||
union U58 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i58;
|
||||
E58 e58;
|
||||
U58 u58;
|
||||
|
||||
struct S59 {
|
||||
enum E59 {A59, B59, C59};
|
||||
union U59 {
|
||||
int a;
|
||||
char c;
|
||||
};
|
||||
|
||||
int i59;
|
||||
E59 e59;
|
||||
U59 u59;
|
||||
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
};
|
||||
|
||||
int
|
||||
main ()
|
||||
{
|
||||
S10 s10;
|
||||
S10::S11 s11;
|
||||
S10::S11::S12 s12;
|
||||
S10::S11::S12::S13 s13;
|
||||
S10::S11::S12::S13::S14 s14;
|
||||
S10::S11::S12::S13::S14::S15 s15;
|
||||
S10::S11::S12::S13::S14::S15::S16 s16;
|
||||
S10::S11::S12::S13::S14::S15::S16::S17 s17;
|
||||
S10::S11::S12::S13::S14::S15::S16::S17::S18 s18;
|
||||
S10::S11::S12::S13::S14::S15::S16::S17::S18::S19 s19;
|
||||
|
||||
S10::S21 s21;
|
||||
S10::S21::S22 s22;
|
||||
S10::S21::S22::S23 s23;
|
||||
S10::S21::S22::S23::S24 s24;
|
||||
S10::S21::S22::S23::S24::S25 s25;
|
||||
S10::S21::S22::S23::S24::S25::S26 s26;
|
||||
S10::S21::S22::S23::S24::S25::S26::S27 s27;
|
||||
S10::S21::S22::S23::S24::S25::S26::S27::S28 s28;
|
||||
S10::S21::S22::S23::S24::S25::S26::S27::S28::S29 s29;
|
||||
|
||||
S10::S31 s31;
|
||||
S10::S31::S32 s32;
|
||||
S10::S31::S32::S33 s33;
|
||||
S10::S31::S32::S33::S34 s34;
|
||||
S10::S31::S32::S33::S34::S35 s35;
|
||||
S10::S31::S32::S33::S34::S35::S36 s36;
|
||||
S10::S31::S32::S33::S34::S35::S36::S37 s37;
|
||||
S10::S31::S32::S33::S34::S35::S36::S37::S38 s38;
|
||||
S10::S31::S32::S33::S34::S35::S36::S37::S38::S39 s39;
|
||||
|
||||
S10::S41 s41;
|
||||
S10::S41::S42 s42;
|
||||
S10::S41::S42::S43 s43;
|
||||
S10::S41::S42::S43::S44 s44;
|
||||
S10::S41::S42::S43::S44::S45 s45;
|
||||
S10::S41::S42::S43::S44::S45::S46 s46;
|
||||
S10::S41::S42::S43::S44::S45::S46::S47 s47;
|
||||
S10::S41::S42::S43::S44::S45::S46::S47::S48 s48;
|
||||
S10::S41::S42::S43::S44::S45::S46::S47::S48::S49 s49;
|
||||
|
||||
S10::S51 s51;
|
||||
S10::S51::S52 s52;
|
||||
S10::S51::S52::S53 s53;
|
||||
S10::S51::S52::S53::S54 s54;
|
||||
S10::S51::S52::S53::S54::S55 s55;
|
||||
S10::S51::S52::S53::S54::S55::S56 s56;
|
||||
S10::S51::S52::S53::S54::S55::S56::S57 s57;
|
||||
S10::S51::S52::S53::S54::S55::S56::S57::S58 s58;
|
||||
S10::S51::S52::S53::S54::S55::S56::S57::S58::S59 s59;
|
||||
return 0;
|
||||
}
|
|
@ -0,0 +1,322 @@
|
|||
# Copyright 2017 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 nested class definitions with the type printer.
|
||||
#
|
||||
# This test works by constructing a tree to represent "struct S10" in
|
||||
# the corresponding source file. It then walks the nodes of this tree
|
||||
# to construct input suitable for passing to cp_test_ptype_class.
|
||||
|
||||
if {[skip_cplus_tests]} { continue }
|
||||
|
||||
load_lib "cp-support.exp"
|
||||
|
||||
standard_testfile .cc
|
||||
|
||||
if {[prepare_for_testing "failed to prepare" $testfile $srcfile \
|
||||
{debug c++}]} {
|
||||
return -1
|
||||
}
|
||||
|
||||
# Build the node given by ID (a number representing the struct S[ID] in
|
||||
# the source file).
|
||||
#
|
||||
# For each node, stored as ::nodes(ID,ARG), where ARG is
|
||||
#
|
||||
# fields - list of fields [no children]
|
||||
# children - list of types [children]
|
||||
|
||||
proc build_node {id} {
|
||||
global nodes
|
||||
|
||||
# For any node, FIELDS is always the types i(N), e(N), u(N)
|
||||
# CHILDREN is a list of nodes called [E(N), U(N)] S(N+1)
|
||||
#
|
||||
# The root (10) also has S(N+11), S(N+21), S(N+31), S(N+41)
|
||||
|
||||
set nodes($id,fields) [list "int i$id" "E$id e$id" "U$id u$id"]
|
||||
set nodes($id,children) {}
|
||||
if {$id == 10} {
|
||||
set limit 5
|
||||
} else {
|
||||
set limit 1
|
||||
}
|
||||
for {set i 0} {$i < $limit} {incr i} {
|
||||
set n [expr {1 + $id + $i * 10}]
|
||||
|
||||
# We don't build nodes which are multiples of 10
|
||||
# (the source only uses that at the root struct).
|
||||
# We also don't create nodes not in the source file
|
||||
# (id >= 60).
|
||||
if {[expr {$n % 10}] != 0 && $n < 60} {
|
||||
lappend nodes($id,children) $n
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# A helper procedure to indent the log output by LVL. This is used for
|
||||
# debugging the tree, if ever necessary.
|
||||
|
||||
proc indent {lvl} {
|
||||
for {set i 0} {$i < $lvl} {incr i} {
|
||||
send_log " "
|
||||
}
|
||||
}
|
||||
|
||||
# For the given CHILD name and PARENT_LIST, return the fully qualified
|
||||
# name of the child type.
|
||||
|
||||
proc qual_name {child parent_list} {
|
||||
if {[string range $child 0 2] != "int" && [llength $parent_list]} {
|
||||
return "[join $parent_list ::]::$child"
|
||||
} else {
|
||||
return "$child"
|
||||
}
|
||||
}
|
||||
|
||||
# Output the test source to the log.
|
||||
|
||||
proc make_source {} {
|
||||
# Output the structure.
|
||||
test_nested_limit 10 true
|
||||
|
||||
# Output main().
|
||||
send_log "int\nmain \(\)\n\{\n"
|
||||
set plist {}
|
||||
for {set i 10} {$i < 60} {incr i} {
|
||||
if {$i > 10 && [expr {$i % 10}] == 0} {
|
||||
incr i
|
||||
set plist {"S10"}
|
||||
send_log "\n"
|
||||
}
|
||||
send_log " [qual_name S$i $plist] s$i;\n"
|
||||
lappend plist "S$i"
|
||||
}
|
||||
|
||||
send_log " return 0;\n"
|
||||
send_log "\}\n"
|
||||
}
|
||||
|
||||
# Output to the log and/or create the result list for the fields of node ID.
|
||||
|
||||
proc make_fields {result_var id parent_list indent_lvl log} {
|
||||
upvar $result_var result
|
||||
global nodes
|
||||
|
||||
foreach type $nodes($id,fields) {
|
||||
set s "[qual_name $type $parent_list];"
|
||||
if {$log} {
|
||||
indent $indent_lvl
|
||||
send_log "$s\n"
|
||||
}
|
||||
lappend result [list "field" "public" "$s"]
|
||||
}
|
||||
}
|
||||
|
||||
# Output to the log and/or create the result list for the union type in
|
||||
# node ID.
|
||||
|
||||
proc make_union {result_var id parent_list indent_lvl log} {
|
||||
upvar $result_var result
|
||||
|
||||
set s "[qual_name U$id $parent_list]"
|
||||
set a "int a;"
|
||||
set c "char c;"
|
||||
lappend result [list "type" "public" "union" $s [list $a $c]]
|
||||
if {$log} {
|
||||
indent $indent_lvl
|
||||
send_log "union $s \{\n"
|
||||
indent [expr {$indent_lvl + 1}]
|
||||
send_log "$a\n"
|
||||
indent [expr {$indent_lvl + 1}]
|
||||
send_log "$c\n"
|
||||
indent $indent_lvl
|
||||
send_log "\};\n"
|
||||
}
|
||||
}
|
||||
|
||||
# Output to the log and/or create the result list for the enum type in
|
||||
# node ID.
|
||||
|
||||
proc make_enum {result_var id parent_list indent_lvl log} {
|
||||
upvar $result_var result
|
||||
|
||||
set s "[qual_name E$id $parent_list]"
|
||||
set a "[qual_name A$id $parent_list]"
|
||||
set b "[qual_name B$id $parent_list]"
|
||||
set c "[qual_name C$id $parent_list]"
|
||||
lappend result [list "type" "public" "enum" $s [list $a $b $c]]
|
||||
|
||||
if {$log} {
|
||||
indent $indent_lvl
|
||||
send_log "enum $s \{$a, $b, $c\};\n"
|
||||
}
|
||||
}
|
||||
|
||||
# Output to the log and/or create the result list for the node given by ID.
|
||||
#
|
||||
# LIMIT describes the number of nested types to output (corresponding to
|
||||
# the "set print type nested-type-limit" command).
|
||||
# PARENT_LIST is the list of parent nodes already seen.
|
||||
# INDENT_LVL is the indentation level (used when LOG is true).
|
||||
|
||||
proc node_result {result_var id limit parent_list indent_lvl log} {
|
||||
upvar $result_var result
|
||||
|
||||
# Start a new type list.
|
||||
set my_name "S$id"
|
||||
set s "[qual_name $my_name $parent_list]"
|
||||
set my_result [list "type" "public" "struct" $s]
|
||||
|
||||
if {$log} {
|
||||
indent $indent_lvl
|
||||
send_log "struct $my_name \{\n"
|
||||
} else {
|
||||
# Add this node to the parent list so that its name appears in
|
||||
# qualified names, but only if we are not logging. [See immediately
|
||||
# below.]
|
||||
lappend parent_list "$my_name"
|
||||
}
|
||||
|
||||
# `ptype' outputs fields before type definitions, but in order to
|
||||
# output compile-ready code, these must be output in reverse.
|
||||
|
||||
if {!$log} {
|
||||
# Output field list to a local children list.
|
||||
set children_list {}
|
||||
make_fields children_list $id $parent_list \
|
||||
[expr {$indent_lvl + 1}] $log
|
||||
|
||||
# Output type definitions to the local children list.
|
||||
# The first number of ID gives us the depth of the node.
|
||||
if {[string index $id 1] < $limit || $limit < 0} {
|
||||
make_enum children_list $id $parent_list \
|
||||
[expr {$indent_lvl + 1}] $log
|
||||
make_union children_list $id $parent_list \
|
||||
[expr {$indent_lvl + 1}] $log
|
||||
}
|
||||
} else {
|
||||
# Output type definitions to the local children list.
|
||||
# The first number of ID gives us the depth of the node.
|
||||
if {[string index $id 1] < $limit || $limit < 0} {
|
||||
make_enum children_list $id $parent_list \
|
||||
[expr {$indent_lvl + 1}] $log
|
||||
make_union children_list $id $parent_list \
|
||||
[expr {$indent_lvl + 1}] $log
|
||||
send_log "\n"
|
||||
}
|
||||
|
||||
# Output field list to a local children list.
|
||||
set children_list {}
|
||||
make_fields children_list $id $parent_list \
|
||||
[expr {$indent_lvl + 1}] $log
|
||||
send_log "\n"
|
||||
}
|
||||
|
||||
# Output the children to the local children list.
|
||||
global nodes
|
||||
if {[info exists nodes($id,children)]} {
|
||||
foreach c $nodes($id,children) {
|
||||
if {[string index $c 1] <= $limit || $limit < 0} {
|
||||
node_result children_list $c $limit $parent_list \
|
||||
[expr {$indent_lvl + 1}] $log
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Add this node's children to its result and add its result to
|
||||
# its parent's results.
|
||||
lappend my_result $children_list
|
||||
lappend result $my_result
|
||||
|
||||
if {$log} {
|
||||
indent $indent_lvl
|
||||
send_log "\};\n"
|
||||
}
|
||||
}
|
||||
|
||||
# Test nested type definitions. LIMIT specifies how many nested levels
|
||||
# of definitions to test. If LOG is true, output the tree to the log in
|
||||
# a human-readable format mimicing the source code.
|
||||
#
|
||||
# Only test when not logging. Generating source code usable by the
|
||||
# test is not quite the same as how GDB outputs it.
|
||||
|
||||
proc test_nested_limit {limit log} {
|
||||
set result {}
|
||||
|
||||
if {!$log} {
|
||||
# Set the number of nested definitions to print.
|
||||
gdb_test_no_output "set print type nested-type-limit $limit"
|
||||
|
||||
# Check the output of "show type print nested-type-limit"
|
||||
if {$limit < 0} {
|
||||
set lstr "unlimited"
|
||||
} else {
|
||||
set lstr $limit
|
||||
}
|
||||
gdb_test "show print type nested-type-limit" \
|
||||
"Will print $lstr nested types defined in a class" \
|
||||
"show print type nested-type-limit ($limit)"
|
||||
} else {
|
||||
send_log "Tree to $limit levels:\n"
|
||||
}
|
||||
|
||||
# Generate the result list.
|
||||
node_result result 10 $limit {} 0 $log
|
||||
|
||||
if {!$log} {
|
||||
# The only output we check for is the contents of the struct,
|
||||
# ignoring the leading "type = struct S10 {" and trailing "}" of
|
||||
# the outermost node.
|
||||
set result [lindex $result 0]
|
||||
lassign $result type access key name children
|
||||
cp_test_ptype_class $name "ptype $name (limit = $limit)" $key \
|
||||
$name $children
|
||||
}
|
||||
}
|
||||
|
||||
# Build a tree of nodes describing the structures in the source file.
|
||||
|
||||
# An array holding all the nodes
|
||||
array set nodes {}
|
||||
build_node 10
|
||||
for {set i 1} {$i < 6} {incr i} {
|
||||
for {set j 1} {$j < 10} {incr j} {
|
||||
build_node $i$j
|
||||
}
|
||||
}
|
||||
|
||||
# Check relevant commands.
|
||||
|
||||
# By default, we do not print nested type definitions.
|
||||
gdb_test "show print type nested-type-limit" \
|
||||
"Will not print nested types defined in a class" \
|
||||
"show default print type nested-type-limit"
|
||||
|
||||
# -1 means we print all nested types
|
||||
test_nested_limit -1 false
|
||||
|
||||
# Test the output of "show print type nested-type-limit" and
|
||||
# ptype on the test source.
|
||||
|
||||
for {set i 1} {$i < 9} {incr i} {
|
||||
test_nested_limit $i false
|
||||
}
|
||||
|
||||
# To output the test code to the log, uncomment the following line:
|
||||
#make_source
|
||||
|
||||
unset -nocomplain nodes result
|
|
@ -15,6 +15,15 @@
|
|||
# You should have received a copy of the GNU General Public License
|
||||
# along with this program. If not, see <http://www.gnu.org/licenses/>.
|
||||
|
||||
load_lib "data-structures.exp"
|
||||
|
||||
# Controls whether detailed logging for cp_test_ptype_class is enabled.
|
||||
# By default, it is not. Enable it to assist with troubleshooting
|
||||
# failed cp_test_ptype_class tests. [Users can simply add the statement
|
||||
# "set debug_cp_ptype_test_class true" after this file is loaded.]
|
||||
|
||||
set ::debug_cp_test_ptype_class false
|
||||
|
||||
# Auxiliary function to check for known problems.
|
||||
#
|
||||
# EXPECTED_STRING is the string expected by the test.
|
||||
|
@ -38,7 +47,41 @@ proc cp_check_errata { expected_string actual_string errata_table } {
|
|||
}
|
||||
}
|
||||
|
||||
# Test ptype of a class.
|
||||
# A convenience procedure for outputting debug info for cp_test_ptype_class
|
||||
# to the log. Set the global variable "debug_cp_test_ptype_class"
|
||||
# to enable logging (to help with debugging failures).
|
||||
|
||||
proc cp_ptype_class_verbose {msg} {
|
||||
global debug_cp_test_ptype_class
|
||||
|
||||
if {$debug_cp_test_ptype_class} {
|
||||
verbose -log $msg
|
||||
}
|
||||
}
|
||||
|
||||
# A namespace to wrap internal procedures.
|
||||
|
||||
namespace eval ::cp_support_internal {
|
||||
|
||||
# A convenience procedure to return the next element of the queue.
|
||||
proc next_line {qid} {
|
||||
set elem {}
|
||||
|
||||
while {$elem == "" && ![queue empty $qid]} {
|
||||
# We make cp_test_ptype_class trim whitespace
|
||||
set elem [queue pop $qid]
|
||||
}
|
||||
|
||||
if {$elem == ""} {
|
||||
cp_ptype_class_verbose "next line element: no more lines"
|
||||
} else {
|
||||
cp_ptype_class_verbose "next line element: \"$elem\""
|
||||
}
|
||||
return $elem
|
||||
}
|
||||
}
|
||||
|
||||
# Test ptype of a class. Return `true' if the test passes, false otherwise.
|
||||
#
|
||||
# Different C++ compilers produce different output. To accommodate all
|
||||
# the variations listed below, I read the output of "ptype" and process
|
||||
|
@ -87,6 +130,20 @@ proc cp_check_errata { expected_string actual_string errata_table } {
|
|||
# the class has a typedef with the given access type and the
|
||||
# given declaration.
|
||||
#
|
||||
# { type "access" "key" "name" children }
|
||||
#
|
||||
# The class has a nested type definition with the given ACCESS.
|
||||
# KEY is the keyword of the nested type ("enum", "union", "struct",
|
||||
# "class").
|
||||
# NAME is the (tag) name of the type.
|
||||
# CHILDREN is a list of the type's children. For struct and union keys,
|
||||
# this is simply the same type of list that is normally passed to
|
||||
# this procedure. For enums the list of children should be the
|
||||
# defined enumerators. For unions it is a list of declarations.
|
||||
# NOTE: The enum key will add a regexp to handle optional storage
|
||||
# class specifiers (": unsigned int", e.g.). The caller need not
|
||||
# specify this.
|
||||
#
|
||||
# If you test the same class declaration more than once, you can specify
|
||||
# IN_CLASS_TABLE as "ibid". "ibid" means: look for a previous class
|
||||
# table that had the same IN_KEY and IN_TAG, and re-use that table.
|
||||
|
@ -102,6 +159,11 @@ proc cp_check_errata { expected_string actual_string errata_table } {
|
|||
#
|
||||
# IN_PTYPE_ARG are arguments to pass to ptype. The default is "/r".
|
||||
#
|
||||
# RECURSIVE_QID is used internally to call this procedure recursively
|
||||
# when, e.g., testing nested type definitions. The "ptype" command will
|
||||
# not be sent to GDB and the lines in the queue given by this argument will
|
||||
# be used instead.
|
||||
#
|
||||
# gdb can vary the output of ptype in several ways:
|
||||
#
|
||||
# . CLASS/STRUCT
|
||||
|
@ -178,16 +240,20 @@ proc cp_check_errata { expected_string actual_string errata_table } {
|
|||
#
|
||||
# -- chastain 2004-08-07
|
||||
|
||||
proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_tail "" } { in_errata_table { } } { in_ptype_arg /r } } {
|
||||
proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table
|
||||
{ in_tail "" } { in_errata_table { } }
|
||||
{ in_ptype_arg /r } { recursive_qid 0 } } {
|
||||
global gdb_prompt
|
||||
set wsopt "\[\r\n\t \]*"
|
||||
|
||||
# The test name defaults to the command, but without the
|
||||
# arguments, for historical reasons.
|
||||
if {$recursive_qid == 0} {
|
||||
# The test name defaults to the command, but without the
|
||||
# arguments, for historical reasons.
|
||||
|
||||
if { "$in_testname" == "" } then { set in_testname "ptype $in_exp" }
|
||||
if { "$in_testname" == "" } then { set in_testname "ptype $in_exp" }
|
||||
|
||||
set in_command "ptype${in_ptype_arg} $in_exp"
|
||||
set in_command "ptype${in_ptype_arg} $in_exp"
|
||||
}
|
||||
|
||||
# Save class tables in a history array for reuse.
|
||||
|
||||
|
@ -195,7 +261,7 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
if { $in_class_table == "ibid" } then {
|
||||
if { ! [info exists cp_class_table_history("$in_key,$in_tag") ] } then {
|
||||
fail "$in_testname // bad ibid"
|
||||
return
|
||||
return false
|
||||
}
|
||||
set in_class_table $cp_class_table_history("$in_key,$in_tag")
|
||||
} else {
|
||||
|
@ -209,6 +275,9 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
set list_fields { }
|
||||
set list_methods { }
|
||||
set list_typedefs { }
|
||||
set list_types { }
|
||||
set list_enums { }
|
||||
set list_unions { }
|
||||
|
||||
foreach class_line $in_class_table {
|
||||
switch [lindex $class_line 0] {
|
||||
|
@ -217,7 +286,11 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
"field" { lappend list_fields [lrange $class_line 1 2] }
|
||||
"method" { lappend list_methods [lrange $class_line 1 2] }
|
||||
"typedef" { lappend list_typedefs [lrange $class_line 1 2] }
|
||||
default { fail "$in_testname // bad line in class table: $class_line"; return; }
|
||||
"type" { lappend list_types [lrange $class_line 1 4] }
|
||||
default {
|
||||
fail "$in_testname // bad line in class table: $class_line"
|
||||
return false
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -225,24 +298,56 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
# These are: { count ccess-type regular-expression }.
|
||||
|
||||
set list_synth { }
|
||||
lappend list_synth [list 0 "public" "$in_tag & operator=\\($in_tag const ?&\\);"]
|
||||
lappend list_synth [list 0 "public" "$in_tag\\((int,|) ?$in_tag const ?&\\);"]
|
||||
lappend list_synth [list 0 "public" "$in_tag\\((int|void|)\\);"]
|
||||
lappend list_synth [list 0 "public" \
|
||||
"$in_tag & operator=\\($in_tag const ?&\\);"]
|
||||
lappend list_synth [list 0 "public" \
|
||||
"$in_tag\\((int,|) ?$in_tag const ?&\\);"]
|
||||
lappend list_synth [list 0 "public" \
|
||||
"$in_tag\\((int|void|)\\);"]
|
||||
|
||||
# Actually do the ptype.
|
||||
# Partial regexp for parsing the struct/class header.
|
||||
set regexp_header "(struct|class)${wsopt}(\[^ \t\]*)${wsopt}"
|
||||
append regexp_header "(\\\[with .*\\\]${wsopt})?((:\[^\{\]*)?)${wsopt}\{"
|
||||
if {$recursive_qid == 0} {
|
||||
# Actually do the ptype.
|
||||
|
||||
set parse_okay 0
|
||||
gdb_test_multiple "$in_command" "$in_testname // parse failed" {
|
||||
-re "type = (struct|class)${wsopt}(\[^ \t\]*)${wsopt}(\\\[with .*\\\]${wsopt})?((:\[^\{\]*)?)${wsopt}\{(.*)\}${wsopt}(\[^\r\n\]*)\[\r\n\]+$gdb_prompt $" {
|
||||
set parse_okay 1
|
||||
set actual_key $expect_out(1,string)
|
||||
set actual_tag $expect_out(2,string)
|
||||
set actual_base_string $expect_out(4,string)
|
||||
set actual_body $expect_out(6,string)
|
||||
set actual_tail $expect_out(7,string)
|
||||
# For processing the output of ptype, we must get to the prompt.
|
||||
set the_regexp "type = ${regexp_header}"
|
||||
append the_regexp "(.*)\}${wsopt}(\[^\r\n\]*)\[\r\n\]+$gdb_prompt $"
|
||||
set parse_okay 0
|
||||
gdb_test_multiple "$in_command" "$in_testname // parse failed" {
|
||||
-re $the_regexp {
|
||||
set parse_okay 1
|
||||
set actual_key $expect_out(1,string)
|
||||
set actual_tag $expect_out(2,string)
|
||||
set actual_base_string $expect_out(4,string)
|
||||
set actual_body $expect_out(6,string)
|
||||
set actual_tail $expect_out(7,string)
|
||||
}
|
||||
}
|
||||
} else {
|
||||
# The struct/class header by the first element in the line queue.
|
||||
# "Parse" that instead of the output of ptype.
|
||||
set header [cp_support_internal::next_line $recursive_qid]
|
||||
set parse_okay [regexp $regexp_header $header dummy actual_key \
|
||||
actual_tag dummy actual_base_string]
|
||||
|
||||
if {$parse_okay} {
|
||||
cp_ptype_class_verbose \
|
||||
"Parsing nested type definition (parse_okay=$parse_okay):"
|
||||
cp_ptype_class_verbose \
|
||||
"\tactual_key=$actual_key, actual_tag=$actual_tag"
|
||||
cp_ptype_class_verbose "\tactual_base_string=$actual_base_string"
|
||||
}
|
||||
|
||||
# Cannot have a tail with a nested type definition.
|
||||
set actual_tail ""
|
||||
}
|
||||
|
||||
if { ! $parse_okay } {
|
||||
cp_ptype_class_verbose "*** parse failed ***"
|
||||
return false
|
||||
}
|
||||
if { ! $parse_okay } then { return }
|
||||
|
||||
# Check the actual key. It would be nice to require that it match
|
||||
# the input key, but gdb does not support that. For now, accept any
|
||||
|
@ -256,7 +361,7 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
cp_check_errata "class" "$actual_key" $in_errata_table
|
||||
cp_check_errata "struct" "$actual_key" $in_errata_table
|
||||
fail "$in_testname // wrong key: $actual_key"
|
||||
return
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
|
@ -265,7 +370,7 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
if { "$actual_tag" != "$in_tag" } then {
|
||||
cp_check_errata "$in_tag" "$actual_tag" $in_errata_table
|
||||
fail "$in_testname // wrong tag: $actual_tag"
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
# Check the actual bases.
|
||||
|
@ -281,11 +386,11 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
|
||||
if { [llength $list_actual_bases] < [llength $list_bases] } then {
|
||||
fail "$in_testname // too few bases"
|
||||
return
|
||||
return false
|
||||
}
|
||||
if { [llength $list_actual_bases] > [llength $list_bases] } then {
|
||||
fail "$in_testname // too many bases"
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
# Check each base.
|
||||
|
@ -296,7 +401,7 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
if { "$actual_base" != "$base" } then {
|
||||
cp_check_errata "$base" "$actual_base" $in_errata_table
|
||||
fail "$in_testname // wrong base: $actual_base"
|
||||
return
|
||||
return false
|
||||
}
|
||||
set list_bases [lreplace $list_bases 0 0]
|
||||
}
|
||||
|
@ -306,11 +411,26 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
set last_was_access 0
|
||||
set vbase_match 0
|
||||
|
||||
foreach actual_line [split $actual_body "\r\n"] {
|
||||
if {$recursive_qid == 0} {
|
||||
# Use a queue to hold the lines that will be checked.
|
||||
# This will allow processing below to remove lines from the input
|
||||
# more easily.
|
||||
set line_queue [::Queue::new]
|
||||
foreach l [split $actual_body "\r\n"] {
|
||||
set l [string trim $l]
|
||||
if {$l != ""} {
|
||||
queue push $line_queue $l
|
||||
}
|
||||
}
|
||||
} else {
|
||||
set line_queue $recursive_qid
|
||||
}
|
||||
|
||||
# Chomp the line.
|
||||
while {![queue empty $line_queue]} {
|
||||
|
||||
set actual_line [string trim $actual_line]
|
||||
# Get the next line.
|
||||
|
||||
set actual_line [cp_support_internal::next_line $line_queue]
|
||||
if { "$actual_line" == "" } then { continue }
|
||||
|
||||
# Access specifiers.
|
||||
|
@ -319,7 +439,8 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
set access "$s1"
|
||||
if { $last_was_access } then {
|
||||
fail "$in_testname // redundant access specifier"
|
||||
return
|
||||
queue delete $line_queue
|
||||
return false
|
||||
}
|
||||
set last_was_access 1
|
||||
continue
|
||||
|
@ -335,7 +456,8 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
if { "$access" != "private" } then {
|
||||
cp_check_errata "private" "$access" $in_errata_table
|
||||
fail "$in_testname // wrong access specifier for virtual base: $access"
|
||||
return
|
||||
queue delete $line_queue
|
||||
return false
|
||||
}
|
||||
set list_vbases [lreplace $list_vbases 0 0]
|
||||
set vbase_match 1
|
||||
|
@ -348,11 +470,18 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
if { [llength $list_fields] > 0 } then {
|
||||
set field_access [lindex [lindex $list_fields 0] 0]
|
||||
set field_decl [lindex [lindex $list_fields 0] 1]
|
||||
if {$recursive_qid > 0} {
|
||||
cp_ptype_class_verbose "\tactual_line=$actual_line"
|
||||
cp_ptype_class_verbose "\tfield_access=$field_access"
|
||||
cp_ptype_class_verbose "\tfield_decl=$field_decl"
|
||||
cp_ptype_class_verbose "\taccess=$access"
|
||||
}
|
||||
if { "$actual_line" == "$field_decl" } then {
|
||||
if { "$access" != "$field_access" } then {
|
||||
cp_check_errata "$field_access" "$access" $in_errata_table
|
||||
fail "$in_testname // wrong access specifier for field: $access"
|
||||
return
|
||||
queue delete $line_queue
|
||||
return false
|
||||
}
|
||||
set list_fields [lreplace $list_fields 0 0]
|
||||
continue
|
||||
|
@ -361,7 +490,8 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
# Data fields must appear before synths and methods.
|
||||
cp_check_errata "$field_decl" "$actual_line" $in_errata_table
|
||||
fail "$in_testname // unrecognized line type 1: $actual_line"
|
||||
return
|
||||
queue delete $line_queue
|
||||
return false
|
||||
}
|
||||
|
||||
# Method function.
|
||||
|
@ -373,7 +503,8 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
if { "$access" != "$method_access" } then {
|
||||
cp_check_errata "$method_access" "$access" $in_errata_table
|
||||
fail "$in_testname // wrong access specifier for method: $access"
|
||||
return
|
||||
queue delete $line_queue
|
||||
return false
|
||||
}
|
||||
set list_methods [lreplace $list_methods 0 0]
|
||||
continue
|
||||
|
@ -385,7 +516,8 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
if { "$access" != "$method_access" } then {
|
||||
cp_check_errata "$method_access" "$access" $in_errata_table
|
||||
fail "$in_testname // wrong access specifier for method: $access"
|
||||
return
|
||||
queue delete $line_queue
|
||||
return false
|
||||
}
|
||||
set list_methods [lreplace $list_methods 0 0]
|
||||
continue
|
||||
|
@ -401,13 +533,130 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
if {![string equal $access $typedef_access]} {
|
||||
cp_check_errata $typedef_access $access $in_errata_table
|
||||
fail "$in_testname // wrong access specifier for typedef: $access"
|
||||
return
|
||||
queue delete $line_queue
|
||||
return false
|
||||
}
|
||||
set list_typedefs [lreplace $list_typedefs 0 0]
|
||||
continue
|
||||
}
|
||||
}
|
||||
|
||||
# Nested type definitions
|
||||
|
||||
if {[llength $list_types] > 0} {
|
||||
cp_ptype_class_verbose "Nested type definition: "
|
||||
lassign [lindex $list_types 0] nested_access nested_key \
|
||||
nested_name nested_children
|
||||
set msg "nested_access=$nested_access, nested_key=$nested_key, "
|
||||
append msg "nested_name=$nested_name, "
|
||||
append msg "[llength $nested_children] children"
|
||||
cp_ptype_class_verbose $msg
|
||||
|
||||
if {![string equal $access $nested_access]} {
|
||||
cp_check_errata $nested_access $access $in_errata_table
|
||||
set txt "$in_testname // wrong access specifier for "
|
||||
append txt "nested type: $access"
|
||||
fail $txt
|
||||
queue delete $line_queue
|
||||
return false
|
||||
}
|
||||
|
||||
switch $nested_key {
|
||||
enum {
|
||||
set expected_result \
|
||||
"enum $nested_name (: (unsigned )?int)? \{"
|
||||
foreach c $nested_children {
|
||||
append expected_result "$c, "
|
||||
}
|
||||
set expected_result \
|
||||
[string trimright $expected_result { ,}]
|
||||
append expected_result "\};"
|
||||
cp_ptype_class_verbose \
|
||||
"Expecting enum result: $expected_result"
|
||||
if {![regexp -- $expected_result $actual_line]} {
|
||||
set txt "$in_testname // wrong nested type enum"
|
||||
append txt " definition: $actual_linejj"
|
||||
fail $txt
|
||||
queue delete $line_queue
|
||||
return false
|
||||
}
|
||||
cp_ptype_class_verbose "passed enum $nested_name"
|
||||
}
|
||||
|
||||
union {
|
||||
set expected_result "union $nested_name \{"
|
||||
cp_ptype_class_verbose \
|
||||
"Expecting union result: $expected_result"
|
||||
if {![string equal $expected_result $actual_line]} {
|
||||
set txt "$in_testname // wrong nested type union"
|
||||
append txt " definition: $actual_line"
|
||||
fail $txt
|
||||
queue delete $line_queue
|
||||
return false
|
||||
}
|
||||
|
||||
# This will be followed by lines for each member of the
|
||||
# union.
|
||||
cp_ptype_class_verbose "matched union name"
|
||||
foreach m $nested_children {
|
||||
set actual_line \
|
||||
[cp_support_internal::next_line $line_queue]
|
||||
cp_ptype_class_verbose "Expecting union member: $m"
|
||||
if {![string equal $m $actual_line]} {
|
||||
set txt "$in_testname // unexpected union member: "
|
||||
append txt $m
|
||||
fail $txt
|
||||
queue delete $line_queue
|
||||
return false
|
||||
}
|
||||
cp_ptype_class_verbose "matched union child \"$m\""
|
||||
}
|
||||
|
||||
# Nested union types always end with a trailing curly brace.
|
||||
set actual_line [cp_support_internal::next_line $line_queue]
|
||||
if {![string equal $actual_line "\};"]} {
|
||||
fail "$in_testname // missing closing curly brace"
|
||||
queue delete $line_queue
|
||||
return false
|
||||
}
|
||||
cp_ptype_class_verbose "passed union $nested_name"
|
||||
}
|
||||
|
||||
struct -
|
||||
class {
|
||||
cp_ptype_class_verbose \
|
||||
"Expecting [llength $nested_children] children"
|
||||
foreach c $nested_children {
|
||||
cp_ptype_class_verbose "\t$c"
|
||||
}
|
||||
# Start by pushing the current line back into the queue
|
||||
# so that the recursive call can parse the class/struct
|
||||
# header.
|
||||
queue unpush $line_queue $actual_line
|
||||
cp_ptype_class_verbose \
|
||||
"Recursing for type $nested_key $nested_name"
|
||||
if {![cp_test_ptype_class $in_exp $in_testname $nested_key \
|
||||
$nested_name $nested_children $in_tail \
|
||||
$in_errata_table $in_ptype_arg $line_queue]} {
|
||||
# The recursive call has already called `fail' and
|
||||
# released the line queue.
|
||||
return false
|
||||
}
|
||||
cp_ptype_class_verbose \
|
||||
"passed nested type $nested_key $nested_name"
|
||||
}
|
||||
|
||||
default {
|
||||
fail "$in_testname // invalid nested type key: $nested_key"
|
||||
queue delete $line_queue
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
set list_types [lreplace $list_types 0 0]
|
||||
continue
|
||||
}
|
||||
|
||||
# Synthetic operators. These are optional and can be mixed in
|
||||
# with the methods in any order, but duplicates are wrong.
|
||||
#
|
||||
|
@ -427,7 +676,8 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
if { "$access" != "$synth_access" } then {
|
||||
cp_check_errata "$synth_access" "$access" $in_errata_table
|
||||
fail "$in_testname // wrong access specifier for synthetic operator: $access"
|
||||
return
|
||||
queue delete $line_queue
|
||||
return false
|
||||
}
|
||||
|
||||
if { $synth_count > 0 } then {
|
||||
|
@ -449,6 +699,12 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
}
|
||||
if { $synth_match } then { continue }
|
||||
|
||||
# If checking a nested type/recursively and we see a closing curly
|
||||
# brace, we're done.
|
||||
if {$recursive_qid != 0 && [string equal $actual_line "\};"]} {
|
||||
break
|
||||
}
|
||||
|
||||
# Unrecognized line.
|
||||
|
||||
if { [llength $list_methods] > 0 } then {
|
||||
|
@ -457,7 +713,13 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
}
|
||||
|
||||
fail "$in_testname // unrecognized line type 2: $actual_line"
|
||||
return
|
||||
queue delete $line_queue
|
||||
return false
|
||||
}
|
||||
|
||||
# Done with the line queue.
|
||||
if {$recursive_qid == 0} {
|
||||
queue delete $line_queue
|
||||
}
|
||||
|
||||
# Check for missing elements.
|
||||
|
@ -465,23 +727,23 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
if { $vbase_match } then {
|
||||
if { [llength $list_vbases] > 0 } then {
|
||||
fail "$in_testname // missing virtual base pointers"
|
||||
return
|
||||
return false
|
||||
}
|
||||
}
|
||||
|
||||
if { [llength $list_fields] > 0 } then {
|
||||
fail "$in_testname // missing fields"
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
if { [llength $list_methods] > 0 } then {
|
||||
fail "$in_testname // missing methods"
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
if {[llength $list_typedefs] > 0} {
|
||||
fail "$in_testname // missing typedefs"
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
# Check the tail.
|
||||
|
@ -490,11 +752,15 @@ proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table { in_
|
|||
if { "$actual_tail" != "$in_tail" } then {
|
||||
cp_check_errata "$in_tail" "$actual_tail" $in_errata_table
|
||||
fail "$in_testname // wrong tail: $actual_tail"
|
||||
return
|
||||
return false
|
||||
}
|
||||
|
||||
# It all worked!
|
||||
# It all worked, but don't call `pass' if we've been called
|
||||
# recursively.
|
||||
|
||||
pass "$in_testname"
|
||||
return
|
||||
if {$recursive_qid == 0} {
|
||||
pass "$in_testname"
|
||||
}
|
||||
|
||||
return true
|
||||
}
|
||||
|
|
|
@ -0,0 +1,164 @@
|
|||
# Copyright 2017 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 file implements some simple data structures in Tcl.
|
||||
|
||||
# A namespace/commands to support a stack.
|
||||
#
|
||||
# To create a stack, call ::Stack::new, recording the returned object ID
|
||||
# for future calls to manipulate the stack object.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# set sid [::Stack::new]
|
||||
# stack push $sid a
|
||||
# stack push $sid b
|
||||
# stack empty $sid; # returns false
|
||||
# stack pop $sid; # returns "b"
|
||||
# stack pop $sid; # returns "a"
|
||||
# stack pop $sid; # errors with "stack is empty"
|
||||
# stack delete $sid1
|
||||
|
||||
namespace eval ::Stack {
|
||||
# A counter used to create object IDs
|
||||
variable num_ 0
|
||||
|
||||
# An array holding all object lists, indexed by object ID.
|
||||
variable data_
|
||||
|
||||
# Create a new stack object, returning its object ID.
|
||||
proc new {} {
|
||||
variable num_
|
||||
variable data_
|
||||
|
||||
set oid [incr num_]
|
||||
set data_($oid) [list]
|
||||
return $oid
|
||||
}
|
||||
|
||||
# Delete the given stack ID.
|
||||
proc delete {oid} {
|
||||
variable data_
|
||||
|
||||
error_if $oid
|
||||
unset data_($oid)
|
||||
}
|
||||
|
||||
# Returns whether the given stack is empty.
|
||||
proc empty {oid} {
|
||||
variable data_
|
||||
|
||||
error_if $oid
|
||||
return [expr {[llength $data_($oid)] == 0}]
|
||||
}
|
||||
|
||||
# Push ELEM onto the stack given by OID.
|
||||
proc push {oid elem} {
|
||||
variable data_
|
||||
|
||||
error_if $oid
|
||||
lappend data_($oid) $elem
|
||||
}
|
||||
|
||||
# Return and pop the top element on OID. It is an error to pop
|
||||
# an empty stack.
|
||||
proc pop {oid} {
|
||||
variable data_
|
||||
|
||||
error_if $oid
|
||||
if {[llength $data_($oid)] == 0} {
|
||||
::error "stack is empty"
|
||||
}
|
||||
set elem [lindex $data_($oid) end]
|
||||
set data_($oid) [lreplace $data_($oid) end end]
|
||||
return $elem
|
||||
}
|
||||
|
||||
# Returns the depth of a given ID.
|
||||
proc length {oid} {
|
||||
variable data_
|
||||
|
||||
error_if $oid
|
||||
return [llength $data_($oid)]
|
||||
}
|
||||
|
||||
# Error handler for invalid object IDs.
|
||||
proc error_if {oid} {
|
||||
variable data_
|
||||
|
||||
if {![info exists data_($oid)]} {
|
||||
::error "object ID $oid does not exist"
|
||||
}
|
||||
}
|
||||
|
||||
# Export procs to be used.
|
||||
namespace export empty push pop new delete length error_if
|
||||
|
||||
# Create an ensemble command to use instead of requiring users
|
||||
# to type namespace proc names.
|
||||
namespace ensemble create -command ::stack
|
||||
}
|
||||
|
||||
# A namespace/commands to support a queue.
|
||||
#
|
||||
# To create a queue, call ::Queue::new, recording the returned queue ID
|
||||
# for future calls to manipulate the queue object.
|
||||
#
|
||||
# Example:
|
||||
#
|
||||
# set qid [::Queue::new]
|
||||
# queue push $qid a
|
||||
# queue push $qid b
|
||||
# queue empty $qid; # returns false
|
||||
# queue pop $qid; # returns "a"
|
||||
# queue pop $qid; # returns "b"
|
||||
# queue pop $qid; # errors with "queue is empty"
|
||||
# queue delete $qid
|
||||
|
||||
namespace eval ::Queue {
|
||||
|
||||
# Remove and return the oldest element in the queue given by OID.
|
||||
# It is an error to pop an empty queue.
|
||||
proc pop {oid} {
|
||||
variable ::Stack::data_
|
||||
|
||||
error_if $oid
|
||||
if {[llength $data_($oid)] == 0} {
|
||||
error "queue is empty"
|
||||
}
|
||||
set elem [lindex $data_($oid) 0]
|
||||
set data_($oid) [lreplace $data_($oid) 0 0]
|
||||
return $elem
|
||||
}
|
||||
|
||||
# "Unpush" ELEM back to the head of the queue given by QID.
|
||||
proc unpush {oid elem} {
|
||||
variable ::Stack::data_
|
||||
|
||||
error_if $oid
|
||||
set data_($oid) [linsert $data_($oid) 0 $elem]
|
||||
}
|
||||
|
||||
# Re-use some common routines from the Stack implementation.
|
||||
namespace import ::Stack::create ::Stack::new ::Stack::empty \
|
||||
::Stack::delete ::Stack::push ::Stack::length ::Stack::error_if
|
||||
|
||||
# Export procs to be used.
|
||||
namespace export new empty push pop new delete length error_if unpush
|
||||
|
||||
# Create an ensemble command to use instead of requiring users
|
||||
# to type namespace proc names.
|
||||
namespace ensemble create -command ::queue
|
||||
}
|
|
@ -42,6 +42,7 @@ const struct type_print_options type_print_raw_options =
|
|||
1, /* raw */
|
||||
1, /* print_methods */
|
||||
1, /* print_typedefs */
|
||||
0, /* print_nested_type_limit */
|
||||
NULL, /* local_typedefs */
|
||||
NULL, /* global_table */
|
||||
NULL /* global_printers */
|
||||
|
@ -54,6 +55,7 @@ static struct type_print_options default_ptype_flags =
|
|||
0, /* raw */
|
||||
1, /* print_methods */
|
||||
1, /* print_typedefs */
|
||||
0, /* print_nested_type_limit */
|
||||
NULL, /* local_typedefs */
|
||||
NULL, /* global_table */
|
||||
NULL /* global_printers */
|
||||
|
@ -79,7 +81,7 @@ struct typedef_hash_table
|
|||
static hashval_t
|
||||
hash_typedef_field (const void *p)
|
||||
{
|
||||
const struct typedef_field *tf = (const struct typedef_field *) p;
|
||||
const struct decl_field *tf = (const struct decl_field *) p;
|
||||
struct type *t = check_typedef (tf->type);
|
||||
|
||||
return htab_hash_string (TYPE_SAFE_NAME (t));
|
||||
|
@ -90,8 +92,8 @@ hash_typedef_field (const void *p)
|
|||
static int
|
||||
eq_typedef_field (const void *a, const void *b)
|
||||
{
|
||||
const struct typedef_field *tfa = (const struct typedef_field *) a;
|
||||
const struct typedef_field *tfb = (const struct typedef_field *) b;
|
||||
const struct decl_field *tfa = (const struct decl_field *) a;
|
||||
const struct decl_field *tfb = (const struct decl_field *) b;
|
||||
|
||||
return types_equal (tfa->type, tfb->type);
|
||||
}
|
||||
|
@ -109,7 +111,7 @@ recursively_update_typedef_hash (struct typedef_hash_table *table,
|
|||
|
||||
for (i = 0; i < TYPE_TYPEDEF_FIELD_COUNT (t); ++i)
|
||||
{
|
||||
struct typedef_field *tdef = &TYPE_TYPEDEF_FIELD (t, i);
|
||||
struct decl_field *tdef = &TYPE_TYPEDEF_FIELD (t, i);
|
||||
void **slot;
|
||||
|
||||
slot = htab_find_slot (table->table, tdef, INSERT);
|
||||
|
@ -137,14 +139,14 @@ add_template_parameters (struct typedef_hash_table *table, struct type *t)
|
|||
|
||||
for (i = 0; i < TYPE_N_TEMPLATE_ARGUMENTS (t); ++i)
|
||||
{
|
||||
struct typedef_field *tf;
|
||||
struct decl_field *tf;
|
||||
void **slot;
|
||||
|
||||
/* We only want type-valued template parameters in the hash. */
|
||||
if (SYMBOL_CLASS (TYPE_TEMPLATE_ARGUMENT (t, i)) != LOC_TYPEDEF)
|
||||
continue;
|
||||
|
||||
tf = XOBNEW (&table->storage, struct typedef_field);
|
||||
tf = XOBNEW (&table->storage, struct decl_field);
|
||||
tf->name = SYMBOL_LINKAGE_NAME (TYPE_TEMPLATE_ARGUMENT (t, i));
|
||||
tf->type = SYMBOL_TYPE (TYPE_TEMPLATE_ARGUMENT (t, i));
|
||||
|
||||
|
@ -262,7 +264,7 @@ find_global_typedef (const struct type_print_options *flags,
|
|||
{
|
||||
char *applied;
|
||||
void **slot;
|
||||
struct typedef_field tf, *new_tf;
|
||||
struct decl_field tf, *new_tf;
|
||||
|
||||
if (flags->global_typedefs == NULL)
|
||||
return NULL;
|
||||
|
@ -273,13 +275,13 @@ find_global_typedef (const struct type_print_options *flags,
|
|||
slot = htab_find_slot (flags->global_typedefs->table, &tf, INSERT);
|
||||
if (*slot != NULL)
|
||||
{
|
||||
new_tf = (struct typedef_field *) *slot;
|
||||
new_tf = (struct decl_field *) *slot;
|
||||
return new_tf->name;
|
||||
}
|
||||
|
||||
/* Put an entry into the hash table now, in case
|
||||
apply_ext_lang_type_printers recurses. */
|
||||
new_tf = XOBNEW (&flags->global_typedefs->storage, struct typedef_field);
|
||||
new_tf = XOBNEW (&flags->global_typedefs->storage, struct decl_field);
|
||||
new_tf->name = NULL;
|
||||
new_tf->type = t;
|
||||
|
||||
|
@ -308,12 +310,12 @@ find_typedef_in_hash (const struct type_print_options *flags, struct type *t)
|
|||
{
|
||||
if (flags->local_typedefs != NULL)
|
||||
{
|
||||
struct typedef_field tf, *found;
|
||||
struct decl_field tf, *found;
|
||||
|
||||
tf.name = NULL;
|
||||
tf.type = t;
|
||||
found = (struct typedef_field *) htab_find (flags->local_typedefs->table,
|
||||
&tf);
|
||||
found = (struct decl_field *) htab_find (flags->local_typedefs->table,
|
||||
&tf);
|
||||
|
||||
if (found != NULL)
|
||||
return found->name;
|
||||
|
@ -703,6 +705,41 @@ show_print_type_typedefs (struct ui_file *file, int from_tty,
|
|||
value);
|
||||
}
|
||||
|
||||
/* Limit on the number of nested type definitions to print or -1 to print
|
||||
all nested type definitions in a class. By default, we do not print
|
||||
nested definitions. */
|
||||
|
||||
static int print_nested_type_limit = 0;
|
||||
|
||||
/* Set how many nested type definitions should be printed by the type
|
||||
printer. */
|
||||
|
||||
static void
|
||||
set_print_type_nested_types (const char *args, int from_tty,
|
||||
struct cmd_list_element *c)
|
||||
{
|
||||
default_ptype_flags.print_nested_type_limit = print_nested_type_limit;
|
||||
}
|
||||
|
||||
/* Show how many nested type definitions the type printer will print. */
|
||||
|
||||
static void
|
||||
show_print_type_nested_types (struct ui_file *file, int from_tty,
|
||||
struct cmd_list_element *c, const char *value)
|
||||
{
|
||||
if (*value == '0')
|
||||
{
|
||||
fprintf_filtered (file,
|
||||
_("Will not print nested types defined in a class\n"));
|
||||
}
|
||||
else
|
||||
{
|
||||
fprintf_filtered (file,
|
||||
_("Will print %s nested types defined in a class\n"),
|
||||
value);
|
||||
}
|
||||
}
|
||||
|
||||
void
|
||||
_initialize_typeprint (void)
|
||||
{
|
||||
|
@ -751,6 +788,16 @@ Show printing of typedefs defined in classes."), NULL,
|
|||
set_print_type_typedefs,
|
||||
show_print_type_typedefs,
|
||||
&setprinttypelist, &showprinttypelist);
|
||||
|
||||
add_setshow_zuinteger_unlimited_cmd ("nested-type-limit", no_class,
|
||||
&print_nested_type_limit,
|
||||
_("\
|
||||
Set the number of recursive nested type definitions to print \
|
||||
(\"unlimited\" or -1 to show all)."), _("\
|
||||
Show the number of recursive nested type definitions to print."), NULL,
|
||||
set_print_type_nested_types,
|
||||
show_print_type_nested_types,
|
||||
&setprinttypelist, &showprinttypelist);
|
||||
}
|
||||
|
||||
/* Print <not allocated> status to stream STREAM. */
|
||||
|
|
|
@ -35,6 +35,9 @@ struct type_print_options
|
|||
/* True means print typedefs in a class. */
|
||||
unsigned int print_typedefs : 1;
|
||||
|
||||
/* The number of nested type definitions to print. -1 == all. */
|
||||
int print_nested_type_limit;
|
||||
|
||||
/* If not NULL, a local typedef hash table used when printing a
|
||||
type. */
|
||||
struct typedef_hash_table *local_typedefs;
|
||||
|
|
Loading…
Reference in New Issue