Home | History | Annotate | Line # | Download | only in gdb.cp
pass-by-ref.exp revision 1.10
      1 # Copyright 2007-2023 Free Software Foundation, Inc.
      2 
      3 # This program is free software; you can redistribute it and/or modify
      4 # it under the terms of the GNU General Public License as published by
      5 # the Free Software Foundation; either version 3 of the License, or
      6 # (at your option) any later version.
      7 #
      8 # This program is distributed in the hope that it will be useful,
      9 # but WITHOUT ANY WARRANTY; without even the implied warranty of
     10 # MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
     11 # GNU General Public License for more details.
     12 #
     13 # You should have received a copy of the GNU General Public License
     14 # along with this program.  If not, see <http://www.gnu.org/licenses/>.
     15 
     16 # Check that GDB can call C++ functions whose parameters have
     17 # object type, and are either passed by value or implicitly by reference.
     18 #
     19 # Suppose F is a function that has a call-by-value parameter whose
     20 # type is class C.  When calling F with an argument A, a copy of A should
     21 # be created and passed to F.  If C is a trivially-copyable type, A can
     22 # be copied by a straightforward memory copy.  However, roughly speaking,
     23 # if C has a user-defined copy constructor and/or a user-defined
     24 # destructor, the copy ctor should be used to initialize the copy of A
     25 # before calling F, and a reference to that copy is passed to F.  After
     26 # the function returns, the destructor should be called to destruct the
     27 # copy.  In this case, C is said to be a 'pass-by-reference' type.
     28 # Determining whether C is pass-by-ref depends on
     29 # how the copy ctor, destructor, and the move ctor of C are defined.
     30 # First of all, C is not copy constructible if its copy constructor is
     31 # explicitly or implicitly deleted.  In this case, it would be illegal
     32 # to pass values of type C to a function.  C is pass-by-value, if all of
     33 # its copy ctor, dtor, and move ctor are trivially defined.
     34 # Otherwise, it is pass-by-ref.
     35 #
     36 # To cover the many possible combinations, this test generates classes
     37 # that contain three special functions:
     38 #   (1) a copy constructor,
     39 #   (2) a destructor, and
     40 #   (3) a move constructor.
     41 # A special function is in one of the following states:
     42 #  * explicit: The function is explicitly defined by the user.
     43 #  * defaultedIn: The function is defaulted inside the class decl,
     44 #      using the 'default' keyword.
     45 #  * defaultedOut: The function is declared inside the class decl,
     46 #      and defaulted outside using the 'default' keyword.
     47 #  * deleted: The function is explicitly deleted by the user,
     48 #      using the 'delete' keyword.
     49 #  * absent: The function is not declared by the user (i.e. it does not
     50 #      exist in the source.  The compiler generates (or deletes) the
     51 #      definition in this case.
     52 #
     53 # The C++ ABI decides if a class is pass-by-value or pass-by-ref
     54 # (i.e.  trivially copyable or not) first at the language level, based
     55 # on the state of the special functions.  Then, at the target level, a
     56 # class may be determined to be pass-by-ref because of its size
     57 # (e.g.  if it is too large to fit on registers).  For this reason, this
     58 # test generates both a small and a large version for the same
     59 # combination of special function states.
     60 #
     61 # A class is not trivially-copyable if a base class or a field is not
     62 # trivially-copyable, even though the class definition itself seems
     63 # trivial.  To test these cases, we also generate derived classes and
     64 # container classes.
     65 #
     66 # The generated code is placed in the test output directory.
     67 #
     68 # The companion test file pass-by-ref-2.exp also contains
     69 # manually-written cases.
     70 
     71 if {[skip_cplus_tests]} {
     72     untested "c++ test skipped"
     73     return
     74 }
     75 
     76 # The program source is generated in the output directory.
     77 # We use standard_testfile here to set convenience variables.
     78 standard_testfile .cc
     79 
     80 # Some constant values used when generating the source
     81 
     82 set SMALL    2
     83 set LARGE    150
     84 set ORIGINAL 2
     85 set CUSTOM   3
     86 set ADDED    4
     87 set TRACE    5
     88 
     89 
     90 # Return 1 if the class whose special function states are STATES
     91 # is copyable.  Otherwise return 0.
     92 
     93 proc is_copy_constructible { states } {
     94     set cctor [lindex $states 0]
     95     set dtor  [lindex $states 1]
     96     set mctor [lindex $states 2]
     97 
     98     if {$cctor == "deleted" || ($cctor == "absent" && $mctor != "absent")} {
     99 	return 0
    100     }
    101     return 1
    102 }
    103 
    104 # Generate a declaration and an out-of-class definition for a function
    105 # with the provided signature.  The STATE should be one of the following:
    106 # - explicit, defaultedIn, defaultedOut, deleted, absent
    107 
    108 proc generate_member_function { classname signature length state } {
    109     set declaration ""
    110     set definition ""
    111 
    112     global CUSTOM
    113     global TRACE
    114 
    115     switch $state {
    116 	explicit {
    117 	    set declaration "$signature;\n"
    118 	    set definition "$classname\:\:$signature
    119                             {
    120                               data\[0\] = $CUSTOM;
    121                               data\[[expr $length - 1]\] = $CUSTOM;
    122                               tracer = $TRACE;
    123                             }\n"
    124 	}
    125 	defaultedIn {
    126 	    set declaration "$signature = default;\n"
    127 	}
    128 	defaultedOut {
    129 	    set declaration "$signature;\n"
    130 	    set definition "$classname\:\:$signature = default;\n"
    131 	}
    132 	deleted {
    133 	    set declaration "$signature = delete;\n"
    134 	}
    135 	default {
    136 	    # function is not user-defined in this case
    137 	}
    138     }
    139 
    140     return [list $declaration $definition]
    141 }
    142 
    143 # Generate a C++ class with the given CLASSNAME and LENGTH-many
    144 # integer elements.  The STATES is an array of 3 items
    145 # containing the desired state of the special functions
    146 # in this order:
    147 # copy constructor, destructor, move constructor
    148 
    149 proc generate_class { classname length states } {
    150     set declarations ""
    151     set definitions ""
    152     set classname "${classname}_[join $states _]"
    153 
    154     for {set i 0} {$i < [llength $states]} {incr i} {
    155 	set sig ""
    156 	switch $i {
    157 	    0 {set sig "$classname (const $classname \&rhs)"}
    158 	    1 {set sig "\~$classname (void)"}
    159 	    2 {set sig "$classname ($classname \&\&rhs)"}
    160 	}
    161 
    162 	set state [lindex $states $i]
    163 	set code [generate_member_function $classname $sig $length $state]
    164 	append declarations [lindex $code 0]
    165 	append definitions [lindex $code 1]
    166     }
    167 
    168     global ORIGINAL
    169 
    170     return "
    171     /*** C++ class $classname ***/
    172     class ${classname} {
    173     public:
    174         $classname (void);
    175         $declarations
    176 
    177         int data\[$length\];
    178     };
    179 
    180     $classname\:\:$classname (void)
    181     {
    182         data\[0\] = $ORIGINAL;
    183         data\[[expr $length - 1]\] = $ORIGINAL;
    184     }
    185 
    186     $definitions
    187 
    188     $classname ${classname}_var; /* global var */
    189 
    190     template int cbv<$classname> ($classname arg);"
    191 }
    192 
    193 # Generate a small C++ class
    194 
    195 proc generate_small_class { states } {
    196     global SMALL
    197     return [generate_class Small $SMALL $states];
    198 }
    199 
    200 # Generate a large C++ class
    201 
    202 proc generate_large_class { states } {
    203     global LARGE
    204     return [generate_class Large $LARGE $states];
    205 }
    206 
    207 # Generate a class that derives from a small class
    208 
    209 proc generate_derived_class { states } {
    210     set base "Small_[join $states _]"
    211     set classname "Derived_[join $states _]"
    212 
    213     return "
    214     /*** Class derived from $base ***/
    215     class $classname : public $base {
    216     public:
    217     };
    218 
    219     $classname ${classname}_var; /* global var */
    220 
    221     template int cbv<$classname> ($classname arg);"
    222 }
    223 
    224 # Generate a class that contains a small class item
    225 
    226 proc generate_container_class { states } {
    227     set contained "Small_[join $states _]"
    228     set classname "Container_[join $states _]"
    229 
    230     return "
    231     /*** Class that contains $contained ***/
    232     class $classname {
    233     public:
    234         $contained item;
    235     };
    236 
    237     $classname ${classname}_var; /* global var */
    238 
    239     template int cbv_container<$classname> ($classname arg);"
    240 }
    241 
    242 # Generate useful statements that use a class in the debugee program
    243 
    244 proc generate_stmts { classprefix states {cbvfun "cbv"}} {
    245     set classname "${classprefix}_[join $states _]"
    246 
    247     # Having an explicit call to the cbv function in the debugee program
    248     # ensures that the compiler will emit necessary function in the binary.
    249     if {[is_copy_constructible $states]} {
    250 	set cbvcall "$cbvfun<$classname> (${classname}_var);\n"
    251     } else {
    252 	set cbvcall ""
    253     }
    254 
    255     return "$cbvcall"
    256 }
    257 
    258 # Generate the complete debugee program
    259 
    260 proc generate_program { classes stmts } {
    261     global ADDED
    262 
    263     return "
    264     /*** THIS FILE IS GENERATED BY THE TEST.  ***/
    265 
    266     static int tracer = 0;
    267 
    268     /* The call-by-value function.  */
    269     template <class T>
    270     int
    271     cbv (T arg)
    272     {
    273       arg.data\[0\] += $ADDED; // intentionally modify the arg
    274       return arg.data\[0\];
    275     }
    276 
    277     template <class T>
    278     int
    279     cbv_container (T arg)
    280     {
    281       arg.item.data\[0\] += $ADDED;  // intentionally modify
    282       return arg.item.data\[0\];
    283     }
    284 
    285     $classes
    286 
    287     int
    288     main (void)
    289     {
    290       $stmts
    291 
    292       /* stop here */
    293 
    294       return 0;
    295     }"
    296 }
    297 
    298 # Compute all the combinations of special function states.
    299 # We do not contain the 'deleted' state for the destructor,
    300 # because it is illegal to have stack-allocated objects
    301 # whose destructor have been deleted.  This case is covered
    302 # in pass-by-ref-2 via heap-allocated objects.
    303 
    304 set options_nodelete [list absent explicit defaultedIn defaultedOut]
    305 set options [concat $options_nodelete {deleted}]
    306 set all_combinations {}
    307 
    308 foreach cctor $options {
    309     foreach dtor $options_nodelete {
    310 	foreach mctor $options {
    311 	    lappend all_combinations [list $cctor $dtor $mctor]
    312 	}
    313     }
    314 }
    315 
    316 # Generate the classes.
    317 
    318 set classes ""
    319 set stmts ""
    320 
    321 foreach state $all_combinations {
    322     append classes [generate_small_class $state]
    323     append stmts [generate_stmts "Small" $state]
    324 
    325     append classes [generate_large_class $state]
    326     append stmts [generate_stmts "Large" $state]
    327 
    328     append classes [generate_derived_class $state]
    329     append stmts [generate_stmts "Derived" $state]
    330 
    331     append classes [generate_container_class $state]
    332     append stmts [generate_stmts "Container" $state "cbv_container"]
    333 }
    334 
    335 # Generate the program code and compile
    336 set program [generate_program $classes $stmts]
    337 set srcfile [standard_output_file ${srcfile}]
    338 gdb_produce_source $srcfile $program
    339 
    340 set options {debug c++ additional_flags=-std=c++11}
    341 if {[prepare_for_testing "failed to prepare" $testfile $srcfile $options]} {
    342     return -1
    343 }
    344 
    345 if {![runto_main]} {
    346     return -1
    347 }
    348 
    349 set bp_location [gdb_get_line_number "stop here"]
    350 gdb_breakpoint $bp_location
    351 gdb_continue_to_breakpoint "end of main" ".*return .*;"
    352 
    353 # Do the checks for a given class whose name is prefixed with PREFIX,
    354 # and whose special functions have the states given in STATES.
    355 # The name of the call-by-value function and the expression to access
    356 # the data field can be specified explicitly if the default values
    357 # do not work.
    358 
    359 proc test_for_class { prefix states cbvfun data_field length} {
    360     set name "${prefix}_[join $states _]"
    361 
    362     set cctor [lindex $states 0]
    363     set dtor  [lindex $states 1]
    364     set mctor [lindex $states 2]
    365 
    366     global ORIGINAL
    367     global CUSTOM
    368     global ADDED
    369     global TRACE
    370 
    371     # GCC version <= 6 and Clang do not emit DW_AT_defaulted and DW_AT_deleted.
    372     set is_gcc_6_or_older [test_compiler_info {gcc-[0-6]-*}]
    373     set is_clang [test_compiler_info {clang-*}]
    374     # But Clang version >= 7 emits DW_AT_calling_convention for types.
    375     set is_clang_6_or_older [test_compiler_info {clang-[0-6]-*}]
    376 
    377     with_test_prefix $name {
    378 	if {[is_copy_constructible $states]} {
    379 	    set expected [expr {$ORIGINAL + $ADDED}]
    380 	    if {$cctor == "explicit"} {
    381 		set expected [expr {$CUSTOM + $ADDED}]
    382 	    }
    383 	    if {$dtor == "explicit"} {
    384 		gdb_test "print tracer = 0" " = 0" "reset the tracer"
    385 	    }
    386 
    387 	    if {$cctor == "defaultedIn" || $dtor == "defaultedIn"} {
    388 		if {$is_gcc_6_or_older || $is_clang_6_or_older} {
    389 		    setup_xfail "*-*-*"
    390 		} elseif {$is_clang} {
    391 		    # If this is a pass-by-value case, Clang >= 7's
    392 		    # DW_AT_calling_convention leads to the right decision.
    393 		    # Otherwise, it is expected to fail.
    394 		    if {"defaultedOut" in $states || "explicit" in $states} {
    395 			setup_xfail "*-*-*"
    396 		    }
    397 		}
    398 	    }
    399 	    gdb_test "print ${cbvfun}<$name> (${name}_var)" " = $expected" \
    400 		"call '$cbvfun'"
    401 	    gdb_test "print ${name}_var.${data_field}\[0\]" " = $ORIGINAL" \
    402 		"cbv argument should not change (item 0)"
    403 	    if {$length > 1} {
    404 		set last_index [expr $length - 1]
    405 		gdb_test "print ${name}_var.${data_field}\[$last_index\]" \
    406 		    " = $ORIGINAL" \
    407 		    "cbv argument should not change (item $last_index)"
    408 	    }
    409 	    if {$dtor == "explicit"} {
    410 		if {$cctor == "defaultedIn"
    411 		    && ($is_gcc_6_or_older || $is_clang)} {
    412 		    setup_xfail "*-*-*"
    413 		}
    414 		gdb_test "print tracer" " = $TRACE" \
    415 		    "destructor should be called"
    416 	    }
    417 	} else {
    418 	    if {$cctor == "deleted" && ($is_gcc_6_or_older || $is_clang)} {
    419 		setup_xfail "*-*-*"
    420 	    }
    421 	    gdb_test "print ${cbvfun}<$name> (${name}_var)" \
    422 		".* cannot be evaluated .* '${name}' is not copy constructible" \
    423 		"calling '$cbvfun' should be refused"
    424 	}
    425     }
    426 }
    427 
    428 foreach state $all_combinations {
    429     test_for_class "Small"     $state "cbv"           "data"      $SMALL
    430     test_for_class "Large"     $state "cbv"           "data"      $LARGE
    431     test_for_class "Derived"   $state "cbv"           "data"      1
    432     test_for_class "Container" $state "cbv_container" "item.data" 1
    433 }
    434