📄 cp-cvt.c
字号:
case INIT_EXPR: { tree real_reference = build_up_reference (type, TREE_OPERAND (targ, 0), LOOKUP_PROTECT, checkconst); rval = build (COMPOUND_EXPR, type, arg, real_reference); TREE_CONSTANT (rval) = staticp (TREE_OPERAND (targ, 0)); return rval; } case COND_EXPR: return build (COND_EXPR, type, TREE_OPERAND (targ, 0), build_up_reference (type, TREE_OPERAND (targ, 1), LOOKUP_PROTECT, checkconst), build_up_reference (type, TREE_OPERAND (targ, 2), LOOKUP_PROTECT, checkconst)); case WITH_CLEANUP_EXPR: return build (WITH_CLEANUP_EXPR, type, build_up_reference (type, TREE_OPERAND (targ, 0), LOOKUP_PROTECT, checkconst), 0, TREE_OPERAND (targ, 2)); case BIND_EXPR: arg = TREE_OPERAND (targ, 1); if (arg == NULL_TREE) { compiler_error ("({ ... }) expression not expanded when needed for reference"); return error_mark_node; } rval = build1 (ADDR_EXPR, type, arg); TREE_REFERENCE_EXPR (rval) = 1; return rval; default: break; } if (TREE_ADDRESSABLE (targ) == 0) { tree temp; if (TREE_CODE (targ) == CALL_EXPR && IS_AGGR_TYPE (argtype)) { temp = build_cplus_new (argtype, targ, 1); rval = build1 (ADDR_EXPR, type, temp); goto done; } else { temp = get_temp_name (argtype, 0); if (global_bindings_p ()) { /* Give this new temp some rtl and initialize it. */ DECL_INITIAL (temp) = targ; TREE_STATIC (temp) = 1; finish_decl (temp, targ, NULL_TREE, 0); /* Do this after declaring it static. */ rval = build_unary_op (ADDR_EXPR, temp, 0); literal_flag = TREE_CONSTANT (rval); goto done; } else { rval = build_unary_op (ADDR_EXPR, temp, 0); /* Put a value into the rtl. */ if (IS_AGGR_TYPE (argtype)) { /* This may produce surprising results, since we commit to initializing the temp when the temp may not actually get used. */ expand_aggr_init (temp, targ, 0); TREE_TYPE (rval) = type; literal_flag = TREE_CONSTANT (rval); goto done; } else { if (binfo && !BINFO_OFFSET_ZEROP (binfo)) rval = convert_pointer_to (target_type, rval); else TREE_TYPE (rval) = type; return build (COMPOUND_EXPR, type, build (MODIFY_EXPR, argtype, temp, arg), rval); } } } } else { if (TREE_CODE (arg) == SAVE_EXPR) my_friendly_abort (5); rval = build1 (ADDR_EXPR, type, arg); } done_but_maybe_warn: if (checkconst && TREE_READONLY (arg) && ! TYPE_READONLY (target_type)) readonly_warning_or_error (arg, "conversion to reference"); done: if (TYPE_USES_COMPLEX_INHERITANCE (argtype)) { TREE_TYPE (rval) = TYPE_POINTER_TO (argtype); rval = convert_pointer_to (target_type, rval); TREE_TYPE (rval) = type; } TREE_CONSTANT (rval) = literal_flag; return rval;}/* For C++: Only need to do one-level references, but cannot get tripped up on signed/unsigned differences. If DECL is NULL_TREE it means convert as though casting (by force). If it is ERROR_MARK_NODE, it means the conversion is implicit, and that temporaries may be created. Make sure the use of user-defined conversion operators is un-ambiguous. Otherwise, DECL is a _DECL node which can be used in error reporting. FNDECL, PARMNUM, and ERRTYPE are only used when checking for use of volatile or const references where they aren't desired. */treeconvert_to_reference (decl, reftype, expr, fndecl, parmnum, errtype, strict, flags) tree decl; tree reftype, expr; tree fndecl; int parmnum; char *errtype; int strict, flags;{ register tree type = TYPE_MAIN_VARIANT (TREE_TYPE (reftype)); register tree intype = TREE_TYPE (expr); register enum tree_code form = TREE_CODE (intype); tree rval = NULL_TREE; if (form == REFERENCE_TYPE) intype = TREE_TYPE (intype); intype = TYPE_MAIN_VARIANT (intype); /* @@ Probably need to have a check for X(X&) here. */ if (IS_AGGR_TYPE (intype)) { rval = build_type_conversion (CONVERT_EXPR, reftype, expr, 1); if (rval) { if (rval == error_mark_node) error ("ambiguous pointer conversion"); return rval; } else if (type != intype && (rval = build_type_conversion (CONVERT_EXPR, type, expr, 1))) { if (rval == error_mark_node) return rval; if (TYPE_NEEDS_DESTRUCTOR (type)) { rval = convert_to_reference (NULL_TREE, reftype, rval, NULL_TREE, -1, (char *)NULL, strict, flags); } else { decl = get_temp_name (type, 0); rval = build (INIT_EXPR, type, decl, rval); rval = build (COMPOUND_EXPR, reftype, rval, convert_to_reference (NULL_TREE, reftype, decl, NULL_TREE, -1, (char *)NULL, strict, flags)); } } if (form == REFERENCE_TYPE && type != intype && TYPE_USES_COMPLEX_INHERITANCE (intype)) { /* If it may move around, build a fresh reference. */ expr = convert_from_reference (expr); form = TREE_CODE (TREE_TYPE (expr)); } } /* @@ Perhaps this should try to go through a constructor first @@ for proper initialization, but I am not sure when that @@ is needed or desirable. @@ The second disjunct is provided to make references behave @@ as some people think they should, i.e., an interconvertability @@ between references to builtin types (such as short and @@ unsigned short). There should be no conversion between @@ types whose codes are different, or whose sizes are different. */ if (((IS_AGGR_TYPE (type) || IS_AGGR_TYPE (intype)) && comptypes (type, intype, strict)) || (!IS_AGGR_TYPE (type) && TREE_CODE (type) == TREE_CODE (intype) && int_size_in_bytes (type) == int_size_in_bytes (intype))) { /* Section 13. */ /* Since convert_for_initialization didn't call convert_for_assignment, we have to do this checking here. XXX We should have a common routine between here and convert_for_assignment. */ if (TREE_CODE (TREE_TYPE (expr)) == REFERENCE_TYPE) { register tree ttl = TREE_TYPE (reftype); register tree ttr = TREE_TYPE (TREE_TYPE (expr)); if (! TYPE_READONLY (ttl) && TYPE_READONLY (ttr)) warn_for_assignment ("%s of non-`const &' reference from `const &'", "reference to const given for argument %d of `%s'", errtype, fndecl, parmnum, pedantic); if (! TYPE_VOLATILE (ttl) && TYPE_VOLATILE (ttr)) warn_for_assignment ("%s of non-`volatile &' reference from `volatile &'", "reference to volatile given for argument %d of `%s'", errtype, fndecl, parmnum, pedantic); } /* If EXPR is of aggregate type, and is really a CALL_EXPR, then we don't need to convert it to reference type if it is only being used to initialize DECL which is also of the same aggregate type. */ if (form == REFERENCE_TYPE || (decl != NULL_TREE && decl != error_mark_node && IS_AGGR_TYPE (type) && TREE_CODE (expr) == CALL_EXPR && TYPE_MAIN_VARIANT (type) == intype)) { if (decl && decl != error_mark_node) { tree e1 = build (INIT_EXPR, void_type_node, decl, expr); tree e2; TREE_SIDE_EFFECTS (e1) = 1; if (form == REFERENCE_TYPE) e2 = build1 (NOP_EXPR, reftype, decl); else { e2 = build_unary_op (ADDR_EXPR, decl, 0); TREE_TYPE (e2) = reftype; TREE_REFERENCE_EXPR (e2) = 1; } return build_compound_expr (tree_cons (NULL_TREE, e1, build_tree_list (NULL_TREE, e2))); } expr = copy_node (expr); TREE_TYPE (expr) = reftype; return expr; } if (decl == error_mark_node) flags |= LOOKUP_PROTECTED_OK; return build_up_reference (reftype, expr, flags, decl!=NULL_TREE); } /* Definitely need to go through a constructor here. */ if (TYPE_HAS_CONSTRUCTOR (type)) { tree init = build_method_call (NULL_TREE, constructor_name (type), build_tree_list (NULL_TREE, expr), TYPE_BINFO (type), LOOKUP_NO_CONVERSION); tree rval1; if (init != error_mark_node) if (rval) { error ("both constructor and type conversion operator apply"); return error_mark_node; } init = build_method_call (NULL_TREE, constructor_name (type), build_tree_list (NULL_TREE, expr), TYPE_BINFO (type), LOOKUP_NORMAL); if (init == error_mark_node) return error_mark_node; rval = build_cplus_new (type, init, 1); if (decl == error_mark_node) flags |= LOOKUP_PROTECTED_OK; return build_up_reference (reftype, rval, flags, decl!=NULL_TREE); } if (rval) { /* If we found a way to convert earlier, then use it. */ return rval; } my_friendly_assert (form != OFFSET_TYPE, 189); /* This is in two pieces for now, because pointer to first becomes invalid once type_as_string is called again. */ error ("cannot convert type `%s'", type_as_string (intype)); error (" to type `%s'", type_as_string (reftype)); return error_mark_node;}/* We are using a reference VAL for its value. Bash that reference all the way down to its lowest form. */treeconvert_from_reference (val) tree val;{ tree type = TREE_TYPE (val); if (TREE_CODE (type) == OFFSET_TYPE) type = TREE_TYPE (type); if (TREE_CODE (type) == REFERENCE_TYPE) { tree target_type = TREE_TYPE (type); /* This can happen if we cast to a reference type. */ if (TREE_CODE (val) == ADDR_EXPR) { val = build1 (NOP_EXPR, build_pointer_type (target_type), val); val = build_indirect_ref (val, 0); return val; } val = build1 (INDIRECT_REF, TYPE_MAIN_VARIANT (target_type), val); TREE_THIS_VOLATILE (val) = TYPE_VOLATILE (target_type); TREE_SIDE_EFFECTS (val) = TYPE_VOLATILE (target_type); TREE_READONLY (val) = TYPE_READONLY (target_type); } return val;}static treeconvert_to_real (type, expr) tree type, expr;{ register enum tree_code form = TREE_CODE (TREE_TYPE (expr)); if (form == REAL_TYPE) return build1 (flag_float_store ? CONVERT_EXPR : NOP_EXPR, type, expr); if (form == INTEGER_TYPE || form == ENUMERAL_TYPE) return build1 (FLOAT_EXPR, type, expr); my_friendly_assert (form != OFFSET_TYPE, 190); if (form == POINTER_TYPE) error ("pointer value used where a floating point value was expected"); /* C++: check to see if we can convert this aggregate type into the required scalar type. */ else if (IS_AGGR_TYPE (TREE_TYPE (expr))) { tree rval; rval = build_type_conversion (CONVERT_EXPR, type, expr, 1); if (rval) return rval; else error ("aggregate value used where a floating point value was expected"); } { register tree tem = make_node (REAL_CST); TREE_TYPE (tem) = type; TREE_REAL_CST (tem) = REAL_VALUE_ATOF ("0.0"); return tem; }}/* The result of this is always supposed to be a newly created tree node not in use in any existing structure. */static treeconvert_to_integer (type, expr) tree type, expr;{ register tree intype = TREE_TYPE (expr); register enum tree_code form = TREE_CODE (intype); extern tree build_binary_op_nodefault (); extern tree build_unary_op (); if (form == POINTER_TYPE) { if (integer_zerop (expr)) expr = integer_zero_node; else expr = fold (build1 (CONVERT_EXPR, type_for_size (POINTER_SIZE, 0), expr)); intype = TREE_TYPE (expr); form = TREE_CODE (intype); if (intype == type) return expr; } if (form == INTEGER_TYPE || form == ENUMERAL_TYPE) { register unsigned outprec = TYPE_PRECISION (type); register unsigned inprec = TYPE_PRECISION (intype); register enum tree_code ex_form = TREE_CODE (expr); if (flag_int_enum_equivalence == 0 && TREE_CODE (type) == ENUMERAL_TYPE && form == INTEGER_TYPE) { if (pedantic) pedwarn ("anachronistic conversion from integer type to enumeral type `%s'", TYPE_NAME_STRING (type)); if (flag_pedantic_errors) return error_mark_node; } /* If we are widening the type, put in an explicit conversion. Similarly if we are not changing the width. However, if this is a logical operation that just returns 0 or 1, we can change the type of the expression (see below). */ if (TREE_CODE_CLASS (ex_form) == '<' || ex_form == TRUTH_AND_EXPR || ex_form == TRUTH_ANDIF_EXPR || ex_form == TRUTH_OR_EXPR || ex_form == TRUTH_ORIF_EXPR || ex_form == TRUTH_NOT_EXPR) { TREE_TYPE (expr) = type; return expr; } else if (outprec >= inprec) return build1 (NOP_EXPR, type, expr);/* Here detect when we can distribute the truncation down past some arithmetic.
⌨️ 快捷键说明
复制代码
Ctrl + C
搜索代码
Ctrl + F
全屏模式
F11
切换主题
Ctrl + Shift + D
显示快捷键
?
增大字号
Ctrl + =
减小字号
Ctrl + -