1 # This test code is part of GDB, the GNU debugger. 2 3 # Copyright 2003-2024 Free Software Foundation, Inc. 4 5 # This program is free software; you can redistribute it and/or modify 6 # it under the terms of the GNU General Public License as published by 7 # the Free Software Foundation; either version 3 of the License, or 8 # (at your option) any later version. 9 # 10 # This program is distributed in the hope that it will be useful, 11 # but WITHOUT ANY WARRANTY; without even the implied warranty of 12 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the 13 # GNU General Public License for more details. 14 # 15 # You should have received a copy of the GNU General Public License 16 # along with this program. If not, see <http://www.gnu.org/licenses/>. 17 18 load_lib "data-structures.exp" 19 20 # Controls whether detailed logging for cp_test_ptype_class is enabled. 21 # By default, it is not. Enable it to assist with troubleshooting 22 # failed cp_test_ptype_class tests. [Users can simply add the statement 23 # "set debug_cp_ptype_test_class true" after this file is loaded.] 24 25 set ::debug_cp_test_ptype_class false 26 27 # Auxiliary function to check for known problems. 28 # 29 # EXPECTED_STRING is the string expected by the test. 30 # 31 # ACTUAL_STRING is the actual string output by gdb. 32 # 33 # ERRATA_TABLE is a list of lines of the form: 34 # 35 # { expected-string broken-string {eval-block} } 36 # 37 # If there is a line for the given EXPECTED_STRING, and if the 38 # ACTUAL_STRING output by gdb is the same as the BROKEN_STRING in the 39 # table, then I eval the eval-block. 40 41 proc cp_check_errata { expected_string actual_string errata_table } { 42 foreach erratum $errata_table { 43 if { "$expected_string" == [lindex $erratum 0] 44 && "$actual_string" == [lindex $erratum 1] } then { 45 eval [lindex $erratum 2] 46 } 47 } 48 } 49 50 # A convenience procedure for outputting debug info for cp_test_ptype_class 51 # to the log. Set the global variable "debug_cp_test_ptype_class" 52 # to enable logging (to help with debugging failures). 53 54 proc cp_ptype_class_verbose {msg} { 55 global debug_cp_test_ptype_class 56 57 if {$debug_cp_test_ptype_class} { 58 verbose -log $msg 59 } 60 } 61 62 # A namespace to wrap internal procedures. 63 64 namespace eval ::cp_support_internal { 65 66 # A convenience procedure to return the next element of the queue. 67 proc next_line {qid} { 68 set elem {} 69 70 while {$elem == "" && ![queue empty $qid]} { 71 # We make cp_test_ptype_class trim whitespace 72 set elem [queue pop $qid] 73 } 74 75 if {$elem == ""} { 76 cp_ptype_class_verbose "next line element: no more lines" 77 } else { 78 cp_ptype_class_verbose "next line element: \"$elem\"" 79 } 80 return $elem 81 } 82 } 83 84 # Test ptype of a class. Return `true' if the test passes, false otherwise. 85 # 86 # Different C++ compilers produce different output. To accommodate all 87 # the variations listed below, I read the output of "ptype" and process 88 # each line, matching it to the class description given in the 89 # parameters. 90 # 91 # IN_EXP is the expression to use; the appropriate "ptype" invocation 92 # is prepended to it. IN_TESTNAME is the testname for 93 # gdb_test_multiple. If IN_TESTNAME is the empty string, then it 94 # defaults to "ptype IN_EXP". 95 # 96 # IN_KEY is "class" or "struct". For now, I ignore it, and allow either 97 # "class" or "struct" in the output, as long as the access specifiers all 98 # work out okay. 99 # 100 # IN_TAG is the class tag or structure tag. 101 # 102 # IN_CLASS_TABLE is a list of class information. Each entry contains a 103 # keyword and some values. The keywords and their values are: 104 # 105 # { base "base-declaration" } 106 # 107 # the class has a base with the given declaration. 108 # 109 # { vbase "name" } 110 # 111 # the class has a virtual base pointer with the given name. this 112 # is for gcc 2.95.3, which emits ptype entries for the virtual base 113 # pointers. the vbase list includes both indirect and direct 114 # virtual base classes (indeed, a virtual base is usually 115 # indirect), so this information cannot be derived from the base 116 # declarations. 117 # 118 # { field "access" "declaration" } 119 # 120 # the class has a data field with the given access type and the 121 # given declaration. 122 # 123 # { method "access" "declaration" } 124 # 125 # the class has a member function with the given access type 126 # and the given declaration. 127 # 128 # { typedef "access" "declaration" } 129 # 130 # the class has a typedef with the given access type and the 131 # given declaration. 132 # 133 # { type "access" "key" "name" children } 134 # 135 # The class has a nested type definition with the given ACCESS. 136 # KEY is the keyword of the nested type ("enum", "union", "struct", 137 # "class"). 138 # NAME is the (tag) name of the type. 139 # CHILDREN is a list of the type's children. For struct and union keys, 140 # this is simply the same type of list that is normally passed to 141 # this procedure. For enums the list of children should be the 142 # defined enumerators. For unions it is a list of declarations. 143 # NOTE: The enum key will add a regexp to handle optional storage 144 # class specifiers (": unsigned int", e.g.). The caller need not 145 # specify this. 146 # 147 # If you test the same class declaration more than once, you can specify 148 # IN_CLASS_TABLE as "ibid". "ibid" means: look for a previous class 149 # table that had the same IN_KEY and IN_TAG, and re-use that table. 150 # 151 # IN_TAIL is the expected text after the close brace, specifically the "*" 152 # in "struct { ... } *". This is an optional parameter. The default 153 # value is "", for no tail. 154 # 155 # IN_ERRATA_TABLE is a list of errata entries. See cp_check_errata for the 156 # format of the errata table. Note: the errata entries are not subject to 157 # demangler syntax adjustment, so you have to make a bigger table 158 # with lines for each output variation. 159 # 160 # IN_PTYPE_ARG are arguments to pass to ptype. The default is "/r". 161 # 162 # RECURSIVE_QID is used internally to call this procedure recursively 163 # when, e.g., testing nested type definitions. The "ptype" command will 164 # not be sent to GDB and the lines in the queue given by this argument will 165 # be used instead. 166 # 167 # gdb can vary the output of ptype in several ways: 168 # 169 # . CLASS/STRUCT 170 # 171 # The output can start with either "class" or "struct", depending on 172 # what the symbol table reader in gdb decides. This is usually 173 # unrelated to the original source code. 174 # 175 # dwarf-2 debug info distinguishes class/struct, but gdb ignores it 176 # stabs+ debug info does not distinguish class/struct 177 # hp debug info distinguishes class/struct, and gdb honors it 178 # 179 # I tried to accommodate this with regular expressions such as 180 # "((class|struct) A \{ public:|struct A \{)", but that turns into a 181 # hairy mess because of optional private virtual base pointers and 182 # optional public synthetic operators. This is the big reason I gave 183 # up on regular expressions and started parsing the output. 184 # 185 # . REDUNDANT ACCESS SPECIFIER 186 # 187 # In "class { private: ... }" or "struct { public: ... }", gdb might 188 # or might not emit a redundant initial access specifier, depending 189 # on the gcc version. 190 # 191 # . VIRTUAL BASE POINTERS 192 # 193 # If a class has virtual bases, either direct or indirect, the class 194 # will have virtual base pointers. With gcc 2.95.3, gdb prints lines 195 # for these virtual base pointers. This does not happen with gcc 196 # 3.3.4, gcc 3.4.1, or hp acc A.03.45. 197 # 198 # I accept these lines. These lines are optional; but if I see one of 199 # these lines, then I expect to see all of them. 200 # 201 # Note: drow considers printing these lines to be a bug in gdb. 202 # 203 # . SYNTHETIC METHODS 204 # 205 # A C++ compiler may synthesize some methods: an assignment 206 # operator, a copy constructor, a constructor, and a destructor. The 207 # compiler might include debug information for these methods. 208 # 209 # dwarf-2 gdb does not show these methods 210 # stabs+ gdb shows these methods 211 # hp gdb does not show these methods 212 # 213 # I accept these methods. These lines are optional, and any or 214 # all of them might appear, mixed in anywhere in the regular methods. 215 # 216 # With gcc v2, the synthetic copy-ctor and ctor have an additional 217 # "int" parameter at the beginning, the "in-charge" flag. 218 # 219 # . DEMANGLER SYNTAX VARIATIONS 220 # 221 # Different demanglers produce "int foo(void)" versus "int foo()", 222 # "const A&" versus "const A &", and so on. 223 # 224 # TESTED WITH 225 # 226 # gcc 2.95.3 -gdwarf-2 227 # gcc 2.95.3 -gstabs+ 228 # gcc 3.3.4 -gdwarf-2 229 # gcc 3.3.4 -gstabs+ 230 # gcc 3.4.1 -gdwarf-2 231 # gcc 3.4.1 -gstabs+ 232 # gcc HEAD 20040731 -gdwarf-2 233 # gcc HEAD 20040731 -gstabs+ 234 # 235 # TODO 236 # 237 # Tagless structs. 238 # 239 # "A*" versus "A *" and "A&" versus "A &" in user methods. 240 # 241 # -- chastain 2004-08-07 242 243 proc cp_test_ptype_class { in_exp in_testname in_key in_tag in_class_table 244 { in_tail "" } { in_errata_table { } } 245 { in_ptype_arg /r } { recursive_qid 0 } } { 246 global gdb_prompt 247 set wsopt "\[\r\n\t \]*" 248 set hwsopt "\[\t \]*" 249 250 if {$recursive_qid == 0} { 251 # The test name defaults to the command, but without the 252 # arguments, for historical reasons. 253 254 if {"$in_testname" == ""} { set in_testname "ptype $in_exp" } 255 256 set in_command "ptype${in_ptype_arg} $in_exp" 257 } 258 259 # Save class tables in a history array for reuse. 260 261 global cp_class_table_history 262 if {$in_class_table == "ibid"} { 263 if {![info exists cp_class_table_history("$in_key,$in_tag")]} { 264 fail "$in_testname // bad ibid" 265 return false 266 } 267 set in_class_table $cp_class_table_history("$in_key,$in_tag") 268 } else { 269 set cp_class_table_history("$in_key,$in_tag") $in_class_table 270 } 271 272 # Split the class table into separate tables. 273 274 set list_bases { } 275 set list_vbases { } 276 set list_fields { } 277 set list_methods { } 278 set list_typedefs { } 279 set list_types { } 280 set list_enums { } 281 set list_unions { } 282 283 foreach class_line $in_class_table { 284 switch [lindex $class_line 0] { 285 "base" { lappend list_bases [lindex $class_line 1] } 286 "vbase" { lappend list_vbases [lindex $class_line 1] } 287 "field" { lappend list_fields [lrange $class_line 1 2] } 288 "method" { lappend list_methods [lrange $class_line 1 2] } 289 "typedef" { lappend list_typedefs [lrange $class_line 1 2] } 290 "type" { lappend list_types [lrange $class_line 1 4] } 291 default { 292 fail "$in_testname // bad line in class table: $class_line" 293 return false 294 } 295 } 296 } 297 298 # Construct a list of synthetic operators. 299 # These are: { count ccess-type regular-expression }. 300 301 set list_synth { } 302 lappend list_synth [list 0 "public" \ 303 "$in_tag & operator=\\($in_tag const ?&\\);"] 304 lappend list_synth [list 0 "public" \ 305 "$in_tag\\((int,|) ?$in_tag const ?&\\);"] 306 lappend list_synth [list 0 "public" \ 307 "$in_tag\\((int|void|)\\);"] 308 309 # Partial regexp for parsing the struct/class header. 310 set regexp_header "(struct|class)${hwsopt}(\[^ \t\]*)${hwsopt}" 311 append regexp_header "(\\\[with .*\\\]${hwsopt})?((:\[^\{\]*)?)${hwsopt}\{" 312 if {$recursive_qid == 0} { 313 # Actually do the ptype. 314 # For processing the output of ptype, we must get to the prompt. 315 set parse_okay 0 316 set state 0 317 set actual_body "" 318 gdb_test_multiple "$in_command" "$in_testname // parse failed" { 319 -re "type = ${regexp_header}" { 320 if { $state == 0 } { set state 1 } else { set state -1 } 321 set actual_key $expect_out(1,string) 322 set actual_tag $expect_out(2,string) 323 set actual_base_string $expect_out(4,string) 324 exp_continue 325 } 326 -re "^\r\n\}${hwsopt}(\[^\r\n\]*)(?=\r\n)" { 327 if { $state == 1 } { set state 2 } else { set state -2 } 328 set actual_tail $expect_out(1,string) 329 exp_continue 330 } 331 -re "^\r\n(\[^\r\n\]*)(?=\r\n)" { 332 if { $state != 1 } { set $state -3 } 333 if { $actual_body == "" } { 334 set actual_body $expect_out(1,string) 335 } else { 336 append actual_body "\n$expect_out(1,string)" 337 } 338 exp_continue 339 } 340 -re -wrap "" { 341 if { $state == 2 } { 342 set parse_okay 1 343 } 344 } 345 } 346 } else { 347 # The struct/class header by the first element in the line queue. 348 # "Parse" that instead of the output of ptype. 349 set header [cp_support_internal::next_line $recursive_qid] 350 set parse_okay [regexp $regexp_header $header dummy actual_key \ 351 actual_tag dummy actual_base_string] 352 353 if {$parse_okay} { 354 cp_ptype_class_verbose \ 355 "Parsing nested type definition (parse_okay=$parse_okay):" 356 cp_ptype_class_verbose \ 357 "\tactual_key=$actual_key, actual_tag=$actual_tag" 358 cp_ptype_class_verbose "\tactual_base_string=$actual_base_string" 359 } 360 361 # Cannot have a tail with a nested type definition. 362 set actual_tail "" 363 } 364 365 if { ! $parse_okay } { 366 cp_ptype_class_verbose "*** parse failed ***" 367 return false 368 } 369 370 # Check the actual key. It would be nice to require that it match 371 # the input key, but gdb does not support that. For now, accept any 372 # $actual_key as long as the access property of each field/method 373 # matches. 374 375 switch "$actual_key" { 376 "class" { set access "private" } 377 "struct" { set access "public" } 378 default { 379 cp_check_errata "class" "$actual_key" $in_errata_table 380 cp_check_errata "struct" "$actual_key" $in_errata_table 381 fail "$in_testname // wrong key: $actual_key" 382 return false 383 } 384 } 385 386 # Check the actual tag. 387 388 if {"$actual_tag" != "$in_tag"} { 389 cp_check_errata "$in_tag" "$actual_tag" $in_errata_table 390 fail "$in_testname // wrong tag: $actual_tag" 391 return false 392 } 393 394 # Check the actual bases. 395 # First parse them into a list. 396 397 set list_actual_bases { } 398 if {"$actual_base_string" != ""} { 399 regsub "^:${wsopt}" $actual_base_string "" actual_base_string 400 set list_actual_bases [split $actual_base_string ","] 401 } 402 403 # Check the base count. 404 405 if {[llength $list_actual_bases] < [llength $list_bases]} { 406 fail "$in_testname // too few bases" 407 return false 408 } 409 if {[llength $list_actual_bases] > [llength $list_bases]} { 410 fail "$in_testname // too many bases" 411 return false 412 } 413 414 # Check each base. 415 416 foreach actual_base $list_actual_bases { 417 set actual_base [string trim $actual_base] 418 set base [lindex $list_bases 0] 419 if {"$actual_base" != "$base"} { 420 cp_check_errata "$base" "$actual_base" $in_errata_table 421 fail "$in_testname // wrong base: $actual_base" 422 return false 423 } 424 set list_bases [lreplace $list_bases 0 0] 425 } 426 427 # Parse each line in the body. 428 429 set last_was_access 0 430 set vbase_match 0 431 432 if {$recursive_qid == 0} { 433 # Use a queue to hold the lines that will be checked. 434 # This will allow processing below to remove lines from the input 435 # more easily. 436 set line_queue [::Queue::new] 437 foreach l [split $actual_body "\r\n"] { 438 set l [string trim $l] 439 if {$l != ""} { 440 queue push $line_queue $l 441 } 442 } 443 } else { 444 set line_queue $recursive_qid 445 } 446 447 while {![queue empty $line_queue]} { 448 449 # Get the next line. 450 451 set actual_line [cp_support_internal::next_line $line_queue] 452 if {"$actual_line" == ""} { continue } 453 454 # Access specifiers. 455 456 if {[regexp "^(public|protected|private)${wsopt}:\$" "$actual_line" s0 s1]} { 457 set access "$s1" 458 if {$last_was_access} { 459 fail "$in_testname // redundant access specifier" 460 queue delete $line_queue 461 return false 462 } 463 set last_was_access 1 464 continue 465 } else { 466 set last_was_access 0 467 } 468 469 # Optional virtual base pointer. 470 471 if {[llength $list_vbases] > 0} { 472 set vbase [lindex $list_vbases 0] 473 if {[regexp "$vbase \\*(_vb.|_vb\\\$|__vb_)\[0-9\]*$vbase;" $actual_line]} { 474 if {"$access" != "private"} { 475 cp_check_errata "private" "$access" $in_errata_table 476 fail "$in_testname // wrong access specifier for virtual base: $access" 477 queue delete $line_queue 478 return false 479 } 480 set list_vbases [lreplace $list_vbases 0 0] 481 set vbase_match 1 482 continue 483 } 484 } 485 486 # Data field. 487 488 if {[llength $list_fields] > 0} { 489 set field_access [lindex [lindex $list_fields 0] 0] 490 set field_decl [lindex [lindex $list_fields 0] 1] 491 if {$recursive_qid > 0} { 492 cp_ptype_class_verbose "\tactual_line=$actual_line" 493 cp_ptype_class_verbose "\tfield_access=$field_access" 494 cp_ptype_class_verbose "\tfield_decl=$field_decl" 495 cp_ptype_class_verbose "\taccess=$access" 496 } 497 if {"$actual_line" == "$field_decl"} { 498 if {"$access" != "$field_access"} { 499 cp_check_errata "$field_access" "$access" $in_errata_table 500 fail "$in_testname // wrong access specifier for field: $access" 501 queue delete $line_queue 502 return false 503 } 504 set list_fields [lreplace $list_fields 0 0] 505 continue 506 } 507 508 # Data fields must appear before synths and methods. 509 cp_check_errata "$field_decl" "$actual_line" $in_errata_table 510 fail "$in_testname // unrecognized line type 1: $actual_line" 511 queue delete $line_queue 512 return false 513 } 514 515 # Method function. 516 517 if {[llength $list_methods] > 0} { 518 set method_access [lindex [lindex $list_methods 0] 0] 519 set method_decl [lindex [lindex $list_methods 0] 1] 520 if {"$actual_line" == "$method_decl"} { 521 if {"$access" != "$method_access"} { 522 cp_check_errata "$method_access" "$access" $in_errata_table 523 fail "$in_testname // wrong access specifier for method: $access" 524 queue delete $line_queue 525 return false 526 } 527 set list_methods [lreplace $list_methods 0 0] 528 continue 529 } 530 531 # gcc 2.95.3 shows "foo()" as "foo(void)". 532 regsub -all "\\(\\)" $method_decl "(void)" method_decl 533 if {"$actual_line" == "$method_decl"} { 534 if {"$access" != "$method_access"} { 535 cp_check_errata "$method_access" "$access" $in_errata_table 536 fail "$in_testname // wrong access specifier for method: $access" 537 queue delete $line_queue 538 return false 539 } 540 set list_methods [lreplace $list_methods 0 0] 541 continue 542 } 543 } 544 545 # Typedef 546 547 if {[llength $list_typedefs] > 0} { 548 set typedef_access [lindex [lindex $list_typedefs 0] 0] 549 set typedef_decl [lindex [lindex $list_typedefs 0] 1] 550 if {[string equal $actual_line $typedef_decl]} { 551 if {![string equal $access $typedef_access]} { 552 cp_check_errata $typedef_access $access $in_errata_table 553 fail "$in_testname // wrong access specifier for typedef: $access" 554 queue delete $line_queue 555 return false 556 } 557 set list_typedefs [lreplace $list_typedefs 0 0] 558 continue 559 } 560 } 561 562 # Nested type definitions 563 564 if {[llength $list_types] > 0} { 565 cp_ptype_class_verbose "Nested type definition: " 566 lassign [lindex $list_types 0] nested_access nested_key \ 567 nested_name nested_children 568 set msg "nested_access=$nested_access, nested_key=$nested_key, " 569 append msg "nested_name=$nested_name, " 570 append msg "[llength $nested_children] children" 571 cp_ptype_class_verbose $msg 572 573 if {![string equal $access $nested_access]} { 574 cp_check_errata $nested_access $access $in_errata_table 575 set txt "$in_testname // wrong access specifier for " 576 append txt "nested type: $access" 577 fail $txt 578 queue delete $line_queue 579 return false 580 } 581 582 switch $nested_key { 583 enum { 584 set expected_result \ 585 "enum $nested_name (: (unsigned )?int )?\{" 586 foreach c $nested_children { 587 append expected_result "$c, " 588 } 589 set expected_result \ 590 [string trimright $expected_result { ,}] 591 append expected_result "\};" 592 cp_ptype_class_verbose \ 593 "Expecting enum result: $expected_result" 594 if {![regexp -- $expected_result $actual_line]} { 595 set txt "$in_testname // wrong nested type enum" 596 append txt " definition: $actual_line" 597 fail $txt 598 queue delete $line_queue 599 return false 600 } 601 cp_ptype_class_verbose "passed enum $nested_name" 602 } 603 604 union { 605 set expected_result "union $nested_name \{" 606 cp_ptype_class_verbose \ 607 "Expecting union result: $expected_result" 608 if {![string equal $expected_result $actual_line]} { 609 set txt "$in_testname // wrong nested type union" 610 append txt " definition: $actual_line" 611 fail $txt 612 queue delete $line_queue 613 return false 614 } 615 616 # This will be followed by lines for each member of the 617 # union. 618 cp_ptype_class_verbose "matched union name" 619 foreach m $nested_children { 620 set actual_line \ 621 [cp_support_internal::next_line $line_queue] 622 cp_ptype_class_verbose "Expecting union member: $m" 623 if {![string equal $m $actual_line]} { 624 set txt "$in_testname // unexpected union member: " 625 append txt $m 626 fail $txt 627 queue delete $line_queue 628 return false 629 } 630 cp_ptype_class_verbose "matched union child \"$m\"" 631 } 632 633 # Nested union types always end with a trailing curly brace. 634 set actual_line [cp_support_internal::next_line $line_queue] 635 if {![string equal $actual_line "\};"]} { 636 fail "$in_testname // missing closing curly brace" 637 queue delete $line_queue 638 return false 639 } 640 cp_ptype_class_verbose "passed union $nested_name" 641 } 642 643 struct - 644 class { 645 cp_ptype_class_verbose \ 646 "Expecting [llength $nested_children] children" 647 foreach c $nested_children { 648 cp_ptype_class_verbose "\t$c" 649 } 650 # Start by pushing the current line back into the queue 651 # so that the recursive call can parse the class/struct 652 # header. 653 queue unpush $line_queue $actual_line 654 cp_ptype_class_verbose \ 655 "Recursing for type $nested_key $nested_name" 656 if {![cp_test_ptype_class $in_exp $in_testname $nested_key \ 657 $nested_name $nested_children $in_tail \ 658 $in_errata_table $in_ptype_arg $line_queue]} { 659 # The recursive call has already called `fail' and 660 # released the line queue. 661 return false 662 } 663 cp_ptype_class_verbose \ 664 "passed nested type $nested_key $nested_name" 665 } 666 667 default { 668 fail "$in_testname // invalid nested type key: $nested_key" 669 queue delete $line_queue 670 return false 671 } 672 } 673 674 set list_types [lreplace $list_types 0 0] 675 continue 676 } 677 678 # Synthetic operators. These are optional and can be mixed in 679 # with the methods in any order, but duplicates are wrong. 680 # 681 # This test must come after the user methods, so that a user 682 # method which matches a synth-method pattern is treated 683 # properly as a user method. 684 685 set synth_match 0 686 for { set isynth 0 } { $isynth < [llength $list_synth] } { incr isynth } { 687 set synth [lindex $list_synth $isynth] 688 set synth_count [lindex $synth 0] 689 set synth_access [lindex $synth 1] 690 set synth_re [lindex $synth 2] 691 692 if {[regexp "$synth_re" "$actual_line"]} { 693 694 if {"$access" != "$synth_access"} { 695 cp_check_errata "$synth_access" "$access" $in_errata_table 696 fail "$in_testname // wrong access specifier for synthetic operator: $access" 697 queue delete $line_queue 698 return false 699 } 700 701 if {$synth_count > 0} { 702 cp_check_errata "$actual_line" "$actual_line" $in_errata_table 703 fail "$in_testname // duplicate synthetic operator: $actual_line" 704 } 705 706 # Update the count in list_synth. 707 708 incr synth_count 709 set synth [list $synth_count $synth_access "$synth_re"] 710 set list_synth [lreplace $list_synth $isynth $isynth $synth] 711 712 # Match found. 713 714 set synth_match 1 715 break 716 } 717 } 718 if {$synth_match} { continue } 719 720 # If checking a nested type/recursively and we see a closing curly 721 # brace, we're done. 722 if {$recursive_qid != 0 && [string equal $actual_line "\};"]} { 723 break 724 } 725 726 # Unrecognized line. 727 728 if {[llength $list_methods] > 0} { 729 set method_decl [lindex [lindex $list_methods 0] 1] 730 cp_check_errata "$method_decl" "$actual_line" $in_errata_table 731 } 732 733 fail "$in_testname // unrecognized line type 2: $actual_line" 734 queue delete $line_queue 735 return false 736 } 737 738 # Done with the line queue. 739 if {$recursive_qid == 0} { 740 queue delete $line_queue 741 } 742 743 # Check for missing elements. 744 745 if {$vbase_match} { 746 if {[llength $list_vbases] > 0} { 747 fail "$in_testname // missing virtual base pointers" 748 return false 749 } 750 } 751 752 if {[llength $list_fields] > 0} { 753 fail "$in_testname // missing fields" 754 return false 755 } 756 757 if {[llength $list_methods] > 0} { 758 fail "$in_testname // missing methods" 759 return false 760 } 761 762 if {[llength $list_typedefs] > 0} { 763 fail "$in_testname // missing typedefs" 764 return false 765 } 766 767 # Check the tail. 768 769 set actual_tail [string trim $actual_tail] 770 if {"$actual_tail" != "$in_tail"} { 771 cp_check_errata "$in_tail" "$actual_tail" $in_errata_table 772 fail "$in_testname // wrong tail: $actual_tail" 773 return false 774 } 775 776 # It all worked, but don't call `pass' if we've been called 777 # recursively. 778 779 if {$recursive_qid == 0} { 780 pass "$in_testname" 781 } 782 783 return true 784 } 785