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; }