Browse Source
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".
gdb-8.1-branch
14 changed files with 1684 additions and 86 deletions
@ -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 |
|||
@ -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 |
|||
} |
|||
Loading…
Reference in new issue