void gen_expr_assign_compound(expr *e) { /* int += float * lea int, cast up to float, add, cast down to int, store */ lea_expr(e->bits.compound_upcast ? expr_cast_child(e->lhs) : e->lhs); if(e->assign_is_post){ out_dup(); out_deref(); out_flush_volatile(); out_swap(); out_comment("saved for compound op"); } out_dup(); /* delay the dereference until after generating rhs. * this is fine, += etc aren't sequence points */ gen_expr(e->rhs); /* here's the delayed dereference */ out_swap(); out_deref(); if(e->bits.compound_upcast) out_cast(e->lhs->tree_type, /*normalise_bool:*/1); out_swap(); out_op(e->op); if(e->bits.compound_upcast) /* need to cast back down to store */ out_cast(e->tree_type, /*normalise_bool:*/1); out_store(); if(e->assign_is_post) out_pop(); }
static void fold_cast_num(expr *const e, numeric *const num) { int to_fp, from_fp; to_fp = type_is_floating(e->tree_type); from_fp = type_is_floating(expr_cast_child(e)->tree_type); if(to_fp){ if(from_fp){ UCC_ASSERT(K_FLOATING(*num), "i/f mismatch types"); /* float -> float - nothing to see here */ }else{ UCC_ASSERT(K_INTEGRAL(*num), "i/f mismatch types"); /* int -> float */ if(num->suffix & VAL_UNSIGNED){ num->val.f = num->val.i; }else{ /* force a signed conversion, long long to long double */ num->val.f = (sintegral_t)num->val.i; } } /* perform the trunc */ switch(type_primitive(e->tree_type)){ default: ICE("fp expected"); #define TRUNC(cse, ty, bmask) \ case type_ ## cse: \ num->val.f = (ty)num->val.f; \ num->suffix = bmask; \ break TRUNC(float, float, VAL_FLOAT); TRUNC(double, double, VAL_DOUBLE); TRUNC(ldouble, long double, VAL_LDOUBLE); #undef TRUNC } return; }else if(from_fp){ UCC_ASSERT(K_FLOATING(*num), "i/f mismatch types"); /* special case _Bool */ if(type_is_primitive(e->tree_type, type__Bool)){ num->val.i = !!num->val.f; }else{ /* float -> int */ num->val.i = num->val.f; } num->suffix = 0; /* fall through to int logic */ } UCC_ASSERT(K_INTEGRAL(*num), "fp const?"); #define pv (&num->val.i) /* need to cast the val.i down as appropriate */ if(type_is_primitive(e->tree_type, type__Bool)){ *pv = !!*pv; /* analagous to out/out.c::out_normalise()'s constant case */ }else if(!from_fp){ *pv = convert_integral_to_integral_warn( *pv, e->expr->tree_type, e->tree_type, e->expr_cast_implicit, &e->where); } #undef pv }
void fold_expr_funcall(expr *e, symtable *stab) { type *func_ty; funcargs *args_from_decl; char *sp = NULL; unsigned count_decl; check_implicit_funcall(e, stab, &sp); FOLD_EXPR(e->expr, stab); func_ty = e->expr->tree_type; if(!type_is_callable(func_ty)){ warn_at_print_error(&e->expr->where, "%s-expression (type '%s') not callable", expr_str_friendly(e->expr, 0), type_to_str(func_ty)); fold_had_error = 1; e->tree_type = type_nav_btype(cc1_type_nav, type_int); return; } e->tree_type = type_func_call(func_ty, &args_from_decl); /* func count comparison, only if the func has arg-decls, or the func is f(void) */ UCC_ASSERT(args_from_decl, "no funcargs for decl %s", sp); count_decl = dynarray_count(args_from_decl->arglist); if(check_arg_counts(args_from_decl, count_decl, e->funcargs, e, sp)) return; if(e->funcargs){ check_arg_voidness_and_nonnulls( e, stab, args_from_decl, count_decl, e->funcargs, sp); } if(!FUNCARGS_EMPTY_NOVOID(args_from_decl)) check_arg_types(args_from_decl, e->funcargs, stab, sp, &e->where); if(e->funcargs) default_promote_args(e->funcargs, count_decl, stab); if(type_is_s_or_u(e->tree_type)){ /* handled transparently by the backend */ e->f_islval = expr_is_lval_struct; cc1_warn_at(&e->expr->where, aggregate_return, "called function returns aggregate (%s)", type_to_str(e->tree_type)); } /* attr */ { type *fnty = e->expr->tree_type; /* look through decays */ if(expr_kind(e->expr, cast) && expr_cast_is_lval2rval(e->expr)) fnty = expr_cast_child(e->expr)->tree_type; format_check_call(fnty, e->funcargs, args_from_decl->variadic); sentinel_check( &e->where, e, e->funcargs, args_from_decl->variadic, count_decl, stab); } /* check the subexp tree type to get the funcall attributes */ if(func_or_builtin_attr_present(e, attr_warn_unused)) e->freestanding = 0; /* needs use */ if(sp && !cc1_fopt.freestanding) check_standard_funcs(sp, e->funcargs); }