您的位置:首页 > 其它

Studying note of GCC-3.4.6 source (152)

2011-01-29 15:07 337 查看
5.12.5.2.2.2.2.

Default arguments

If arg

exhausted, but parm

doesn’t, parm

must contain default arguments, for which the list should be terminated by the
special void_list_node

.
Then in corresponding node, TREE_VALUE holds the type, and TREE_PURPOSE is the
expression 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 default
argument for parameter %d of `%D' has "

4266

"not yet been
parsed",

4267

parmnum, fn);

4268

return
error_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

"default
argument", 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

"default
argument", fn, parmnum);

4290

arg = convert_for_arg_passing
(type, arg);

4291

}

4292

4293

return
arg;

4294

}

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

Then arg

passed for below function at line 4274, is the default argument shared by all
invocations of the function. However, as [3] defines, “
Default arguments are evaluated each time the
function is called

”, so before really evaluate the expression of the
default argument, it needs prepare appropriate copy of arg

and update this local
temparories acclaimed as below.

1259

tree

1260

break_out_target_exprs

(tree t)
in
cp/tree.c

1261

{

1262

static
int target_remap_count;

1263

static
splay_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

return
t;

1279

}

Above walk_tree

traverses the subtree rooted by t

and
executes provided function upon nodes selected by the code of t

. In
first traversal, below function is used. Note that the function always returns
NULL (copy_tree_r

below returns NULL) to force walk_tree

to do full traversal with depth
first (i.e. tp

maybe a tree_list, in which node can contain operands which in turn can be
tree_list again and so on, the visit should be from bottom up); however whether
stepping into the sub-tree (i.e. operand) is controlled by local variable walk_subtrees

(which is passes as argument walk_subtrees

in below function). Before
processing the tree node with the specified function, walk_subtrees

is set as 1; it is
the specified function to decide whether the node is of interesting and needs
to 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

this
point. We used to check !TREE_SIDE_EFFECTS, but then we

1192

failed to copy an ADDR_EXPR of the slot
VAR_DECL.
*/

1193

*walk_subtrees = 0;

1194

return
NULL_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 handled
anything below this

1221

point.

*/

1222

*walk_subtrees = 0;

1223

return
NULL_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

return
copy_tree_r
(tp, walk_subtrees, NULL);

1230

}

For node other than constant or TRAGET_EXPR, copy_tree_r

copies the node
if it is either *_CST (see it is filtered out by TREE_CONSTANT above) or
expression or TREE_LIST or TREE_VEC or OVERLOAD (told by C++ hook of tree_chain_matters_p

below, and note that walk_subtrees

is unchanged here, walk_tree

will step into the sub-nodes of the node and continues copying the structure
accordingly).

1966

tree

1967

copy_tree_r

(tree *tp, int
*walk_subtrees, void *data ATTRIBUTE_UNUSED)

in tree-inline.c

1968

{

1969

enum
tree_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 we
make 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 as
well.
*/

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 we
make copies. So, we

1994

have
to 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

return

NULL_TREE;

2006

}

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

An AGGR_INIT_EXPR represents the initialization as the return value
of a function call, or as the result of a constructor. An AGGR_INIT_EXPR will
only appear as the second operand of a TARGET_EXPR. The first operand to the
AGGR_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 expression
is that returned by the function.

Then if AGGR_INIT_EXPR is used in TRAGET_EXPR, it recurses break_out_target_exprs

to copy this node. With the copied expression, build_cplus_new

generates
code for the initialization.

2007

tree

2008

build_cplus_new

(tree type, tree init)
in
cp/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

return
convert (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

this
is that this expression might be a default argument

2032

expression. In that case, we need a new
temporary every time the

2033

expression is used. That's what
break_out_target_exprs does; it

2034

replaces every AGGR_INIT_EXPR with a copy
that uses a fresh

2035

temporary slot. Then, expand_expr builds up
a call-expression

2036

using
the 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

return
rval;

2052

}

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

.

253

static
tree

254

build_local_temp

(tree type)
in
cp/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 the
initialization is via a constructor call. AGGR_INIT_EXPR constructed at line 2042
will have this temporary as its third operand, which is always a VAR_DECL. And init

is
the AGGR_INIT_EXPR in the original TARGET_EXPR (the address of the third
operand of the AGGR_INIT_EXPR is taken, and this value replaces the first
argument in the argument list. In this case, the value of the expression is the
VAR_DECL given by the third operand to the AGGR_INIT_EXPR; constructors do not
return 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

is
TARGET_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)
in
cp/tree.c

322

{

323

tree slot;

324

325

if (TREE_CODE (init) == TARGET_EXPR)

326

return
init;

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 to
build up a copy constructor call. COND_EXPR is a special

332

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

333

another one
here. A CONSTRUCTOR is aggregate initialization, which

334

is handled
separately. 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 copy
initialization of the type can use a bitwise copy. For which case, it can
simply build TARGET_EXPR; otherwise, it needs perform an lvalue-to-rvalue
conversion, including invoking the copy ctor as below.

590

tree

591

force_rvalue

(tree expr)
in
cvt.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 then
invoking build_cplus_new

to 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, tree
value)
in
cp/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 set
TREE_SIDE_EFFECTS so that expand_expr does not

242

ignore the TARGET_EXPR. If there really turn
out to be no

243

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

244

whatever code is
generated anyhow.
*/

245

TREE_SIDE_EFFECTS (t) = 1;

246

247

return
t;

248

}

For temporary with non-trivial destructor, the compiler needs
generate code to destory the temporary at exitting its scope by invoking the
destructor. So at line 240, cxx_maybe_build_cleanup

generates this code
if necessary.

Now at line 1213 in
bot_manip

,
u

is
the TARGET_EXPR built corresponding to t

. It maps the new version temporary with the old
one. Then, we immediately replace the old one with it. However, it is possible
some sub-nodes within node handled by break_out_target_exprs

, still hold the
reference to this old version, which needs be updated as below.

1236

static
tree

1237

bot_replace

(tree* t,
in
cp/tree.c

1238

int* walk_subtrees
ATTRIBUTE_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

return
NULL_TREE;

1252

}

Back convert_default_arg

, it gets the updated arg

at
line 4274 from break_out_target_exprs

, then the following functions are used
to generate code for the initialization.

5.12.5.2.2.2.3.

Ellipsis arguments

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

.

4161

tree

4162

convert_arg_to_ellipsis

(tree arg)
in
call.c

4163

{

4164

/*
[expr.call]

4165

4166

The
lvalue-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 the
argument has integral or enumeration type that is subject

4172

to the
integral promotions (_conv.prom_), or a floating point

4173

type
that is subject to the floating point promotion

4174

(_conv.fpprom_), the value of the argument
is 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 used
to just warn

4189

here
and do a bitwise copy, but now cp_expr_size will abort if we

4190

try
to do that.

4191

If
the call appears in the context of a sizeof expression,

4192

there is no need to emit a warning, since
the expression won't be

4193

evaluated. We keep the builtin_trap just
as a safety check.
*/

4194

if (!skip_evaluation

)

4195

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

4196

"call will
abort 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

return
arg;

4203

}

[3], clause 5.2.2
“Function call”, terms 7 defines the behavior of compiler upon ellipsis
argument 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_conversion

performs the conversions in exp,

which are used when an lvalue appears in an
rvalue context, and include lvalue-to-rvalue, array-to-pointer, and function-to-pointer
conversion.

1335

tree

1336

decay_conversion

(tree exp)
n
typeck.c

1337

{

1338

tree type;

1339

enum
tree_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

return
error_mark_node;

1353

1354

if (type_unknown_p (exp))

1355

{

1356

cxx_incomplete_type_error
(exp, TREE_TYPE (exp));

1357

return
error_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't
do this for arrays, though; we want the address of the

1365

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

1366

of its
initializing 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 the
result not an lvalue.

1374

Leave
such NOP_EXPRs, since RHS is being used in non-lvalue context.
*/

1375

1376

if (code == VOID_TYPE)

1377

{

1378

error ("void value
not ignored as it ought to be");

1379

return
error_mark_node;

1380

}

1381

if (invalid_nonstatic_memfn_p
(exp))

1382

return
error_mark_node;

1383

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

1384

return
build_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

return
build_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

return
build
(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 use
of non-lvalue array");

1405

return
error_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

return
adr;

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

return
cp_convert (ptrtype, adr);

1422

}

1423

1424

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

1425

rvalues always have cv-unqualified
types.
*/

1426

if (! CLASS_TYPE_P (type))

1427

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

1428

1429

return
exp;

1430

}

First for REFERENCE_TYPE, it is a lvalue, to change it to rvalue, it
should uses the value referred instead of holding reference any more. In
front-end, INDIRECT_REF is built for the purpose (it because reference always
has its address passed just like pointer, and in compiler, the mode of
reference is the same as pointer, both are ptr_mode

, see build_reference_type

).

566

tree

567

convert_from_reference

(tree val)
in
cvt.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 at
line 1390 is satisfied, if we are using expression like: int *a[i] (a is array
having dimensions more than 1, for example, int A[2][2]), so it builds type
like: int**, and see converting pointer of “int *a[i]” to “int**” needesn’t
generate any code, NOP_EXPR is built for such conversion.

Further if exp

simply is a declaration of an array, for
exmaple: int a[8], rvalue of this declaration is just “int*”. It can build this
rvalue directly. However, for other cases, for example: tempA.a (it is a tree
rooted by SCOPE_REF), it is not a simple rule we can use directly, so it asks build_unary_op

and cp_convert

to do the appropriate conversion.

As comment at line 4188 in
convert_arg_to_ellipsis

mentions, for the undefined behavior of non-POD class type, GCC once uses
bitwise copy, but this behavior will cause later invocation of cp_expr_size

triggering abort in current version. This abort is triggered by below
invocation of “__builtin_trap”, which is included in arg

of COMPOUND_EXPR at line 4198.

4148

c
tree

4149

call_builtin_trap

(void)
in
call.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

return
fn;

4156

}

The behavior of the builtin trap will use trap if the target machine
defines it; otherwise the compiler will call abort

() (see expand_builtin_trap

).

Below is an
interesting 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 out
following warning:

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

test2.cpp:11: warning: cannot receive objects of
non-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-POD
type ‘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 then
gives warning as:

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

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

And at execution, no error will be output, as func(1, a) will not be
evaluated except its returned value.
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: