tree convert (tree type, tree expr) { tree e = expr; enum tree_code code = TREE_CODE (type); const char *invalid_conv_diag; if (type == error_mark_node || expr == error_mark_node || TREE_TYPE (expr) == error_mark_node) return error_mark_node; if ((invalid_conv_diag = targetm.invalid_conversion (TREE_TYPE (expr), type))) { error (invalid_conv_diag); return error_mark_node; } if (type == TREE_TYPE (expr)) return expr; if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr))) return fold_convert (type, expr); if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK) return error_mark_node; if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE) { error ("void value not ignored as it ought to be"); return error_mark_node; } if (code == VOID_TYPE) return fold_convert (type, e); // check if (code == INTEGER_TYPE && TREE_CODE(expr) == STRING_CST) { char *c = TREE_STRING_POINTER(expr)+1; return build_int_cst(type, *c); } if (code == INTEGER_TYPE || code == ENUMERAL_TYPE) return fold (convert_to_integer (type, e)); if (code == BOOLEAN_TYPE) return fold_convert (type, c_objc_common_truthvalue_conversion (expr)); if (code == POINTER_TYPE || code == REFERENCE_TYPE) return fold (convert_to_pointer (type, e)); if (code == REAL_TYPE) return fold (convert_to_real (type, e)); if (code == COMPLEX_TYPE) return fold (convert_to_complex (type, e)); if (code == VECTOR_TYPE) return fold (convert_to_vector (type, e)); if ((code == RECORD_TYPE || code == UNION_TYPE) && lang_hooks.types_compatible_p (type, TREE_TYPE (expr))) return e; error ("conversion to non-scalar type requested"); return error_mark_node; }
tree convert (tree type, tree expr) { tree e = expr; enum tree_code code = TREE_CODE (type); const char *invalid_conv_diag; tree ret; location_t loc = EXPR_LOCATION (expr); if (type == error_mark_node || expr == error_mark_node || TREE_TYPE (expr) == error_mark_node) return error_mark_node; if ((invalid_conv_diag = targetm.invalid_conversion (TREE_TYPE (expr), type))) { error (invalid_conv_diag); return error_mark_node; } if (type == TREE_TYPE (expr)) return expr; ret = targetm.convert_to_type (type, expr); if (ret) return ret; STRIP_TYPE_NOPS (e); if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)) && (TREE_CODE (TREE_TYPE (expr)) != COMPLEX_TYPE || TREE_CODE (e) == COMPLEX_EXPR)) return fold_convert_loc (loc, type, expr); if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK) return error_mark_node; if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE) { error ("void value not ignored as it ought to be"); return error_mark_node; } switch (code) { case VOID_TYPE: return fold_convert_loc (loc, type, e); case INTEGER_TYPE: case ENUMERAL_TYPE: ret = convert_to_integer (type, e); goto maybe_fold; case BOOLEAN_TYPE: return fold_convert_loc (loc, type, c_objc_common_truthvalue_conversion (input_location, expr)); case POINTER_TYPE: case REFERENCE_TYPE: ret = convert_to_pointer (type, e); goto maybe_fold; case REAL_TYPE: ret = convert_to_real (type, e); goto maybe_fold; case FIXED_POINT_TYPE: ret = convert_to_fixed (type, e); goto maybe_fold; case COMPLEX_TYPE: /* If converting from COMPLEX_TYPE to a different COMPLEX_TYPE and e is not COMPLEX_EXPR, convert_to_complex uses save_expr, but for the C FE c_save_expr needs to be called instead. */ if (TREE_CODE (TREE_TYPE (e)) == COMPLEX_TYPE) { if (TREE_CODE (e) != COMPLEX_EXPR) { tree subtype = TREE_TYPE (type); tree elt_type = TREE_TYPE (TREE_TYPE (e)); if (in_late_binary_op) e = save_expr (e); else e = c_save_expr (e); ret = fold_build2_loc (loc, COMPLEX_EXPR, type, convert (subtype, fold_build1 (REALPART_EXPR, elt_type, e)), convert (subtype, fold_build1 (IMAGPART_EXPR, elt_type, e))); goto maybe_fold; } } ret = convert_to_complex (type, e); goto maybe_fold; case VECTOR_TYPE: ret = convert_to_vector (type, e); goto maybe_fold; case RECORD_TYPE: case UNION_TYPE: if (lang_hooks.types_compatible_p (type, TREE_TYPE (expr))) return e; break; default: break; maybe_fold: if (TREE_CODE (ret) != C_MAYBE_CONST_EXPR) ret = fold (ret); return ret; } error ("conversion to non-scalar type requested"); return error_mark_node; }
tree convert (tree type, tree expr) { tree e = expr; enum tree_code code = TREE_CODE (type); const char *invalid_conv_diag; tree ret; location_t loc = EXPR_LOCATION (expr); if (type == error_mark_node || expr == error_mark_node || TREE_TYPE (expr) == error_mark_node) return error_mark_node; if ((invalid_conv_diag = targetm.invalid_conversion (TREE_TYPE (expr), type))) { error (invalid_conv_diag); return error_mark_node; } if (type == TREE_TYPE (expr)) return expr; ret = targetm.convert_to_type (type, expr); if (ret) return ret; STRIP_TYPE_NOPS (e); if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr))) return fold_convert_loc (loc, type, expr); if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK) return error_mark_node; if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE) { error ("void value not ignored as it ought to be"); return error_mark_node; } switch (code) { case VOID_TYPE: return fold_convert_loc (loc, type, e); case INTEGER_TYPE: case ENUMERAL_TYPE: ret = convert_to_integer (type, e); goto maybe_fold; case BOOLEAN_TYPE: return fold_convert_loc (loc, type, c_objc_common_truthvalue_conversion (input_location, expr)); case POINTER_TYPE: case REFERENCE_TYPE: ret = convert_to_pointer (type, e); goto maybe_fold; case REAL_TYPE: ret = convert_to_real (type, e); goto maybe_fold; case FIXED_POINT_TYPE: ret = convert_to_fixed (type, e); goto maybe_fold; case COMPLEX_TYPE: ret = convert_to_complex (type, e); goto maybe_fold; case VECTOR_TYPE: ret = convert_to_vector (type, e); goto maybe_fold; case RECORD_TYPE: case UNION_TYPE: if (lang_hooks.types_compatible_p (type, TREE_TYPE (expr))) return e; break; default: break; maybe_fold: if (TREE_CODE (ret) != C_MAYBE_CONST_EXPR) ret = fold (ret); return ret; } error ("conversion to non-scalar type requested"); return error_mark_node; }
struct c_expr c_parser_binary_expression (c_parser *parser, struct c_expr *after) { /* A binary expression is parsed using operator-precedence parsing, with the operands being cast expressions. All the binary operators are left-associative. Thus a binary expression is of form: E0 op1 E1 op2 E2 ... which we represent on a stack. On the stack, the precedence levels are strictly increasing. When a new operator is encountered of higher precedence than that at the top of the stack, it is pushed; its LHS is the top expression, and its RHS is everything parsed until it is popped. When a new operator is encountered with precedence less than or equal to that at the top of the stack, triples E[i-1] op[i] E[i] are popped and replaced by the result of the operation until the operator at the top of the stack has lower precedence than the new operator or there is only one element on the stack; then the top expression is the LHS of the new operator. In the case of logical AND and OR expressions, we also need to adjust skip_evaluation as appropriate when the operators are pushed and popped. */ /* The precedence levels, where 0 is a dummy lowest level used for the bottom of the stack. */ enum prec { PREC_NONE, PREC_LOGOR, PREC_LOGAND, PREC_BITOR, PREC_BITXOR, PREC_BITAND, PREC_LOGNOT, PREC_EQ, PREC_REL, PREC_SHIFT, PREC_ADD, PREC_MULT, NUM_PRECS }; struct { /* The expression at this stack level. */ struct c_expr expr; /* The precedence of the operator on its left, PREC_NONE at the bottom of the stack. */ enum prec prec; /* The operation on its left. */ #if 0 enum tree_code op; #else int op; #endif } stack[NUM_PRECS]; int sp; #define POP \ do { \ /*switch (stack[sp].op) \ { \ case TRUTH_ANDIF_EXPR: \ skip_evaluation -= stack[sp - 1].expr.value == truthvalue_false_node; \ break; \ case TRUTH_ORIF_EXPR: \ skip_evaluation -= stack[sp - 1].expr.value == truthvalue_true_node; \ break; \ default: \ break; \ }*/ \ stack[sp - 1].expr \ = default_function_array_conversion (stack[sp - 1].expr); \ stack[sp].expr \ = default_function_array_conversion (stack[sp].expr); \ stack[sp - 1].expr = parser_build_binary_op (stack[sp].op, \ stack[sp - 1].expr, \ stack[sp].expr); \ sp--; \ } while (0) #if 0 gcc_assert (!after || c_dialect_objc ()); #endif ; stack[0].expr = c_parser_cast_expression (parser, after); stack[0].prec = PREC_NONE; sp = 0; while (true) { enum prec oprec; #if 0 enum tree_code ocode; #else int ocode; #endif if (parser->error) goto out; switch (c_parser_peek_token (parser)->type) { case '*': case CPP_MULT: oprec = PREC_MULT; ocode = MULT_EXPR; break; #if 0 case '/': case CPP_DIV: oprec = PREC_MULT; ocode = TRUNC_DIV_EXPR; break; case CPP_MOD: oprec = PREC_MULT; ocode = TRUNC_MOD_EXPR; break; #endif case '+': case CPP_PLUS: oprec = PREC_ADD; ocode = PLUS_EXPR; break; case '-': case CPP_MINUS: oprec = PREC_ADD; ocode = MINUS_EXPR; break; #if 0 case CPP_LSHIFT: oprec = PREC_SHIFT; ocode = LSHIFT_EXPR; break; case CPP_RSHIFT: oprec = PREC_SHIFT; ocode = RSHIFT_EXPR; break; #endif case K_LT: case CPP_LESS: oprec = PREC_REL; ocode = LT_EXPR; break; case K_GT: case CPP_GREATER: oprec = PREC_REL; ocode = GT_EXPR; break; case K_LE: case CPP_LESS_EQ: oprec = PREC_REL; ocode = LE_EXPR; break; case K_GE: case CPP_GREATER_EQ: oprec = PREC_REL; ocode = GE_EXPR; break; case K_EQ: case CPP_EQ_EQ: oprec = PREC_EQ; ocode = EQ_EXPR; break; case K_NE: case CPP_NOT_EQ: oprec = PREC_EQ; ocode = NE_EXPR; break; case K_EQS: case K_NES: case K_LES: case K_LTS: case K_GES: case K_GTS: oprec = PREC_EQ; ocode = c_parser_peek_token (parser)->type; break; case K_AND: case CPP_AND: oprec = PREC_BITAND; ocode = BIT_AND_EXPR; break; case CPP_XOR: oprec = PREC_BITXOR; ocode = BIT_XOR_EXPR; break; case K_OR: case CPP_OR: oprec = PREC_BITOR; ocode = BIT_IOR_EXPR; break; case CPP_AND_AND: oprec = PREC_LOGAND; ocode = TRUTH_ANDIF_EXPR; break; case CPP_OR_OR: oprec = PREC_LOGOR; ocode = TRUTH_ORIF_EXPR; break; default: /* Not a binary operator, so end of the binary expression. */ goto out; } c_parser_consume_token (parser); while (oprec <= stack[sp].prec) POP; switch (ocode) { #if 0 case TRUTH_ANDIF_EXPR: stack[sp].expr = default_function_array_conversion (stack[sp].expr); stack[sp].expr.value = c_objc_common_truthvalue_conversion (default_conversion (stack[sp].expr.value)); skip_evaluation += stack[sp].expr.value == truthvalue_false_node; break; case TRUTH_ORIF_EXPR: stack[sp].expr = default_function_array_conversion (stack[sp].expr); stack[sp].expr.value = c_objc_common_truthvalue_conversion (default_conversion (stack[sp].expr.value)); skip_evaluation += stack[sp].expr.value == truthvalue_true_node; break; #endif default: break; } sp++; stack[sp].expr = c_parser_cast_expression (parser, NULL); stack[sp].prec = oprec; stack[sp].op = ocode; } out: while (sp > 0) POP; return stack[0].expr; #undef POP }
tree convert (tree type, tree expr) { tree e = expr; enum tree_code code = TREE_CODE (type); const char *invalid_conv_diag; tree ret; location_t loc = EXPR_LOCATION (expr); if (type == error_mark_node || error_operand_p (expr)) return error_mark_node; if ((invalid_conv_diag = targetm.invalid_conversion (TREE_TYPE (expr), type))) { error (invalid_conv_diag); return error_mark_node; } if (type == TREE_TYPE (expr)) return expr; ret = targetm.convert_to_type (type, expr); if (ret) return ret; STRIP_TYPE_NOPS (e); if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr)) && (TREE_CODE (TREE_TYPE (expr)) != COMPLEX_TYPE || TREE_CODE (e) == COMPLEX_EXPR)) return fold_convert_loc (loc, type, expr); if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK) return error_mark_node; if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE) { error ("void value not ignored as it ought to be"); return error_mark_node; } switch (code) { case VOID_TYPE: return fold_convert_loc (loc, type, e); case INTEGER_TYPE: case ENUMERAL_TYPE: if (flag_sanitize & SANITIZE_FLOAT_CAST && TREE_CODE (TREE_TYPE (expr)) == REAL_TYPE && COMPLETE_TYPE_P (type) && current_function_decl != NULL_TREE && !lookup_attribute ("no_sanitize_undefined", DECL_ATTRIBUTES (current_function_decl))) { tree arg; if (in_late_binary_op) { expr = save_expr (expr); arg = expr; } else { expr = c_save_expr (expr); arg = c_fully_fold (expr, false, NULL); } tree check = ubsan_instrument_float_cast (loc, type, expr, arg); expr = fold_build1 (FIX_TRUNC_EXPR, type, expr); if (check == NULL) return expr; return fold_build2 (COMPOUND_EXPR, TREE_TYPE (expr), check, expr); } ret = convert_to_integer (type, e); goto maybe_fold; case BOOLEAN_TYPE: return fold_convert_loc (loc, type, c_objc_common_truthvalue_conversion (input_location, expr)); case POINTER_TYPE: case REFERENCE_TYPE: ret = convert_to_pointer (type, e); goto maybe_fold; case REAL_TYPE: ret = convert_to_real (type, e); goto maybe_fold; case FIXED_POINT_TYPE: ret = convert_to_fixed (type, e); goto maybe_fold; case COMPLEX_TYPE: /* If converting from COMPLEX_TYPE to a different COMPLEX_TYPE and e is not COMPLEX_EXPR, convert_to_complex uses save_expr, but for the C FE c_save_expr needs to be called instead. */ if (TREE_CODE (TREE_TYPE (e)) == COMPLEX_TYPE) { if (TREE_CODE (e) != COMPLEX_EXPR) { tree subtype = TREE_TYPE (type); tree elt_type = TREE_TYPE (TREE_TYPE (e)); if (in_late_binary_op) e = save_expr (e); else e = c_save_expr (e); ret = fold_build2_loc (loc, COMPLEX_EXPR, type, convert (subtype, fold_build1 (REALPART_EXPR, elt_type, e)), convert (subtype, fold_build1 (IMAGPART_EXPR, elt_type, e))); goto maybe_fold; } } ret = convert_to_complex (type, e); goto maybe_fold; case VECTOR_TYPE: ret = convert_to_vector (type, e); goto maybe_fold; case RECORD_TYPE: case UNION_TYPE: if (lang_hooks.types_compatible_p (type, TREE_TYPE (expr))) return e; break; default: break; maybe_fold: if (TREE_CODE (ret) != C_MAYBE_CONST_EXPR) ret = fold (ret); return ret; } error ("conversion to non-scalar type requested"); return error_mark_node; }
tree convert (tree type, tree expr) { tree e = expr; enum tree_code code = TREE_CODE (type); const char *invalid_conv_diag; if (type == error_mark_node || expr == error_mark_node || TREE_TYPE (expr) == error_mark_node) return error_mark_node; if ((invalid_conv_diag = targetm.invalid_conversion (TREE_TYPE (expr), type))) { error (invalid_conv_diag); return error_mark_node; } if (type == TREE_TYPE (expr)) return expr; if (TYPE_MAIN_VARIANT (type) == TYPE_MAIN_VARIANT (TREE_TYPE (expr))) return fold_build1 (NOP_EXPR, type, expr); if (TREE_CODE (TREE_TYPE (expr)) == ERROR_MARK) return error_mark_node; if (TREE_CODE (TREE_TYPE (expr)) == VOID_TYPE) { error ("void value not ignored as it ought to be"); return error_mark_node; } if (code == VOID_TYPE) return build1 (CONVERT_EXPR, type, e); #if 0 /* This is incorrect. A truncation can't be stripped this way. Extensions will be stripped by the use of get_unwidened. */ if (TREE_CODE (expr) == NOP_EXPR) return convert (type, TREE_OPERAND (expr, 0)); #endif if (code == INTEGER_TYPE || code == ENUMERAL_TYPE) return fold (convert_to_integer (type, e)); if (code == BOOLEAN_TYPE) { tree t = c_objc_common_truthvalue_conversion (expr); if (TREE_CODE (t) == ERROR_MARK) return t; /* If it returns a NOP_EXPR, we must fold it here to avoid infinite recursion between fold () and convert (). */ if (TREE_CODE (t) == NOP_EXPR) return fold_build1 (NOP_EXPR, type, TREE_OPERAND (t, 0)); else return fold_build1 (NOP_EXPR, type, t); } if (code == POINTER_TYPE || code == REFERENCE_TYPE) return fold (convert_to_pointer (type, e)); if (code == REAL_TYPE) return fold (convert_to_real (type, e)); if (code == COMPLEX_TYPE) return fold (convert_to_complex (type, e)); if (code == VECTOR_TYPE) return fold (convert_to_vector (type, e)); if ((code == RECORD_TYPE || code == UNION_TYPE) && lang_hooks.types_compatible_p (type, TREE_TYPE (expr))) return e; error ("conversion to non-scalar type requested"); return error_mark_node; }