void fold_expr_assign_compound(expr *e, symtable *stab) { const char *const desc = "compound assignment"; #define lvalue e->lhs fold_inc_writes_if_sym(lvalue, stab); fold_expr_nodecay(e->lhs, stab); FOLD_EXPR(e->rhs, stab); fold_check_expr(e->lhs, FOLD_CHK_NO_ST_UN, desc); fold_check_expr(e->rhs, FOLD_CHK_NO_ST_UN, desc); /* skip the addr we inserted */ if(!expr_must_lvalue(lvalue, desc)){ /* prevent ICE from type_size(vla), etc */ e->tree_type = lvalue->tree_type; return; } expr_assign_const_check(lvalue, &e->where); fold_check_restrict(lvalue, e->rhs, desc, &e->where); UCC_ASSERT(op_can_compound(e->bits.compoundop.op), "non-compound op in compound expr"); /*expr_promote_int_if_smaller(&e->lhs, stab); * lhs int promotion is handled in code-gen */ expr_promote_int_if_smaller(&e->rhs, stab); { type *tlhs, *trhs; type *resolved = op_required_promotion( e->bits.compoundop.op, lvalue, e->rhs, &e->where, desc, &tlhs, &trhs); if(tlhs){ /* must cast the lvalue, then down cast once the operation is done * special handling for expr_kind(e->lhs, cast) is done in the gen-code */ e->bits.compoundop.upcast_ty = tlhs; }else if(trhs){ fold_insert_casts(trhs, &e->rhs, stab); } e->tree_type = lvalue->tree_type; (void)resolved; /*type_free_1(resolved); XXX: memleak */ } /* type check is done in op_required_promotion() */ #undef lvalue }
static void check_arg_voidness_and_nonnulls( expr *callexpr, symtable *stab, funcargs *args_from_decl, unsigned count_decl, expr **exprargs, char *sp) { /* this block folds the args and type-checks */ unsigned long nonnulls = 0; unsigned i; attribute *da; if((da = func_or_builtin_attr_present(callexpr, attr_nonnull))) nonnulls = da->bits.nonnull_args; for(i = 0; exprargs[i]; i++){ expr *arg = FOLD_EXPR(exprargs[i], stab); char buf[64]; ARG_BUF(buf, i, sp); if(fold_check_expr(arg, FOLD_CHK_NO_ST_UN, buf)) continue; if(i < count_decl && (nonnulls & (1 << i)) && type_is_ptr(args_from_decl->arglist[i]->ref) && expr_is_null_ptr(arg, NULL_STRICT_INT)) { cc1_warn_at(&arg->where, attr_nonnull, "null passed where non-null required (arg %d)", i + 1); } } }
void fold_expr_assign_compound(expr *e, symtable *stab) { expr *const lvalue = e->lhs; fold_inc_writes_if_sym(lvalue, stab); fold_expr_no_decay(e->lhs, stab); FOLD_EXPR(e->rhs, stab); fold_check_expr(e->lhs, FOLD_CHK_NO_ST_UN, "compound assignment"); fold_check_expr(e->rhs, FOLD_CHK_NO_ST_UN, "compound assignment"); /* skip the addr we inserted */ expr_must_lvalue(lvalue); expr_assign_const_check(lvalue, &e->where); fold_check_restrict(lvalue, e->rhs, "compound assignment", &e->where); UCC_ASSERT(op_can_compound(e->op), "non-compound op in compound expr"); { type *tlhs, *trhs; type *resolved = op_required_promotion(e->op, lvalue, e->rhs, &e->where, &tlhs, &trhs); if(tlhs){ /* must cast the lvalue, then down cast once the operation is done * special handling for expr_kind(e->lhs, cast) is done in the gen-code */ fold_insert_casts(tlhs, &e->lhs, stab); /* casts may be inserted anyway, and don't want to rely on * .implicit_cast stuff */ e->bits.compound_upcast = 1; }else if(trhs){ fold_insert_casts(trhs, &e->rhs, stab); } e->tree_type = lvalue->tree_type; (void)resolved; /*type_free_1(resolved); XXX: memleak */ } /* type check is done in op_required_promotion() */ }
void fold_stmt_if(stmt *s) { fold_check_expr(s->expr, FOLD_CHK_BOOL, s->f_str()); fold_stmt(s->lhs); if(s->rhs) fold_stmt(s->rhs); }
void fold_stmt_for(stmt *s) { if(s->flow->for_while){ fold_check_expr( s->flow->for_while, FOLD_CHK_NO_ST_UN | FOLD_CHK_BOOL, "for-test"); } fold_stmt(s->lhs); }
void fold_stmt_case_range(stmt *s) { integral_t lv, rv; FOLD_EXPR(s->expr, s->symtab); FOLD_EXPR(s->expr2, s->symtab); fold_check_expr(s->expr, FOLD_CHK_INTEGRAL | FOLD_CHK_CONST_I, "case-range"); lv = const_fold_val_i(s->expr); fold_check_expr(s->expr2, FOLD_CHK_INTEGRAL | FOLD_CHK_CONST_I, "case-range"); rv = const_fold_val_i(s->expr2); if(lv >= rv) die_at(&s->where, "case range equal or inverse"); s->bits.case_lbl = out_label_case(CASE_RANGE, lv); fold_stmt_and_add_to_curswitch(s, &s->bits.case_lbl); }
void fold_expr_addr(expr *e, symtable *stab) { if(e->bits.lbl.spel){ decl *in_func = symtab_func(stab); if(!in_func) die_at(&e->where, "address-of-label outside a function"); if(e->bits.lbl.static_ctx) in_func->bits.func.contains_static_label_addr = 1; (e->bits.lbl.label = symtab_label_find_or_new( stab, e->bits.lbl.spel, &e->where)) ->uses++; /* address of label - void * */ e->tree_type = type_ptr_to(type_nav_btype(cc1_type_nav, type_void)); }else{ /* if it's an identifier, act as a read */ fold_inc_writes_if_sym(e->lhs, stab); fold_expr_nodecay(e->lhs, stab); e->tree_type = type_ptr_to(e->lhs->tree_type); /* can address: lvalues, arrays and functions */ if(!expr_is_addressable(e->lhs)){ warn_at_print_error(&e->where, "can't take the address of %s (%s)", expr_str_friendly(e->lhs), type_to_str(e->lhs->tree_type)); fold_had_error = 1; return; } if(expr_kind(e->lhs, identifier)){ sym *sym = e->lhs->bits.ident.bits.ident.sym; if(sym){ decl *d = sym->decl; if((d->store & STORE_MASK_STORE) == store_register) die_at(&e->lhs->where, "can't take the address of register"); } } fold_check_expr(e->lhs, FOLD_CHK_ALLOW_VOID | FOLD_CHK_NO_BITFIELD, "address-of"); } }
void fold_expr_stmt(expr *e, symtable *stab) { stmt *last_stmt; int last; (void)stab; last = dynarray_count(e->code->bits.code.stmts); if(last){ last_stmt = e->code->bits.code.stmts[last - 1]; last_stmt->freestanding = 1; /* allow the final to be freestanding */ last_stmt->expr_no_pop = 1; } fold_stmt(e->code); /* symtab should've been set by parse */ if(last && stmt_kind(last_stmt, expr)){ expr *last_expr = last_stmt->expr; e->tree_type = last_expr->tree_type; if(fold_check_expr(e, FOLD_CHK_ALLOW_VOID, "({ ... }) statement")) { return; } switch(expr_is_lval(last_expr)){ case LVALUE_NO: break; case LVALUE_STRUCT: case LVALUE_USER_ASSIGNABLE: e->f_islval = expr_is_lval_struct; } }else{ e->tree_type = type_nav_btype(cc1_type_nav, type_void); } e->freestanding = 1; /* ({ ... }) on its own is freestanding */ }
void fold_expr_if(expr *e, symtable *stab) { const char *desc = "?:"; consty konst; type *tt_l, *tt_r; FOLD_EXPR(e->expr, stab); const_fold(e->expr, &konst); fold_check_expr(e->expr, FOLD_CHK_NO_ST_UN, desc); if(e->lhs){ e->lhs = fold_expr_nonstructdecay(e->lhs, stab); fold_check_expr(e->lhs, FOLD_CHK_ALLOW_VOID, "?: left operand"); } e->rhs = fold_expr_nonstructdecay(e->rhs, stab); fold_check_expr(e->rhs, FOLD_CHK_ALLOW_VOID, "?: right operand"); e->freestanding = (e->lhs ? e->lhs : e->expr)->freestanding || e->rhs->freestanding; /* Arithmetic Arithmetic Arithmetic type after usual arithmetic conversions Structure or union type Compatible structure or union type Structure or union type with all the qualifiers on both operands void void void Pointer to compatible type Pointer to compatible type Pointer to type with all the qualifiers specified for the type Pointer to type NULL pointer (the constant 0) Pointer to type Pointer to object or incomplete type Pointer to void Pointer to void with all the qualifiers specified for the type GCC and Clang seem to relax the last rule: a) resolve if either is any pointer, not just (void *) b) resolve to a pointer to the incomplete-type */ tt_l = (e->lhs ? e->lhs : e->expr)->tree_type; tt_r = e->rhs->tree_type; /* C11 6.5.15 */ if(type_is_arith(tt_l) && type_is_arith(tt_r)){ /* 6.5.15 p4 */ expr **middle_op = e->lhs ? &e->lhs : &e->expr; expr_check_sign(desc, *middle_op, e->rhs, &e->where); e->tree_type = op_promote_types( op_unknown, middle_op, &e->rhs, stab, &e->where, desc); }else if(type_is_void(tt_l) || type_is_void(tt_r)){ e->tree_type = type_nav_btype(cc1_type_nav, type_void); }else{ const enum type_cmp cmp = type_cmp(tt_l, tt_r, 0); if((cmp & (TYPE_EQUAL_ANY | TYPE_QUAL_ADD | TYPE_QUAL_SUB)) && type_is_s_or_u(tt_l)) { e->f_islval = expr_is_lval_struct; e->tree_type = type_qualify(tt_l, type_qual(tt_l) | type_qual(tt_r)); }else{ try_pointer_propagate(e, cmp, tt_l, tt_r); } } }
void fold_expr_if(expr *e, symtable *stab) { consty konst; type *tt_l, *tt_r; FOLD_EXPR(e->expr, stab); const_fold(e->expr, &konst); fold_check_expr(e->expr, FOLD_CHK_NO_ST_UN, "if-expr"); if(e->lhs){ FOLD_EXPR(e->lhs, stab); fold_check_expr(e->lhs, FOLD_CHK_NO_ST_UN | FOLD_CHK_ALLOW_VOID, "if-lhs"); } FOLD_EXPR(e->rhs, stab); fold_check_expr(e->rhs, FOLD_CHK_NO_ST_UN | FOLD_CHK_ALLOW_VOID, "if-rhs"); /* Arithmetic Arithmetic Arithmetic type after usual arithmetic conversions // Structure or union type Compatible structure or union type Structure or union type with all the qualifiers on both operands void void void Pointer to compatible type Pointer to compatible type Pointer to type with all the qualifiers specified for the type Pointer to type NULL pointer (the constant 0) Pointer to type Pointer to object or incomplete type Pointer to void Pointer to void with all the qualifiers specified for the type GCC and Clang seem to relax the last rule: a) resolve if either is any pointer, not just (void *) b) resolve to a pointer to the incomplete-type */ tt_l = (e->lhs ? e->lhs : e->expr)->tree_type; tt_r = e->rhs->tree_type; if(type_is_integral(tt_l) && type_is_integral(tt_r)){ expr **middle_op = e->lhs ? &e->lhs : &e->expr; expr_check_sign("?:", *middle_op, e->rhs, &e->where); e->tree_type = op_promote_types( op_unknown, middle_op, &e->rhs, &e->where, stab); }else if(type_is_void(tt_l) || type_is_void(tt_r)){ e->tree_type = type_nav_btype(cc1_type_nav, type_void); }else if(type_cmp(tt_l, tt_r, 0) & TYPE_EQUAL_ANY){ /* pointer to 'compatible' type */ e->tree_type = type_qualify(tt_l, type_qual(tt_l) | type_qual(tt_r)); }else{ /* brace yourself. */ int l_ptr_null = expr_is_null_ptr( e->lhs ? e->lhs : e->expr, NULL_STRICT_VOID_PTR); int r_ptr_null = expr_is_null_ptr(e->rhs, NULL_STRICT_VOID_PTR); int l_complete = !l_ptr_null && type_is_complete(tt_l); int r_complete = !r_ptr_null && type_is_complete(tt_r); if((l_complete && r_ptr_null) || (r_complete && l_ptr_null)){ e->tree_type = l_ptr_null ? tt_r : tt_l; }else{ int l_ptr = l_ptr_null || type_is(tt_l, type_ptr); int r_ptr = r_ptr_null || type_is(tt_r, type_ptr); if(l_ptr || r_ptr){ fold_type_chk_warn( tt_l, tt_r, &e->where, "?: pointer type mismatch"); /* qualified void * */ e->tree_type = type_qualify( type_ptr_to(type_nav_btype(cc1_type_nav, type_void)), type_qual(tt_l) | type_qual(tt_r)); }else{ char buf[TYPE_STATIC_BUFSIZ]; warn_at(&e->where, "conditional type mismatch (%s vs %s)", type_to_str(tt_l), type_to_str_r(buf, tt_r)); e->tree_type = type_nav_btype(cc1_type_nav, type_void); } } } e->freestanding = (e->lhs ? e->lhs : e->expr)->freestanding || e->rhs->freestanding; }