1*11efff7fSkettenis# This test code is part of GDB, the GNU debugger. 2*11efff7fSkettenis 3*11efff7fSkettenis# Copyright 2003, 2004 Free Software Foundation, Inc. 4*11efff7fSkettenis 5*11efff7fSkettenis# This program is free software; you can redistribute it and/or modify 6*11efff7fSkettenis# it under the terms of the GNU General Public License as published by 7*11efff7fSkettenis# the Free Software Foundation; either version 2 of the License, or 8*11efff7fSkettenis# (at your option) any later version. 9*11efff7fSkettenis# 10*11efff7fSkettenis# This program is distributed in the hope that it will be useful, 11*11efff7fSkettenis# but WITHOUT ANY WARRANTY; without even the implied warranty of 12*11efff7fSkettenis# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13*11efff7fSkettenis# GNU General Public License for more details. 14*11efff7fSkettenis# 15*11efff7fSkettenis# You should have received a copy of the GNU General Public License 16*11efff7fSkettenis# along with this program; if not, write to the Free Software 17*11efff7fSkettenis# Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA 02111-1307, USA. 18*11efff7fSkettenis 19*11efff7fSkettenis# Auxiliary function to check for known problems. 20*11efff7fSkettenis# 21*11efff7fSkettenis# EXPECTED_STRING is the string expected by the test. 22*11efff7fSkettenis# 23*11efff7fSkettenis# ACTUAL_STRING is the actual string output by gdb. 24*11efff7fSkettenis# 25*11efff7fSkettenis# ERRATA_TABLE is a list of lines of the form: 26*11efff7fSkettenis# 27*11efff7fSkettenis# { expected-string broken-string {eval-block} } 28*11efff7fSkettenis# 29*11efff7fSkettenis# If there is a line for the given EXPECTED_STRING, and if the 30*11efff7fSkettenis# ACTUAL_STRING output by gdb is the same as the BROKEN_STRING in the 31*11efff7fSkettenis# table, then I eval the eval-block. 32*11efff7fSkettenis 33*11efff7fSkettenisproc cp_check_errata { expected_string actual_string errata_table } { 34*11efff7fSkettenis foreach erratum $errata_table { 35*11efff7fSkettenis if { "$expected_string" == [lindex $erratum 0] 36*11efff7fSkettenis && "$actual_string" == [lindex $erratum 1] } then { 37*11efff7fSkettenis eval [lindex $erratum 2] 38*11efff7fSkettenis } 39*11efff7fSkettenis } 40*11efff7fSkettenis} 41*11efff7fSkettenis 42*11efff7fSkettenis# Test ptype of a class. 43*11efff7fSkettenis# 44*11efff7fSkettenis# Different C++ compilers produce different output. To accommodate all 45*11efff7fSkettenis# the variations listed below, I read the output of "ptype" and process 46*11efff7fSkettenis# each line, matching it to the class description given in the 47*11efff7fSkettenis# parameters. 48*11efff7fSkettenis# 49*11efff7fSkettenis# IN_COMMAND and IN_TESTNAME are the command and testname for 50*11efff7fSkettenis# gdb_test_multiple. If IN_TESTNAME is the empty string, then it 51*11efff7fSkettenis# defaults to IN_COMMAND. 52*11efff7fSkettenis# 53*11efff7fSkettenis# IN_KEY is "class" or "struct". For now, I ignore it, and allow either 54*11efff7fSkettenis# "class" or "struct" in the output, as long as the access specifiers all 55*11efff7fSkettenis# work out okay. 56*11efff7fSkettenis# 57*11efff7fSkettenis# IN_TAG is the class tag or structure tag. 58*11efff7fSkettenis# 59*11efff7fSkettenis# IN_CLASS_TABLE is a list of class information. Each entry contains a 60*11efff7fSkettenis# keyword and some values. The keywords and their values are: 61*11efff7fSkettenis# 62*11efff7fSkettenis# { base "base-declaration" } 63*11efff7fSkettenis# 64*11efff7fSkettenis# the class has a base with the given declaration. 65*11efff7fSkettenis# 66*11efff7fSkettenis# { vbase "name" } 67*11efff7fSkettenis# 68*11efff7fSkettenis# the class has a virtual base pointer with the given name. this 69*11efff7fSkettenis# is for gcc 2.95.3, which emits ptype entries for the virtual base 70*11efff7fSkettenis# pointers. the vbase list includes both indirect and direct 71*11efff7fSkettenis# virtual base classes (indeed, a virtual base is usually 72*11efff7fSkettenis# indirect), so this information cannot be derived from the base 73*11efff7fSkettenis# declarations. 74*11efff7fSkettenis# 75*11efff7fSkettenis# { field "access" "declaration" } 76*11efff7fSkettenis# 77*11efff7fSkettenis# the class has a data field with the given access type and the 78*11efff7fSkettenis# given declaration. 79*11efff7fSkettenis# 80*11efff7fSkettenis# { method "access" "declaration" } 81*11efff7fSkettenis# 82*11efff7fSkettenis# the class has a member function with the given access type 83*11efff7fSkettenis# and the given declaration. 84*11efff7fSkettenis# 85*11efff7fSkettenis# If you test the same class declaration more than once, you can specify 86*11efff7fSkettenis# IN_CLASS_TABLE as "ibid". "ibid" means: look for a previous class 87*11efff7fSkettenis# table that had the same IN_KEY and IN_TAG, and re-use that table. 88*11efff7fSkettenis# 89*11efff7fSkettenis# IN_TAIL is the expected text after the close brace, specifically the "*" 90*11efff7fSkettenis# in "struct { ... } *". This is an optional parameter. The default 91*11efff7fSkettenis# value is "", for no tail. 92*11efff7fSkettenis# 93*11efff7fSkettenis# IN_ERRATA_TABLE is a list of errata entries. See cp_check_errata for the 94*11efff7fSkettenis# format of the errata table. Note: the errata entries are not subject to 95*11efff7fSkettenis# demangler syntax adjustment, so you have to make a bigger table 96*11efff7fSkettenis# with lines for each output variation. 97*11efff7fSkettenis# 98*11efff7fSkettenis# gdb can vary the output of ptype in several ways: 99*11efff7fSkettenis# 100*11efff7fSkettenis# . CLASS/STRUCT 101*11efff7fSkettenis# 102*11efff7fSkettenis# The output can start with either "class" or "struct", depending on 103*11efff7fSkettenis# what the symbol table reader in gdb decides. This is usually 104*11efff7fSkettenis# unrelated to the original source code. 105*11efff7fSkettenis# 106*11efff7fSkettenis# dwarf-2 debug info distinguishes class/struct, but gdb ignores it 107*11efff7fSkettenis# stabs+ debug info does not distinguish class/struct 108*11efff7fSkettenis# hp debug info distinguishes class/struct, and gdb honors it 109*11efff7fSkettenis# 110*11efff7fSkettenis# I tried to accommodate this with regular expressions such as 111*11efff7fSkettenis# "((class|struct) A \{ public:|struct A \{)", but that turns into a 112*11efff7fSkettenis# hairy mess because of optional private virtual base pointers and 113*11efff7fSkettenis# optional public synthetic operators. This is the big reason I gave 114*11efff7fSkettenis# up on regular expressions and started parsing the output. 115*11efff7fSkettenis# 116*11efff7fSkettenis# . REDUNDANT ACCESS SPECIFIER 117*11efff7fSkettenis# 118*11efff7fSkettenis# In "class { private: ... }" or "struct { public: ... }", gdb might 119*11efff7fSkettenis# or might not emit a redundant initial access specifier, depending 120*11efff7fSkettenis# on the gcc version. 121*11efff7fSkettenis# 122*11efff7fSkettenis# . VIRTUAL BASE POINTERS 123*11efff7fSkettenis# 124*11efff7fSkettenis# If a class has virtual bases, either direct or indirect, the class 125*11efff7fSkettenis# will have virtual base pointers. With gcc 2.95.3, gdb prints lines 126*11efff7fSkettenis# for these virtual base pointers. This does not happen with gcc 127*11efff7fSkettenis# 3.3.4, gcc 3.4.1, or hp acc A.03.45. 128*11efff7fSkettenis# 129*11efff7fSkettenis# I accept these lines. These lines are optional; but if I see one of 130*11efff7fSkettenis# these lines, then I expect to see all of them. 131*11efff7fSkettenis# 132*11efff7fSkettenis# Note: drow considers printing these lines to be a bug in gdb. 133*11efff7fSkettenis# 134*11efff7fSkettenis# . SYNTHETIC METHODS 135*11efff7fSkettenis# 136*11efff7fSkettenis# A C++ compiler may synthesize some methods: an assignment 137*11efff7fSkettenis# operator, a copy constructor, a constructor, and a destructor. The 138*11efff7fSkettenis# compiler might include debug information for these methods. 139*11efff7fSkettenis# 140*11efff7fSkettenis# dwarf-2 gdb does not show these methods 141*11efff7fSkettenis# stabs+ gdb shows these methods 142*11efff7fSkettenis# hp gdb does not show these methods 143*11efff7fSkettenis# 144*11efff7fSkettenis# I accept these methods. These lines are optional, and any or 145*11efff7fSkettenis# all of them might appear, mixed in anywhere in the regular methods. 146*11efff7fSkettenis# 147*11efff7fSkettenis# With gcc v2, the synthetic copy-ctor and ctor have an additional 148*11efff7fSkettenis# "int" parameter at the beginning, the "in-charge" flag. 149*11efff7fSkettenis# 150*11efff7fSkettenis# . DEMANGLER SYNTAX VARIATIONS 151*11efff7fSkettenis# 152*11efff7fSkettenis# Different demanglers produce "int foo(void)" versus "int foo()", 153*11efff7fSkettenis# "const A&" versus "const A &", and so on. 154*11efff7fSkettenis# 155*11efff7fSkettenis# TESTED WITH 156*11efff7fSkettenis# 157*11efff7fSkettenis# gcc 2.95.3 -gdwarf-2 158*11efff7fSkettenis# gcc 2.95.3 -gstabs+ 159*11efff7fSkettenis# gcc 3.3.4 -gdwarf-2 160*11efff7fSkettenis# gcc 3.3.4 -gstabs+ 161*11efff7fSkettenis# gcc 3.4.1 -gdwarf-2 162*11efff7fSkettenis# gcc 3.4.1 -gstabs+ 163*11efff7fSkettenis# gcc HEAD 20040731 -gdwarf-2 164*11efff7fSkettenis# gcc HEAD 20040731 -gstabs+ 165*11efff7fSkettenis# 166*11efff7fSkettenis# TODO 167*11efff7fSkettenis# 168*11efff7fSkettenis# Tagless structs. 169*11efff7fSkettenis# 170*11efff7fSkettenis# "A*" versus "A *" and "A&" versus "A &" in user methods. 171*11efff7fSkettenis# 172*11efff7fSkettenis# Test with hp ACC. 173*11efff7fSkettenis# 174*11efff7fSkettenis# -- chastain 2004-08-07 175*11efff7fSkettenis 176*11efff7fSkettenisproc cp_test_ptype_class { in_command in_testname in_key in_tag in_class_table { in_tail "" } { in_errata_table { } } } { 177*11efff7fSkettenis global gdb_prompt 178*11efff7fSkettenis set wsopt "\[\r\n\t \]*" 179*11efff7fSkettenis 180*11efff7fSkettenis # The test name defaults to the command. 181*11efff7fSkettenis 182*11efff7fSkettenis if { "$in_testname" == "" } then { set in_testname "$in_command" } 183*11efff7fSkettenis 184*11efff7fSkettenis # Save class tables in a history array for reuse. 185*11efff7fSkettenis 186*11efff7fSkettenis global cp_class_table_history 187*11efff7fSkettenis if { $in_class_table == "ibid" } then { 188*11efff7fSkettenis if { ! [info exists cp_class_table_history("$in_key,$in_tag") ] } then { 189*11efff7fSkettenis fail "$in_testname // bad ibid" 190*11efff7fSkettenis return 191*11efff7fSkettenis } 192*11efff7fSkettenis set in_class_table $cp_class_table_history("$in_key,$in_tag") 193*11efff7fSkettenis } else { 194*11efff7fSkettenis set cp_class_table_history("$in_key,$in_tag") $in_class_table 195*11efff7fSkettenis } 196*11efff7fSkettenis 197*11efff7fSkettenis # Split the class table into separate tables. 198*11efff7fSkettenis 199*11efff7fSkettenis set list_bases { } 200*11efff7fSkettenis set list_vbases { } 201*11efff7fSkettenis set list_fields { } 202*11efff7fSkettenis set list_methods { } 203*11efff7fSkettenis 204*11efff7fSkettenis foreach class_line $in_class_table { 205*11efff7fSkettenis switch [lindex $class_line 0] { 206*11efff7fSkettenis "base" { lappend list_bases [lindex $class_line 1] } 207*11efff7fSkettenis "vbase" { lappend list_vbases [lindex $class_line 1] } 208*11efff7fSkettenis "field" { lappend list_fields [lrange $class_line 1 2] } 209*11efff7fSkettenis "method" { lappend list_methods [lrange $class_line 1 2] } 210*11efff7fSkettenis default { fail "$in_testname // bad line in class table: $class_line"; return; } 211*11efff7fSkettenis } 212*11efff7fSkettenis } 213*11efff7fSkettenis 214*11efff7fSkettenis # Construct a list of synthetic operators. 215*11efff7fSkettenis # These are: { count ccess-type regular-expression }. 216*11efff7fSkettenis 217*11efff7fSkettenis set list_synth { } 218*11efff7fSkettenis lappend list_synth [list 0 "public" "$in_tag & operator=\\($in_tag const ?&\\);"] 219*11efff7fSkettenis lappend list_synth [list 0 "public" "$in_tag\\((int,|) ?$in_tag const ?&\\);"] 220*11efff7fSkettenis lappend list_synth [list 0 "public" "$in_tag\\((int|void|)\\);"] 221*11efff7fSkettenis 222*11efff7fSkettenis # Actually do the ptype. 223*11efff7fSkettenis 224*11efff7fSkettenis set parse_okay 0 225*11efff7fSkettenis gdb_test_multiple "$in_command" "$in_testname // parse failed" { 226*11efff7fSkettenis -re "type = (struct|class)${wsopt}(\[A-Za-z0-9_\]*)${wsopt}((:\[^\{\]*)?)${wsopt}\{(.*)\}${wsopt}(\[^\r\n\]*)\[\r\n\]+$gdb_prompt $" { 227*11efff7fSkettenis set parse_okay 1 228*11efff7fSkettenis set actual_key $expect_out(1,string) 229*11efff7fSkettenis set actual_tag $expect_out(2,string) 230*11efff7fSkettenis set actual_base_string $expect_out(3,string) 231*11efff7fSkettenis set actual_body $expect_out(5,string) 232*11efff7fSkettenis set actual_tail $expect_out(6,string) 233*11efff7fSkettenis } 234*11efff7fSkettenis } 235*11efff7fSkettenis if { ! $parse_okay } then { return } 236*11efff7fSkettenis 237*11efff7fSkettenis # Check the actual key. It would be nice to require that it match 238*11efff7fSkettenis # the input key, but gdb does not support that. For now, accept any 239*11efff7fSkettenis # $actual_key as long as the access property of each field/method 240*11efff7fSkettenis # matches. 241*11efff7fSkettenis 242*11efff7fSkettenis switch "$actual_key" { 243*11efff7fSkettenis "class" { set access "private" } 244*11efff7fSkettenis "struct" { set access "public" } 245*11efff7fSkettenis default { 246*11efff7fSkettenis cp_check_errata "class" "$actual_key" $in_errata_table 247*11efff7fSkettenis cp_check_errata "struct" "$actual_key" $in_errata_table 248*11efff7fSkettenis fail "$in_testname // wrong key: $actual_key" 249*11efff7fSkettenis return 250*11efff7fSkettenis } 251*11efff7fSkettenis } 252*11efff7fSkettenis 253*11efff7fSkettenis # Check the actual tag. 254*11efff7fSkettenis 255*11efff7fSkettenis if { "$actual_tag" != "$in_tag" } then { 256*11efff7fSkettenis cp_check_errata "$in_tag" "$actual_tag" $in_errata_table 257*11efff7fSkettenis fail "$in_testname // wrong tag: $actual_tag" 258*11efff7fSkettenis return 259*11efff7fSkettenis } 260*11efff7fSkettenis 261*11efff7fSkettenis # Check the actual bases. 262*11efff7fSkettenis # First parse them into a list. 263*11efff7fSkettenis 264*11efff7fSkettenis set list_actual_bases { } 265*11efff7fSkettenis if { "$actual_base_string" != "" } then { 266*11efff7fSkettenis regsub "^:${wsopt}" $actual_base_string "" actual_base_string 267*11efff7fSkettenis set list_actual_bases [split $actual_base_string ","] 268*11efff7fSkettenis } 269*11efff7fSkettenis 270*11efff7fSkettenis # Check the base count. 271*11efff7fSkettenis 272*11efff7fSkettenis if { [llength $list_actual_bases] < [llength $list_bases] } then { 273*11efff7fSkettenis fail "$in_testname // too few bases" 274*11efff7fSkettenis return 275*11efff7fSkettenis } 276*11efff7fSkettenis if { [llength $list_actual_bases] > [llength $list_bases] } then { 277*11efff7fSkettenis fail "$in_testname // too many bases" 278*11efff7fSkettenis return 279*11efff7fSkettenis } 280*11efff7fSkettenis 281*11efff7fSkettenis # Check each base. 282*11efff7fSkettenis 283*11efff7fSkettenis foreach actual_base $list_actual_bases { 284*11efff7fSkettenis set actual_base [string trim $actual_base] 285*11efff7fSkettenis set base [lindex $list_bases 0] 286*11efff7fSkettenis if { "$actual_base" != "$base" } then { 287*11efff7fSkettenis cp_check_errata "$base" "$actual_base" $in_errata_table 288*11efff7fSkettenis fail "$in_testname // wrong base: $actual_base" 289*11efff7fSkettenis return 290*11efff7fSkettenis } 291*11efff7fSkettenis set list_bases [lreplace $list_bases 0 0] 292*11efff7fSkettenis } 293*11efff7fSkettenis 294*11efff7fSkettenis # Parse each line in the body. 295*11efff7fSkettenis 296*11efff7fSkettenis set last_was_access 0 297*11efff7fSkettenis set vbase_match 0 298*11efff7fSkettenis 299*11efff7fSkettenis foreach actual_line [split $actual_body "\r\n"] { 300*11efff7fSkettenis 301*11efff7fSkettenis # Chomp the line. 302*11efff7fSkettenis 303*11efff7fSkettenis set actual_line [string trim $actual_line] 304*11efff7fSkettenis if { "$actual_line" == "" } then { continue } 305*11efff7fSkettenis 306*11efff7fSkettenis # Access specifiers. 307*11efff7fSkettenis 308*11efff7fSkettenis if { [regexp "^(public|protected|private)${wsopt}:\$" "$actual_line" s0 s1] } then { 309*11efff7fSkettenis set access "$s1" 310*11efff7fSkettenis if { $last_was_access } then { 311*11efff7fSkettenis fail "$in_testname // redundant access specifier" 312*11efff7fSkettenis return 313*11efff7fSkettenis } 314*11efff7fSkettenis set last_was_access 1 315*11efff7fSkettenis continue 316*11efff7fSkettenis } else { 317*11efff7fSkettenis set last_was_access 0 318*11efff7fSkettenis } 319*11efff7fSkettenis 320*11efff7fSkettenis # Optional virtual base pointer. 321*11efff7fSkettenis 322*11efff7fSkettenis if { [ llength $list_vbases ] > 0 } then { 323*11efff7fSkettenis set vbase [lindex $list_vbases 0] 324*11efff7fSkettenis if { [ regexp "$vbase \\*(_vb.|_vb\\\$|__vb_)\[0-9\]*$vbase;" $actual_line ] } then { 325*11efff7fSkettenis if { "$access" != "private" } then { 326*11efff7fSkettenis cp_check_errata "private" "$access" $in_errata_table 327*11efff7fSkettenis fail "$in_testname // wrong access specifier for virtual base: $access" 328*11efff7fSkettenis return 329*11efff7fSkettenis } 330*11efff7fSkettenis set list_vbases [lreplace $list_vbases 0 0] 331*11efff7fSkettenis set vbase_match 1 332*11efff7fSkettenis continue 333*11efff7fSkettenis } 334*11efff7fSkettenis } 335*11efff7fSkettenis 336*11efff7fSkettenis # Data field. 337*11efff7fSkettenis 338*11efff7fSkettenis if { [llength $list_fields] > 0 } then { 339*11efff7fSkettenis set field_access [lindex [lindex $list_fields 0] 0] 340*11efff7fSkettenis set field_decl [lindex [lindex $list_fields 0] 1] 341*11efff7fSkettenis if { "$actual_line" == "$field_decl" } then { 342*11efff7fSkettenis if { "$access" != "$field_access" } then { 343*11efff7fSkettenis cp_check_errata "$field_access" "$access" $in_errata_table 344*11efff7fSkettenis fail "$in_testname // wrong access specifier for field: $access" 345*11efff7fSkettenis return 346*11efff7fSkettenis } 347*11efff7fSkettenis set list_fields [lreplace $list_fields 0 0] 348*11efff7fSkettenis continue 349*11efff7fSkettenis } 350*11efff7fSkettenis 351*11efff7fSkettenis # Data fields must appear before synths and methods. 352*11efff7fSkettenis cp_check_errata "$field_decl" "$actual_line" $in_errata_table 353*11efff7fSkettenis fail "$in_testname // unrecognized line type 1: $actual_line" 354*11efff7fSkettenis return 355*11efff7fSkettenis } 356*11efff7fSkettenis 357*11efff7fSkettenis # Method function. 358*11efff7fSkettenis 359*11efff7fSkettenis if { [llength $list_methods] > 0 } then { 360*11efff7fSkettenis set method_access [lindex [lindex $list_methods 0] 0] 361*11efff7fSkettenis set method_decl [lindex [lindex $list_methods 0] 1] 362*11efff7fSkettenis if { "$actual_line" == "$method_decl" } then { 363*11efff7fSkettenis if { "$access" != "$method_access" } then { 364*11efff7fSkettenis cp_check_errata "$method_access" "$access" $in_errata_table 365*11efff7fSkettenis fail "$in_testname // wrong access specifier for method: $access" 366*11efff7fSkettenis return 367*11efff7fSkettenis } 368*11efff7fSkettenis set list_methods [lreplace $list_methods 0 0] 369*11efff7fSkettenis continue 370*11efff7fSkettenis } 371*11efff7fSkettenis 372*11efff7fSkettenis # gcc 2.95.3 shows "foo()" as "foo(void)". 373*11efff7fSkettenis regsub -all "\\(\\)" $method_decl "(void)" method_decl 374*11efff7fSkettenis if { "$actual_line" == "$method_decl" } then { 375*11efff7fSkettenis if { "$access" != "$method_access" } then { 376*11efff7fSkettenis cp_check_errata "$method_access" "$access" $in_errata_table 377*11efff7fSkettenis fail "$in_testname // wrong access specifier for method: $access" 378*11efff7fSkettenis return 379*11efff7fSkettenis } 380*11efff7fSkettenis set list_methods [lreplace $list_methods 0 0] 381*11efff7fSkettenis continue 382*11efff7fSkettenis } 383*11efff7fSkettenis } 384*11efff7fSkettenis 385*11efff7fSkettenis # Synthetic operators. These are optional and can be mixed in 386*11efff7fSkettenis # with the methods in any order, but duplicates are wrong. 387*11efff7fSkettenis # 388*11efff7fSkettenis # This test must come after the user methods, so that a user 389*11efff7fSkettenis # method which matches a synth-method pattern is treated 390*11efff7fSkettenis # properly as a user method. 391*11efff7fSkettenis 392*11efff7fSkettenis set synth_match 0 393*11efff7fSkettenis for { set isynth 0 } { $isynth < [llength $list_synth] } { incr isynth } { 394*11efff7fSkettenis set synth [lindex $list_synth $isynth] 395*11efff7fSkettenis set synth_count [lindex $synth 0] 396*11efff7fSkettenis set synth_access [lindex $synth 1] 397*11efff7fSkettenis set synth_re [lindex $synth 2] 398*11efff7fSkettenis 399*11efff7fSkettenis if { [ regexp "$synth_re" "$actual_line" ] } then { 400*11efff7fSkettenis 401*11efff7fSkettenis if { "$access" != "$synth_access" } then { 402*11efff7fSkettenis cp_check_errata "$synth_access" "$access" $in_errata_table 403*11efff7fSkettenis fail "$in_testname // wrong access specifier for synthetic operator: $access" 404*11efff7fSkettenis return 405*11efff7fSkettenis } 406*11efff7fSkettenis 407*11efff7fSkettenis if { $synth_count > 0 } then { 408*11efff7fSkettenis cp_check_errata "$actual_line" "$actual_line" $in_errata_table 409*11efff7fSkettenis fail "$in_testname // duplicate synthetic operator: $actual_line" 410*11efff7fSkettenis } 411*11efff7fSkettenis 412*11efff7fSkettenis # Update the count in list_synth. 413*11efff7fSkettenis 414*11efff7fSkettenis incr synth_count 415*11efff7fSkettenis set synth [list $synth_count $synth_access "$synth_re"] 416*11efff7fSkettenis set list_synth [lreplace $list_synth $isynth $isynth $synth] 417*11efff7fSkettenis 418*11efff7fSkettenis # Match found. 419*11efff7fSkettenis 420*11efff7fSkettenis set synth_match 1 421*11efff7fSkettenis break 422*11efff7fSkettenis } 423*11efff7fSkettenis } 424*11efff7fSkettenis if { $synth_match } then { continue } 425*11efff7fSkettenis 426*11efff7fSkettenis # Unrecognized line. 427*11efff7fSkettenis 428*11efff7fSkettenis if { [llength $list_methods] > 0 } then { 429*11efff7fSkettenis set method_decl [lindex [lindex $list_methods 0] 1] 430*11efff7fSkettenis cp_check_errata "$method_decl" "$actual_line" $in_errata_table 431*11efff7fSkettenis } 432*11efff7fSkettenis 433*11efff7fSkettenis fail "$in_testname // unrecognized line type 2: $actual_line" 434*11efff7fSkettenis return 435*11efff7fSkettenis } 436*11efff7fSkettenis 437*11efff7fSkettenis # Check for missing elements. 438*11efff7fSkettenis 439*11efff7fSkettenis if { $vbase_match } then { 440*11efff7fSkettenis if { [llength $list_vbases] > 0 } then { 441*11efff7fSkettenis fail "$in_testname // missing virtual base pointers" 442*11efff7fSkettenis return 443*11efff7fSkettenis } 444*11efff7fSkettenis } 445*11efff7fSkettenis 446*11efff7fSkettenis if { [llength $list_fields] > 0 } then { 447*11efff7fSkettenis fail "$in_testname // missing fields" 448*11efff7fSkettenis return 449*11efff7fSkettenis } 450*11efff7fSkettenis 451*11efff7fSkettenis if { [llength $list_methods] > 0 } then { 452*11efff7fSkettenis fail "$in_testname // missing methods" 453*11efff7fSkettenis return 454*11efff7fSkettenis } 455*11efff7fSkettenis 456*11efff7fSkettenis # Check the tail. 457*11efff7fSkettenis 458*11efff7fSkettenis set actual_tail [string trim $actual_tail] 459*11efff7fSkettenis if { "$actual_tail" != "$in_tail" } then { 460*11efff7fSkettenis cp_check_errata "$in_tail" "$actual_tail" $in_errata_table 461*11efff7fSkettenis fail "$in_testname // wrong tail: $actual_tail" 462*11efff7fSkettenis return 463*11efff7fSkettenis } 464*11efff7fSkettenis 465*11efff7fSkettenis # It all worked! 466*11efff7fSkettenis 467*11efff7fSkettenis pass "$in_testname" 468*11efff7fSkettenis return 469*11efff7fSkettenis} 470