Home | History | Annotate | Line # | Download | only in gdb.cp
pass-by-ref.exp revision 1.1.1.8
      1 # Copyright 2007-2024 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 require allow_cplus_tests
     72 
     73 # The program source is generated in the output directory.
     74 # We use standard_testfile here to set convenience variables.
     75 standard_testfile .cc
     76 
     77 # Some constant values used when generating the source
     78 
     79 set SMALL    2
     80 set LARGE    150
     81 set ORIGINAL 2
     82 set CUSTOM   3
     83 set ADDED    4
     84 set TRACE    5
     85 
     86 
     87 # Return 1 if the class whose special function states are STATES
     88 # is copyable.  Otherwise return 0.
     89 
     90 proc is_copy_constructible { states } {
     91     set cctor [lindex $states 0]
     92     set dtor  [lindex $states 1]
     93     set mctor [lindex $states 2]
     94 
     95     if {$cctor == "deleted" || ($cctor == "absent" && $mctor != "absent")} {
     96 	return 0
     97     }
     98     return 1
     99 }
    100 
    101 # Generate a declaration and an out-of-class definition for a function
    102 # with the provided signature.  The STATE should be one of the following:
    103 # - explicit, defaultedIn, defaultedOut, deleted, absent
    104 
    105 proc generate_member_function { classname signature length state } {
    106     set declaration ""
    107     set definition ""
    108 
    109     global CUSTOM
    110     global TRACE
    111 
    112     switch $state {
    113 	explicit {
    114 	    set declaration "$signature;\n"
    115 	    set definition "$classname\:\:$signature
    116                             {
    117                               data\[0\] = $CUSTOM;
    118                               data\[[expr $length - 1]\] = $CUSTOM;
    119                               tracer = $TRACE;
    120                             }\n"
    121 	}
    122 	defaultedIn {
    123 	    set declaration "$signature = default;\n"
    124 	}
    125 	defaultedOut {
    126 	    set declaration "$signature;\n"
    127 	    set definition "$classname\:\:$signature = default;\n"
    128 	}
    129 	deleted {
    130 	    set declaration "$signature = delete;\n"
    131 	}
    132 	default {
    133 	    # function is not user-defined in this case
    134 	}
    135     }
    136 
    137     return [list $declaration $definition]
    138 }
    139 
    140 # Generate a C++ class with the given CLASSNAME and LENGTH-many
    141 # integer elements.  The STATES is an array of 3 items
    142 # containing the desired state of the special functions
    143 # in this order:
    144 # copy constructor, destructor, move constructor
    145 
    146 proc generate_class { classname length states } {
    147     set declarations ""
    148     set definitions ""
    149     set classname "${classname}_[join $states _]"
    150 
    151     for {set i 0} {$i < [llength $states]} {incr i} {
    152 	set sig ""
    153 	switch $i {
    154 	    0 {set sig "$classname (const $classname \&rhs)"}
    155 	    1 {set sig "\~$classname (void)"}
    156 	    2 {set sig "$classname ($classname \&\&rhs)"}
    157 	}
    158 
    159 	set state [lindex $states $i]
    160 	set code [generate_member_function $classname $sig $length $state]
    161 	append declarations [lindex $code 0]
    162 	append definitions [lindex $code 1]
    163     }
    164 
    165     global ORIGINAL
    166 
    167     return "
    168     /*** C++ class $classname ***/
    169     class ${classname} {
    170     public:
    171         $classname (void);
    172         $declarations
    173 
    174         int data\[$length\];
    175     };
    176 
    177     $classname\:\:$classname (void)
    178     {
    179         data\[0\] = $ORIGINAL;
    180         data\[[expr $length - 1]\] = $ORIGINAL;
    181     }
    182 
    183     $definitions
    184 
    185     $classname ${classname}_var; /* global var */
    186 
    187     template int cbv<$classname> ($classname arg);"
    188 }
    189 
    190 # Generate a small C++ class
    191 
    192 proc generate_small_class { states } {
    193     global SMALL
    194     return [generate_class Small $SMALL $states];
    195 }
    196 
    197 # Generate a large C++ class
    198 
    199 proc generate_large_class { states } {
    200     global LARGE
    201     return [generate_class Large $LARGE $states];
    202 }
    203 
    204 # Generate a class that derives from a small class
    205 
    206 proc generate_derived_class { states } {
    207     set base "Small_[join $states _]"
    208     set classname "Derived_[join $states _]"
    209 
    210     return "
    211     /*** Class derived from $base ***/
    212     class $classname : public $base {
    213     public:
    214     };
    215 
    216     $classname ${classname}_var; /* global var */
    217 
    218     template int cbv<$classname> ($classname arg);"
    219 }
    220 
    221 # Generate a class that contains a small class item
    222 
    223 proc generate_container_class { states } {
    224     set contained "Small_[join $states _]"
    225     set classname "Container_[join $states _]"
    226 
    227     return "
    228     /*** Class that contains $contained ***/
    229     class $classname {
    230     public:
    231         $contained item;
    232     };
    233 
    234     $classname ${classname}_var; /* global var */
    235 
    236     template int cbv_container<$classname> ($classname arg);"
    237 }
    238 
    239 # Generate useful statements that use a class in the debugee program
    240 
    241 proc generate_stmts { classprefix states {cbvfun "cbv"}} {
    242     set classname "${classprefix}_[join $states _]"
    243 
    244     # Having an explicit call to the cbv function in the debugee program
    245     # ensures that the compiler will emit necessary function in the binary.
    246     if {[is_copy_constructible $states]} {
    247 	set cbvcall "$cbvfun<$classname> (${classname}_var);\n"
    248     } else {
    249 	set cbvcall ""
    250     }
    251 
    252     return "$cbvcall"
    253 }
    254 
    255 # Generate the complete debugee program
    256 
    257 proc generate_program { classes stmts } {
    258     global ADDED
    259 
    260     return "
    261     /*** THIS FILE IS GENERATED BY THE TEST.  ***/
    262 
    263     static int tracer = 0;
    264 
    265     /* The call-by-value function.  */
    266     template <class T>
    267     int
    268     cbv (T arg)
    269     {
    270       arg.data\[0\] += $ADDED; // intentionally modify the arg
    271       return arg.data\[0\];
    272     }
    273 
    274     template <class T>
    275     int
    276     cbv_container (T arg)
    277     {
    278       arg.item.data\[0\] += $ADDED;  // intentionally modify
    279       return arg.item.data\[0\];
    280     }
    281 
    282     $classes
    283 
    284     int
    285     main (void)
    286     {
    287       $stmts
    288 
    289       /* stop here */
    290 
    291       return 0;
    292     }"
    293 }
    294 
    295 # Compute all the combinations of special function states.
    296 # We do not contain the 'deleted' state for the destructor,
    297 # because it is illegal to have stack-allocated objects
    298 # whose destructor have been deleted.  This case is covered
    299 # in pass-by-ref-2 via heap-allocated objects.
    300 
    301 set options_nodelete [list absent explicit defaultedIn defaultedOut]
    302 set options [concat $options_nodelete {deleted}]
    303 set all_combinations {}
    304 
    305 foreach cctor $options {
    306     foreach dtor $options_nodelete {
    307 	foreach mctor $options {
    308 	    lappend all_combinations [list $cctor $dtor $mctor]
    309 	}
    310     }
    311 }
    312 
    313 # Generate the classes.
    314 
    315 set classes ""
    316 set stmts ""
    317 
    318 foreach state $all_combinations {
    319     append classes [generate_small_class $state]
    320     append stmts [generate_stmts "Small" $state]
    321 
    322     append classes [generate_large_class $state]
    323     append stmts [generate_stmts "Large" $state]
    324 
    325     append classes [generate_derived_class $state]
    326     append stmts [generate_stmts "Derived" $state]
    327 
    328     append classes [generate_container_class $state]
    329     append stmts [generate_stmts "Container" $state "cbv_container"]
    330 }
    331 
    332 # Generate the program code and compile
    333 set program [generate_program $classes $stmts]
    334 set srcfile [standard_output_file ${srcfile}]
    335 gdb_produce_source $srcfile $program
    336 
    337 set options {debug c++ additional_flags=-std=c++11}
    338 if {[prepare_for_testing "failed to prepare" $testfile $srcfile $options]} {
    339     return -1
    340 }
    341 
    342 if {![runto_main]} {
    343     return -1
    344 }
    345 
    346 set bp_location [gdb_get_line_number "stop here"]
    347 gdb_breakpoint $bp_location
    348 gdb_continue_to_breakpoint "end of main" ".*return .*;"
    349 
    350 # Do the checks for a given class whose name is prefixed with PREFIX,
    351 # and whose special functions have the states given in STATES.
    352 # The name of the call-by-value function and the expression to access
    353 # the data field can be specified explicitly if the default values
    354 # do not work.
    355 
    356 proc test_for_class { prefix states cbvfun data_field length} {
    357     set name "${prefix}_[join $states _]"
    358 
    359     set cctor [lindex $states 0]
    360     set dtor  [lindex $states 1]
    361     set mctor [lindex $states 2]
    362 
    363     global ORIGINAL
    364     global CUSTOM
    365     global ADDED
    366     global TRACE
    367 
    368     # GCC version <= 6 and Clang do not emit DW_AT_defaulted and DW_AT_deleted.
    369     set is_gcc_6_or_older [test_compiler_info {gcc-[0-6]-*}]
    370     set is_clang [test_compiler_info {clang-*}]
    371     # But Clang version >= 7 emits DW_AT_calling_convention for types.
    372     set is_clang_6_or_older [test_compiler_info {clang-[0-6]-*}]
    373 
    374     with_test_prefix $name {
    375 	if {[is_copy_constructible $states]} {
    376 	    set expected [expr {$ORIGINAL + $ADDED}]
    377 	    if {$cctor == "explicit"} {
    378 		set expected [expr {$CUSTOM + $ADDED}]
    379 	    }
    380 	    if {$dtor == "explicit"} {
    381 		gdb_test "print tracer = 0" " = 0" "reset the tracer"
    382 	    }
    383 
    384 	    if {$cctor == "defaultedIn" || $dtor == "defaultedIn"} {
    385 		if {$is_gcc_6_or_older || $is_clang_6_or_older} {
    386 		    setup_xfail "*-*-*"
    387 		} elseif {$is_clang} {
    388 		    # If this is a pass-by-value case, Clang >= 7's
    389 		    # DW_AT_calling_convention leads to the right decision.
    390 		    # Otherwise, it is expected to fail.
    391 		    if {"defaultedOut" in $states || "explicit" in $states} {
    392 			setup_xfail "*-*-*"
    393 		    }
    394 		}
    395 	    }
    396 	    gdb_test "print ${cbvfun}<$name> (${name}_var)" " = $expected" \
    397 		"call '$cbvfun'"
    398 	    gdb_test "print ${name}_var.${data_field}\[0\]" " = $ORIGINAL" \
    399 		"cbv argument should not change (item 0)"
    400 	    if {$length > 1} {
    401 		set last_index [expr $length - 1]
    402 		gdb_test "print ${name}_var.${data_field}\[$last_index\]" \
    403 		    " = $ORIGINAL" \
    404 		    "cbv argument should not change (item $last_index)"
    405 	    }
    406 	    if {$dtor == "explicit"} {
    407 		if {$cctor == "defaultedIn"
    408 		    && ($is_gcc_6_or_older || $is_clang)} {
    409 		    setup_xfail "*-*-*"
    410 		}
    411 		gdb_test "print tracer" " = $TRACE" \
    412 		    "destructor should be called"
    413 	    }
    414 	} else {
    415 	    if {$cctor == "deleted" && ($is_gcc_6_or_older || $is_clang)} {
    416 		setup_xfail "*-*-*"
    417 	    }
    418 	    gdb_test "print ${cbvfun}<$name> (${name}_var)" \
    419 		".* cannot be evaluated .* '${name}' is not copy constructible" \
    420 		"calling '$cbvfun' should be refused"
    421 	}
    422     }
    423 }
    424 
    425 foreach state $all_combinations {
    426     test_for_class "Small"     $state "cbv"           "data"      $SMALL
    427     test_for_class "Large"     $state "cbv"           "data"      $LARGE
    428     test_for_class "Derived"   $state "cbv"           "data"      1
    429     test_for_class "Container" $state "cbv_container" "item.data" 1
    430 }
    431