Studying note of GCC-3.4.6 source (152)

来源:互联网 发布:sql substr 编辑:程序博客网 时间:2024/06/08 00:01

5.12.5.2.2.2.2.         Default arguments

If argexhausted, but parmdoesn’t, parmmust contain default arguments, for which the list should be terminated by thespecial void_list_node.Then in corresponding node, TREE_VALUE holds the type, and TREE_PURPOSE is theexpression of the default argument.

 

4258 tree

4259 convert_default_arg (tree type, tree arg, tree fn, int parmnum)                                    in call.c

4260 {

4261   /*If the ARG is an unparsed default argument expression, the

4262     conversion cannot be performed.  */

4263   if (TREE_CODE (arg) ==DEFAULT_ARG)

4264   {

4265     error ("the defaultargument for parameter %d of `%D' has "

4266           "not yet beenparsed",

4267           parmnum, fn);

4268     returnerror_mark_node;

4269   }

4270

4271   if (fn &&DECL_TEMPLATE_INFO (fn))

4272     arg =tsubst_default_argument (fn, type, arg);

4273

4274   arg = break_out_target_exprs (arg);

4275

4276   if (TREE_CODE (arg) ==CONSTRUCTOR)

4277   {

4278     arg = digest_init(type, arg, 0);

4279     arg =convert_for_initialization (0, type, arg, LOOKUP_NORMAL,

4280                               "defaultargument", fn, parmnum);

4281   }

4282   else

4283   {

4284     /*This could get clobbered by the following call. */

4285     if (TREE_HAS_CONSTRUCTOR(arg))

4286       arg = copy_node (arg);

4287

4288     arg =convert_for_initialization (0, type, arg, LOOKUP_NORMAL,

4289                               "defaultargument", fn, parmnum);

4290     arg = convert_for_arg_passing (type, arg);

4291   }

4292

4293   returnarg;

4294 }

 

Node of DEFAULT_ARG is created for unparsed default argument.Remember during parsing class definition, any default argument is cached byDEFAULT_ARG, which will be parsed after the parsing. So DEFAULT_ARG should notbe present here (if so, it may be missing “};” in the class definition), and atthis point, the front-end doesn’t know how to handle node of this kind.

Then argpassed for below function at line 4274, is the default argument shared by allinvocations of the function. However, as [3] defines, “Default arguments are evaluated each time thefunction is called”, so before really evaluate the expression of thedefault argument, it needs prepare appropriate copy of arg and update this localtemparories acclaimed as below.

 

1259 tree

1260 break_out_target_exprs (tree t)                                                                  incp/tree.c

1261 {

1262   staticint target_remap_count;

1263   staticsplay_tree target_remap;

1264

1265   if (!target_remap_count++)

1266     target_remap =splay_tree_new (splay_tree_compare_pointers,

1267                                /*splay_tree_delete_key_fn=*/NULL,

1268                                /*splay_tree_delete_value_fn=*/NULL);

1269   walk_tree(&t, bot_manip, target_remap, NULL);

1270   walk_tree(&t, bot_replace, target_remap, NULL);

1271

1272   if (!--target_remap_count)

1273   {

1274     splay_tree_delete(target_remap);

1275     target_remap = NULL;

1276   }

1277

1278   returnt;

1279 }

 

Above walk_tree traverses the subtree rooted by t andexecutes provided function upon nodes selected by the code of t. Infirst traversal, below function is used. Note that the function always returnsNULL (copy_tree_rbelow returns NULL) to force walk_tree to do full traversal with depthfirst (i.e. tpmaybe a tree_list, in which node can contain operands which in turn can betree_list again and so on, the visit should be from bottom up); however whetherstepping into the sub-tree (i.e. operand) is controlled by local variable walk_subtrees(which is passes as argument walk_subtrees in below function). Beforeprocessing the tree node with the specified function, walk_subtrees is set as 1; it isthe specified function to decide whether the node is of interesting and needsto be stepped into if no result gotten.

 

1182 static tree

1183 bot_manip (tree* tp, int* walk_subtrees, void* data)                                     in cp/tree.c

1184 {

1185   splay_tree target_remap =((splay_tree) data);

1186   tree t = *tp;

1187

1188   if (TREE_CONSTANT (t))

1189   {

1190     /*There can't be any TARGET_EXPRs or their slot variables below

1191       thispoint. We used to check !TREE_SIDE_EFFECTS, but then we

1192       failed to copy an ADDR_EXPR of the slotVAR_DECL.  */

1193     *walk_subtrees = 0;

1194     returnNULL_TREE;

1195   }

1196   if (TREE_CODE (t) ==TARGET_EXPR)

1197   {

1198     tree u;

1199

1200     if (TREE_CODE(TREE_OPERAND (t, 1)) == AGGR_INIT_EXPR)

1201     {

1202       mark_used(TREE_OPERAND (TREE_OPERAND (TREE_OPERAND (t, 1), 0), 0));

1203       u = build_cplus_new

1204             (TREE_TYPE (t),break_out_target_exprs (TREE_OPERAND (t, 1)));

1205     }

1206     else

1207     {

1208       u = build_target_expr_with_type

1209             (break_out_target_exprs (TREE_OPERAND (t,1)), TREE_TYPE (t));

1210     }

1211

1212     /* Map the old variable to the new one.  */

1213     splay_tree_insert(target_remap,

1214                     (splay_tree_key)TREE_OPERAND (t, 0),

1215                     (splay_tree_value)TREE_OPERAND (u, 0));

1216

1217     /*Replace the old expression with the new version.  */

1218     *tp = u;

1219     /*We don't have to go below this point; the recursive call to

1220       break_out_target_exprs will have handledanything below this

1221       point. */

1222     *walk_subtrees = 0;

1223     returnNULL_TREE;

1224   }

1225   else if (TREE_CODE (t) ==CALL_EXPR)

1226     mark_used(TREE_OPERAND (TREE_OPERAND (t, 0), 0));

1227

1228   /*Make a copy of this node.  */

1229   returncopy_tree_r (tp, walk_subtrees, NULL);

1230 }

 

For node other than constant or TRAGET_EXPR, copy_tree_r copies the nodeif it is either *_CST (see it is filtered out by TREE_CONSTANT above) orexpression or TREE_LIST or TREE_VEC or OVERLOAD (told by C++ hook of tree_chain_matters_pbelow, and note that walk_subtrees is unchanged here, walk_treewill step into the sub-nodes of the node and continues copying the structureaccordingly).

 

1966 tree

1967 copy_tree_r (tree *tp, int*walk_subtrees, void *data ATTRIBUTE_UNUSED) in tree-inline.c

1968 {

1969   enumtree_code code = TREE_CODE (*tp);

1970

1971   /* We make copies of most nodes.  */

1972   if (IS_EXPR_CODE_CLASS(TREE_CODE_CLASS (code))

1973       || TREE_CODE_CLASS(code) == 'c'

1974       || code == TREE_LIST

1975       || code == TREE_VEC

1976       || (*lang_hooks.tree_inlining.tree_chain_matters_p)(*tp))

1977   {

1978     /* Because the chain gets clobbered when wemake a copy, we save it

1979       here. */

1980     tree chain = TREE_CHAIN(*tp);

1981

1982     /*Copy the node.  */

1983     *tp = copy_node (*tp);

1984

1985     /*Now, restore the chain, if appropriate. That will cause

1986       walk_tree to walk into the chain aswell.  */

1987     if (code == PARM_DECL ||code == TREE_LIST

1988 #ifndef INLINER_FOR_JAVA

1989         || (*lang_hooks.tree_inlining.tree_chain_matters_p)(*tp)

1990         || STATEMENT_CODE_P (code))

1991       TREE_CHAIN (*tp) = chain;

1992

1993     /* For now, we don't update BLOCKs when wemake copies. So, we

1994       haveto nullify all scope-statements.  */

1995     if (TREE_CODE (*tp) ==SCOPE_STMT)

1996       SCOPE_STMT_BLOCK (*tp) =NULL_TREE;

1997 #else/* INLINER_FOR_JAVA */

1998         || (*lang_hooks.tree_inlining.tree_chain_matters_p)(*tp))

1999       TREE_CHAIN (*tp) =chain;

2000 #endif /*INLINER_FOR_JAVA */

2001   }

2002   else if (TREE_CODE_CLASS(code) == 't')

2003     *walk_subtrees = 0;

2004

2005   returnNULL_TREE;

2006 }

 

A TARGET_EXPR represents a temporary object. The first operand is aVAR_DECL for the temporary variable. The second operand is the initializer forthe temporary. The initializer is evaluated, and copied (bitwise) into thetemporary.

An AGGR_INIT_EXPR represents the initialization as the return valueof a function call, or as the result of a constructor. An AGGR_INIT_EXPR willonly appear as the second operand of a TARGET_EXPR. The first operand to theAGGR_INIT_EXPR is the address of a function to call, just as in a CALL_EXPR.The second operand are the arguments to pass that function, as a TREE_LIST,again in a manner similar to that of a CALL_EXPR. The value of the expressionis that returned by the function.

Then if AGGR_INIT_EXPR is used in TRAGET_EXPR, it recurses break_out_target_exprsto copy this node. With the copied expression, build_cplus_new generatescode for the initialization.

 

2007 tree

2008 build_cplus_new (tree type, tree init)                                                          incp/tree.c

2009 {

2010   tree fn;

2011   tree slot;

2012   tree rval;

2013   int is_ctor;

2014

2015   /*Make sure that we're not trying to create an instance of an

2016     abstract class.  */

2017   abstract_virtuals_error (NULL_TREE, type);

2018

2019   if (TREE_CODE (init) != CALL_EXPR &&TREE_CODE (init) != AGGR_INIT_EXPR)

2020     returnconvert (type, init);

2021

2022   fn = TREE_OPERAND (init, 0);

2023   is_ctor = (TREE_CODE (fn) ==ADDR_EXPR

2024            &&TREE_CODE (TREE_OPERAND (fn, 0)) == FUNCTION_DECL

2025            &&DECL_CONSTRUCTOR_P (TREE_OPERAND (fn, 0)));

2026

2027   slot = build_local_temp (type);

2028

2029   /*We split the CALL_EXPR into its function and its arguments here.

2030     Then,in expand_expr, we put them back together. The reason for

2031     thisis that this expression might be a default argument

2032     expression. In that case, we need a newtemporary every time the

2033     expression is used. That's whatbreak_out_target_exprs does; it

2034     replaces every AGGR_INIT_EXPR with a copythat uses a fresh

2035     temporary slot. Then, expand_expr builds upa call-expression

2036     usingthe new slot.  */

2037

2038   /*If we don't need to use a constructor to create an object of this

2039     type,don't mess with AGGR_INIT_EXPR.  */

2040   if (is_ctor ||TREE_ADDRESSABLE (type))

2041   {

2042     rval = build(AGGR_INIT_EXPR, type, fn, TREE_OPERAND (init, 1), slot);

2043     TREE_SIDE_EFFECTS (rval) =1;

2044     AGGR_INIT_VIA_CTOR_P(rval) = is_ctor;

2045   }

2046   else

2047     rval = init;

2048

2049   rval = build_target_expr (slot, rval);

2050

2051   returnrval;

2052 }

 

Now it needs update the temporary in the TARGET_EXPR, as we are notwithin the context generating the original TARGET_EXPR. See it makes thetemporary as local by forcing its DECL_CONTEXT by current_function_decl.

 

253    static tree

254    build_local_temp (tree type)                                                                      incp/tree.c

255    {

256      tree slot = build_decl(VAR_DECL, NULL_TREE, type);

257      DECL_ARTIFICIAL (slot) = 1;

258      DECL_CONTEXT (slot) = current_function_decl;

259      layout_decl (slot,0);

260      return slot;

261    }

 

Note if AGGR_INIT_VIA_CTOR_P holds for the AGGR_INIT_EXPR, then theinitialization is via a constructor call. AGGR_INIT_EXPR constructed at line 2042will have this temporary as its third operand, which is always a VAR_DECL. And init isthe AGGR_INIT_EXPR in the original TARGET_EXPR (the address of the thirdoperand of the AGGR_INIT_EXPR is taken, and this value replaces the firstargument in the argument list. In this case, the value of the expression is theVAR_DECL given by the third operand to the AGGR_INIT_EXPR; constructors do notreturn a value).

Finally, this new generated TARGET_EXPR is retuned by build_cplus_new.

While for second operand in TARGET_EXPR other than AGGR_INIT_EXPR,the operand is handled by build_target_expr_with_type instead. Here if init isTARGET_EXPR, it must be one that built by break_out_target_exprs at line 1209 in bot_manip, which is the node we expect.

 

320    tree

321    build_target_expr_with_type (tree init,tree type)                                        incp/tree.c

322    {

323      tree slot;

324   

325      if (TREE_CODE (init) == TARGET_EXPR)

326        returninit;

327      else if (CLASS_TYPE_P (type) &&!TYPE_HAS_TRIVIAL_INIT_REF (type)

328            && TREE_CODE (init) !=COND_EXPR

329            && TREE_CODE (init) !=CONSTRUCTOR

330            && TREE_CODE (init) !=VA_ARG_EXPR)

331        /* We need tobuild up a copy constructor call. COND_EXPR is a special

332          case because wealready have copies on the arms and we don't want

333          another onehere. A CONSTRUCTOR is aggregate initialization, which

334          is handledseparately. A VA_ARG_EXPR is magic creation of an

335          aggregate;there's no additional work to be done. */

336        return force_rvalue (init);

337   

338      slot = build_local_temp(type);

339      return build_target_expr (slot, init);

340    }

 

Above if TYPE_HAS_TRIVIAL_INIT_REF is nonzero, it means that copyinitialization of the type can use a bitwise copy. For which case, it cansimply build TARGET_EXPR; otherwise, it needs perform an lvalue-to-rvalueconversion, including invoking the copy ctor as below.

 

590    tree

591    force_rvalue (tree expr)                                                                                  incvt.c

592    {

593      if (IS_AGGR_TYPE (TREE_TYPE(expr)) && TREE_CODE (expr) != TARGET_EXPR)

594        expr = ocp_convert (TREE_TYPE (expr), expr,

595                       CONV_IMPLICIT|CONV_FORCE_TEMP, LOOKUP_NORMAL);

596      else

597        expr = decay_conversion(expr);

598   

599      return expr;

600    }

 

We will see the detail of ocp_convert in short later. As summary here,the function will generate code for invoking the appropriate copy ctor and theninvoking build_cplus_newto create the temporary with its initialization. Before leaving bot_manip,it worthes a look of build_target_expr.

 

234    static tree

235    build_target_expr (tree decl, treevalue)                                                     incp/tree.c

236    {

237      tree t;

238   

239      t = build (TARGET_EXPR,TREE_TYPE (decl), decl, value,

240              cxx_maybe_build_cleanup(decl), NULL_TREE);

241      /* We always setTREE_SIDE_EFFECTS so that expand_expr does not

242        ignore the TARGET_EXPR. If there really turnout to be no

243        side-effects,then the optimizer should be able to get rid of

244        whatever code isgenerated anyhow.  */

245      TREE_SIDE_EFFECTS (t) = 1;

246   

247      return t;

248    }

 

For temporary with non-trivial destructor, the compiler needsgenerate code to destory the temporary at exitting its scope by invoking thedestructor. So at line 240, cxx_maybe_build_cleanup generates this codeif necessary.

Now at line 1213 inbot_manip,u isthe TARGET_EXPR built corresponding to t. It maps the new version temporary with the oldone. Then, we immediately replace the old one with it. However, it is possiblesome sub-nodes within node handled by break_out_target_exprs, still hold thereference to this old version, which needs be updated as below.

 

1236 static tree

1237 bot_replace (tree* t,                                                                                  incp/tree.c

1238            int* walk_subtreesATTRIBUTE_UNUSED ,

1239            void* data)

1240 {

1241   splay_tree target_remap =((splay_tree) data);

1242

1243   if (TREE_CODE (*t) ==VAR_DECL)

1244   {

1245     splay_tree_node n =splay_tree_lookup (target_remap,

1246                                      (splay_tree_key)*t);

1247     if (n)

1248       *t = (tree) n->value;

1249   }

1250

1251   returnNULL_TREE;

1252 }

 

Back convert_default_arg, it gets the updated arg atline 4274 from break_out_target_exprs, then the following functions are usedto generate code for the initialization.

5.12.5.2.2.2.3.         Ellipsis arguments

The last possibility is the ellipsis arguments, note that ellipsisargument can’t coexist with default argument. In front-end to tell out functiondeclaration containing ellipsis arguments, the list of parameters is terminatedby NULL instead of void_list_node.

 

4161 tree

4162 convert_arg_to_ellipsis (tree arg)                                                                       incall.c

4163 {

4164   /*[expr.call]

4165

4166     Thelvalue-to-rvalue, array-to-pointer, and function-to-pointer

4167     standard conversions are performed.  */

4168   arg = decay_conversion (arg);

4169   /* [expr.call]

4170

4171     If theargument has integral or enumeration type that is subject

4172     to theintegral promotions (_conv.prom_), or a floating point

4173     typethat is subject to the floating point promotion

4174     (_conv.fpprom_), the value of the argumentis converted to the

4175     promoted type before the call.  */

4176   if (TREE_CODE (TREE_TYPE(arg)) == REAL_TYPE

4177      &&(TYPE_PRECISION (TREE_TYPE (arg))

4178           < TYPE_PRECISION(double_type_node)))

4179     arg = convert_to_real (double_type_node,arg);

4180   else if(INTEGRAL_OR_ENUMERATION_TYPE_P (TREE_TYPE (arg)))

4181     arg =perform_integral_promotions (arg);

4182

4183   arg = require_complete_type(arg);

4184   

4185   if (arg != error_mark_node

4186       && !pod_type_p(TREE_TYPE (arg)))

4187   {

4188     /*Undefined behavior [expr.call] 5.2.2/7. We usedto just warn

4189       hereand do a bitwise copy, but now cp_expr_size will abort if we

4190       tryto do that.

4191       Ifthe call appears in the context of a sizeof expression,

4192       there is no need to emit a warning, sincethe expression won't be

4193       evaluated. We keep the builtin_trap justas a safety check.  */

4194     if (!skip_evaluation)

4195       warning ("cannotpass objects of non-POD type `%#T' through `...'; "

4196               "call willabort at runtime", TREE_TYPE (arg));

4197     arg = call_builtin_trap ();

4198     arg = build(COMPOUND_EXPR, integer_type_node, arg,

4199               integer_zero_node);

4200   }

4201

4202   returnarg;

4203 }

 

[3], clause 5.2.2“Function call”, terms 7 defines the behavior of compiler upon ellipsisargument as below.

7.  When there is no parameter for a given argument, the argument is passed in such a way that the receiving function can obtain the value of the argument by invoking va_arg (18.7). The lvalue-to-rvalue (4.1), array-to-pointer (4.2), and function-to-pointer (4.3) standard conversions are performed on the argument expression. After these conversions, if the argument does not have arithmetic, enumeration, pointer, pointer to member, or class type, the program is ill-formed. If the argument has a non-POD class type (clause 9), the behavior is undefined. If the argument has integral or enumeration type that is subject to the integral promotions (4.5), or a floating point type that is subject to the floating point promotion (4.6), the value of the argument is converted to the promoted type before the call. These promotions are referred to as the default argument promotions.

Function decay_conversionperforms the conversions in exp, which are used when an lvalue appears in anrvalue context, and include lvalue-to-rvalue, array-to-pointer, and function-to-pointerconversion.

 

1335 tree

1336 decay_conversion (tree exp)                                                                       ntypeck.c

1337 {

1338   tree type;

1339   enumtree_code code;

1340

1341   type = TREE_TYPE (exp);

1342   code = TREE_CODE (type);

1343

1344   if (code == REFERENCE_TYPE)

1345   {

1346     exp = convert_from_reference (exp);

1347     type = TREE_TYPE (exp);

1348     code = TREE_CODE (type);

1349   }

1350

1351   if (type == error_mark_node)

1352     returnerror_mark_node;

1353

1354   if (type_unknown_p (exp))

1355   {

1356     cxx_incomplete_type_error(exp, TREE_TYPE (exp));

1357     returnerror_mark_node;

1358   }

1359   

1360   /*Constants can be used directly unless they're not loadable.  */

1361   if (TREE_CODE (exp) ==CONST_DECL)

1362     exp = DECL_INITIAL (exp);

1363   /*Replace a nonvolatile const static variable with its value. We

1364     don'tdo this for arrays, though; we want the address of the

1365     firstelement of the array, not the address of the first element

1366     of itsinitializing constant.  */

1367   else if (code != ARRAY_TYPE)

1368   {

1369     exp = decl_constant_value(exp);

1370     type = TREE_TYPE (exp);

1371   }

1372

1373   /* build_c_cast puts on a NOP_EXPR to make theresult not an lvalue.

1374     Leavesuch NOP_EXPRs, since RHS is being used in non-lvalue context.  */

1375

1376   if (code == VOID_TYPE)

1377   {

1378     error ("void valuenot ignored as it ought to be");

1379     returnerror_mark_node;

1380   }

1381   if (invalid_nonstatic_memfn_p(exp))

1382     returnerror_mark_node;

1383   if (code == FUNCTION_TYPE ||is_overloaded_fn (exp))

1384     returnbuild_unary_op (ADDR_EXPR, exp, 0);

1385   if (code == ARRAY_TYPE)

1386   {

1387     tree adr;

1388     tree ptrtype;

1389

1390     if (TREE_CODE (exp) ==INDIRECT_REF)

1391       returnbuild_nop (build_pointer_type (TREE_TYPE(type)),

1392                     TREE_OPERAND (exp, 0));

1393

1394     if (TREE_CODE (exp) ==COMPOUND_EXPR)

1395     {

1396       tree op1 = decay_conversion (TREE_OPERAND (exp, 1));

1397       returnbuild (COMPOUND_EXPR, TREE_TYPE (op1),

1398                 TREE_OPERAND(exp, 0), op1);

1399     }

1400

1401     if (!lvalue_p (exp)

1402        && ! (TREE_CODE(exp) == CONSTRUCTOR && TREE_STATIC (exp)))

1403     {

1404       error ("invalid useof non-lvalue array");

1405       returnerror_mark_node;

1406     }

1407

1408     ptrtype = build_pointer_type (TREE_TYPE (type));

1409

1410     if (TREE_CODE (exp) ==VAR_DECL)

1411     {

1412       if(!cxx_mark_addressable (exp))

1413         return error_mark_node;

1414       adr = build_nop(ptrtype, build_address (exp));

1415       TREE_SIDE_EFFECTS (adr)= 0;   /*Default would be, same as EXP.  */

1416       returnadr;

1417     }

1418     /*This way is better for a COMPONENT_REF since it can

1419       simplify the offset for a component.  */

1420     adr = build_unary_op(ADDR_EXPR, exp, 1);

1421     returncp_convert (ptrtype, adr);

1422   }

1423

1424   /*[basic.lval]: Class rvalues can have cv-qualified types; non-class

1425     rvalues always have cv-unqualifiedtypes.  */

1426   if (! CLASS_TYPE_P (type))

1427     exp = cp_convert(TYPE_MAIN_VARIANT (type), exp);

1428

1429   returnexp;

1430 }

 

First for REFERENCE_TYPE, it is a lvalue, to change it to rvalue, itshould uses the value referred instead of holding reference any more. Infront-end, INDIRECT_REF is built for the purpose (it because reference alwayshas its address passed just like pointer, and in compiler, the mode ofreference is the same as pointer, both are ptr_mode, see build_reference_type).

 

566    tree

567    convert_from_reference (tree val)                                                                    incvt.c

568    {

569      if (TREE_CODE (TREE_TYPE (val)) ==REFERENCE_TYPE)

570        return build_indirect_ref (val, NULL);

571      return val;

572    }

 

Remember pointer is rvalue. When handling ARRAY_TYPE, condition atline 1390 is satisfied, if we are using expression like: int *a[i] (a is arrayhaving dimensions more than 1, for example, int A[2][2]), so it builds typelike: int**, and see converting pointer of “int *a[i]” to “int**” needesn’tgenerate any code, NOP_EXPR is built for such conversion.

Further if exp simply is a declaration of an array, forexmaple: int a[8], rvalue of this declaration is just “int*”. It can build thisrvalue directly. However, for other cases, for example: tempA.a (it is a treerooted by SCOPE_REF), it is not a simple rule we can use directly, so it asks build_unary_opand cp_convertto do the appropriate conversion.

As comment at line 4188 inconvert_arg_to_ellipsismentions, for the undefined behavior of non-POD class type, GCC once usesbitwise copy, but this behavior will cause later invocation of cp_expr_sizetriggering abort in current version. This abort is triggered by belowinvocation of “__builtin_trap”, which is included in arg of COMPOUND_EXPR at line 4198.

 

4148 c tree

4149 call_builtin_trap (void)                                                                               incall.c

4150 {

4151   tree fn =IDENTIFIER_GLOBAL_VALUE (get_identifier ("__builtin_trap"));

4152

4153   my_friendly_assert (fn !=NULL, 20030927);

4154   fn = build_call (fn,NULL_TREE);

4155   returnfn;

4156 }

 

The behavior of the builtin trap will use trap if the target machinedefines it; otherwise the compiler will call abort() (see expand_builtin_trap).

Below is aninteresting test for the behavior of non-POD class type:

#include <stdarg.h>

class A {

    public: virtual void func() {}

};

int func (int a, ...) {

    va_list ap;

    va_start(ap, a);

    va_arg(ap, A); 

    va_end(ap);

    return 1;

}

int main() {

    A a;

    func (1, a);      // sizeof (func (1, a))

}

The compiler will give outfollowing warning:

test2.cpp: In function ‘int func(int, ...)’:

test2.cpp:11: warning: cannot receive objects ofnon-POD type ‘class A’ through ‘...’; call will abort at runtime

test2.cpp: In function ‘int main()’:

test2.cpp:19: warning: cannot pass objects of non-PODtype ‘class A’ through ’...’; call will abort at runtime

When execute the program, it gets error: Illegal instruction.

However, if we use statement in comment instead, the compiler thengives warning as:

test2.cpp: In function ‘int func(int, ...)’:

test2.cpp:11: warning: cannot receive objects ofnon-POD type ‘class A’ through ‘...’; call will abort at runtime

And at execution, no error will be output, as func(1, a) will not beevaluated except its returned value.

 

原创粉丝点击