/* * sparse/evaluate.c * * Copyright (C) 2003 Transmeta Corp. * 2003-2004 Linus Torvalds * * Permission is hereby granted, free of charge, to any person obtaining a copy * of this software and associated documentation files (the "Software"), to deal * in the Software without restriction, including without limitation the rights * to use, copy, modify, merge, publish, distribute, sublicense, and/or sell * copies of the Software, and to permit persons to whom the Software is * furnished to do so, subject to the following conditions: * * The above copyright notice and this permission notice shall be included in * all copies or substantial portions of the Software. * * THE SOFTWARE IS PROVIDED "AS IS", WITHOUT WARRANTY OF ANY KIND, EXPRESS OR * IMPLIED, INCLUDING BUT NOT LIMITED TO THE WARRANTIES OF MERCHANTABILITY, * FITNESS FOR A PARTICULAR PURPOSE AND NONINFRINGEMENT. IN NO EVENT SHALL THE * AUTHORS OR COPYRIGHT HOLDERS BE LIABLE FOR ANY CLAIM, DAMAGES OR OTHER * LIABILITY, WHETHER IN AN ACTION OF CONTRACT, TORT OR OTHERWISE, ARISING FROM, * OUT OF OR IN CONNECTION WITH THE SOFTWARE OR THE USE OR OTHER DEALINGS IN * THE SOFTWARE. * * Evaluate constant expressions. */ #include #include #include #include #include #include #include #include #include #include "evaluate.h" #include "lib.h" #include "allocate.h" #include "parse.h" #include "token.h" #include "symbol.h" #include "target.h" #include "expression.h" struct symbol *current_fn; struct ident bad_address_space = { .len = 6, .name = "bad AS", }; static struct symbol *degenerate(struct expression *expr); static struct symbol *evaluate_symbol(struct symbol *sym); static inline int valid_expr_type(struct expression *expr) { return expr && valid_type(expr->ctype); } static inline int valid_subexpr_type(struct expression *expr) { return valid_expr_type(expr->left) && valid_expr_type(expr->right); } static struct symbol *evaluate_symbol_expression(struct expression *expr) { struct expression *addr; struct symbol *sym = expr->symbol; struct symbol *base_type; if (!sym) { expression_error(expr, "undefined identifier '%s'", show_ident(expr->symbol_name)); return NULL; } examine_symbol_type(sym); base_type = get_base_type(sym); if (!base_type) { expression_error(expr, "identifier '%s' has no type", show_ident(expr->symbol_name)); return NULL; } addr = alloc_expression(expr->pos, EXPR_SYMBOL); addr->symbol = sym; addr->symbol_name = expr->symbol_name; addr->ctype = &lazy_ptr_ctype; /* Lazy evaluation: we need to do a proper job if somebody does &sym */ addr->flags = expr->flags; expr->type = EXPR_PREOP; expr->op = '*'; expr->unop = addr; expr->flags = CEF_NONE; /* The type of a symbol is the symbol itself! */ expr->ctype = sym; return sym; } static struct symbol *evaluate_string(struct expression *expr) { struct symbol *sym = alloc_symbol(expr->pos, SYM_NODE); struct symbol *array = alloc_symbol(expr->pos, SYM_ARRAY); struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL); struct expression *initstr = alloc_expression(expr->pos, EXPR_STRING); unsigned int length = expr->string->length; sym->array_size = alloc_const_expression(expr->pos, length); sym->bit_size = bytes_to_bits(length); sym->ctype.alignment = 1; sym->string = 1; sym->ctype.modifiers = MOD_STATIC; sym->ctype.base_type = array; sym->initializer = initstr; initstr->ctype = sym; initstr->string = expr->string; array->array_size = sym->array_size; array->bit_size = bytes_to_bits(length); array->ctype.alignment = 1; array->ctype.modifiers = MOD_STATIC; array->ctype.base_type = &char_ctype; addr->symbol = sym; addr->ctype = &lazy_ptr_ctype; addr->flags = CEF_ADDR; expr->type = EXPR_PREOP; expr->op = '*'; expr->unop = addr; expr->ctype = sym; return sym; } /* type has come from classify_type and is an integer type */ static inline struct symbol *integer_promotion(struct symbol *type) { unsigned long mod = type->ctype.modifiers; int width = type->bit_size; /* * Bitfields always promote to the base type, * even if the bitfield might be bigger than * an "int". */ if (type->type == SYM_BITFIELD) { type = type->ctype.base_type; } mod = type->ctype.modifiers; if (width < bits_in_int) return &int_ctype; /* If char/short has as many bits as int, it still gets "promoted" */ if (mod & (MOD_CHAR | MOD_SHORT)) { if (mod & MOD_UNSIGNED) return &uint_ctype; return &int_ctype; } return type; } /* * integer part of usual arithmetic conversions: * integer promotions are applied * if left and right are identical, we are done * if signedness is the same, convert one with lower rank * unless unsigned argument has rank lower than signed one, convert the * signed one. * if signed argument is bigger than unsigned one, convert the unsigned. * otherwise, convert signed. * * Leaving aside the integer promotions, that is equivalent to * if identical, don't convert * if left is bigger than right, convert right * if right is bigger than left, convert right * otherwise, if signedness is the same, convert one with lower rank * otherwise convert the signed one. */ static struct symbol *bigger_int_type(struct symbol *left, struct symbol *right) { unsigned long lmod, rmod; left = integer_promotion(left); right = integer_promotion(right); if (left == right) goto left; if (left->bit_size > right->bit_size) goto left; if (right->bit_size > left->bit_size) goto right; lmod = left->ctype.modifiers; rmod = right->ctype.modifiers; if ((lmod ^ rmod) & MOD_UNSIGNED) { if (lmod & MOD_UNSIGNED) goto left; } else if ((lmod & ~rmod) & (MOD_LONG_ALL)) goto left; right: left = right; left: return left; } static int same_cast_type(struct symbol *orig, struct symbol *new) { return orig->bit_size == new->bit_size && orig->bit_offset == new->bit_offset; } static struct symbol *base_type(struct symbol *node, unsigned long *modp, struct ident **asp) { unsigned long mod = 0; struct ident *as = NULL; while (node) { mod |= node->ctype.modifiers; combine_address_space(node->pos, &as, node->ctype.as); if (node->type == SYM_NODE) { node = node->ctype.base_type; continue; } break; } *modp = mod & ~MOD_IGNORE; *asp = as; return node; } static int is_same_type(struct expression *expr, struct symbol *new) { struct symbol *old = expr->ctype; unsigned long oldmod, newmod; struct ident *oldas, *newas; old = base_type(old, &oldmod, &oldas); new = base_type(new, &newmod, &newas); /* Same base type, same address space? */ if (old == new && oldas == newas) { unsigned long difmod; /* Check the modifier bits. */ difmod = (oldmod ^ newmod) & ~MOD_NOCAST; /* Exact same type? */ if (!difmod) return 1; /* * Not the same type, but differs only in "const". * Don't warn about MOD_NOCAST. */ if (difmod == MOD_CONST) return 0; } if ((oldmod | newmod) & MOD_NOCAST) { const char *tofrom = "to/from"; if (!(newmod & MOD_NOCAST)) tofrom = "from"; if (!(oldmod & MOD_NOCAST)) tofrom = "to"; warning(expr->pos, "implicit cast %s nocast type", tofrom); } return 0; } static void warn_for_different_enum_types (struct position pos, struct symbol *typea, struct symbol *typeb) { if (!Wenum_mismatch) return; if (typea->type == SYM_NODE) typea = typea->ctype.base_type; if (typeb->type == SYM_NODE) typeb = typeb->ctype.base_type; if (typea == typeb) return; if (typea->type == SYM_ENUM && typeb->type == SYM_ENUM) { warning(pos, "mixing different enum types"); info(pos, " %s versus", show_typename(typea)); info(pos, " %s", show_typename(typeb)); } } static int cast_flags(struct expression *expr, struct expression *target); static struct symbol *cast_to_bool(struct expression *expr); /* * This gets called for implicit casts in assignments and * integer promotion. We often want to try to move the * cast down, because the ops involved may have been * implicitly cast up, and we can get rid of the casts * early. */ static struct expression * cast_to(struct expression *old, struct symbol *type) { struct expression *expr; warn_for_different_enum_types (old->pos, old->ctype, type); if (old->ctype != &null_ctype && is_same_type(old, type)) return old; /* * See if we can simplify the op. Move the cast down. */ switch (old->type) { case EXPR_PREOP: if (old->ctype->bit_size < type->bit_size) break; if (old->op == '~') { old->ctype = type; old->unop = cast_to(old->unop, type); return old; } break; case EXPR_IMPLIED_CAST: warn_for_different_enum_types(old->pos, old->ctype, type); if (old->ctype->bit_size >= type->bit_size) { struct expression *orig = old->cast_expression; if (same_cast_type(orig->ctype, type)) return orig; if (old->ctype->bit_offset == type->bit_offset) { old->ctype = type; old->cast_type = type; return old; } } break; default: /* nothing */; } expr = alloc_expression(old->pos, EXPR_IMPLIED_CAST); expr->ctype = type; expr->cast_type = type; expr->cast_expression = old; expr->flags = cast_flags(expr, old); if (is_bool_type(type)) cast_to_bool(expr); return expr; } enum { TYPE_NUM = 1, TYPE_BITFIELD = 2, TYPE_RESTRICT = 4, TYPE_FLOAT = 8, TYPE_PTR = 16, TYPE_COMPOUND = 32, TYPE_FOULED = 64, TYPE_FN = 128, }; static inline int classify_type(struct symbol *type, struct symbol **base) { static int type_class[SYM_BAD + 1] = { [SYM_PTR] = TYPE_PTR, [SYM_FN] = TYPE_PTR | TYPE_FN, [SYM_ARRAY] = TYPE_PTR | TYPE_COMPOUND, [SYM_STRUCT] = TYPE_COMPOUND, [SYM_UNION] = TYPE_COMPOUND, [SYM_BITFIELD] = TYPE_NUM | TYPE_BITFIELD, [SYM_RESTRICT] = TYPE_NUM | TYPE_RESTRICT, [SYM_FOULED] = TYPE_NUM | TYPE_RESTRICT | TYPE_FOULED, }; if (type->type == SYM_NODE) type = type->ctype.base_type; if (type->type == SYM_TYPEOF) { type = evaluate_expression(type->initializer); if (!type) type = &bad_ctype; else if (type->type == SYM_NODE) type = type->ctype.base_type; } if (type->type == SYM_ENUM) type = type->ctype.base_type; *base = type; if (type->type == SYM_BASETYPE) { if (type->ctype.base_type == &int_type) return TYPE_NUM; if (type->ctype.base_type == &fp_type) return TYPE_NUM | TYPE_FLOAT; } return type_class[type->type]; } #define is_int(class) ((class & (TYPE_NUM | TYPE_FLOAT)) == TYPE_NUM) static inline int is_string_type(struct symbol *type) { if (type->type == SYM_NODE) type = type->ctype.base_type; return type->type == SYM_ARRAY && is_byte_type(type->ctype.base_type); } static struct symbol *bad_expr_type(struct expression *expr) { switch (expr->type) { case EXPR_BINOP: case EXPR_COMPARE: if (!valid_subexpr_type(expr)) break; sparse_error(expr->pos, "incompatible types for operation (%s)", show_special(expr->op)); info(expr->pos, " left side has type %s", show_typename(expr->left->ctype)); info(expr->pos, " right side has type %s", show_typename(expr->right->ctype)); break; case EXPR_PREOP: case EXPR_POSTOP: if (!valid_expr_type(expr->unop)) break; sparse_error(expr->pos, "incompatible types for operation (%s)", show_special(expr->op)); info(expr->pos, " argument has type %s", show_typename(expr->unop->ctype)); break; default: break; } expr->flags = CEF_NONE; return expr->ctype = &bad_ctype; } static int restricted_value(struct expression *v, struct symbol *type) { if (v->type != EXPR_VALUE) return 1; if (v->value != 0) return 1; return 0; } static int restricted_binop(int op, struct symbol *type) { switch (op) { case '&': case '=': case SPECIAL_AND_ASSIGN: case SPECIAL_OR_ASSIGN: case SPECIAL_XOR_ASSIGN: return 1; /* unfoul */ case '|': case '^': case '?': return 2; /* keep fouled */ case SPECIAL_EQUAL: case SPECIAL_NOTEQUAL: return 3; /* warn if fouled */ default: return 0; /* warn */ } } static int restricted_unop(int op, struct symbol **type) { if (op == '~') { if ((*type)->bit_size < bits_in_int) *type = befoul(*type); return 0; } if (op == '+') return 0; return 1; } /* type should be SYM_FOULED */ static inline struct symbol *unfoul(struct symbol *type) { return type->ctype.base_type; } static struct symbol *restricted_binop_type(int op, struct expression *left, struct expression *right, int lclass, int rclass, struct symbol *ltype, struct symbol *rtype) { struct symbol *ctype = NULL; if (lclass & TYPE_RESTRICT) { if (rclass & TYPE_RESTRICT) { if (ltype == rtype) { ctype = ltype; } else if (lclass & TYPE_FOULED) { if (unfoul(ltype) == rtype) ctype = ltype; } else if (rclass & TYPE_FOULED) { if (unfoul(rtype) == ltype) ctype = rtype; } } else { if (!restricted_value(right, ltype)) ctype = ltype; } } else if (!restricted_value(left, rtype)) ctype = rtype; if (ctype) { switch (restricted_binop(op, ctype)) { case 1: if ((lclass ^ rclass) & TYPE_FOULED) ctype = unfoul(ctype); break; case 3: if (!(lclass & rclass & TYPE_FOULED)) break; case 0: ctype = NULL; default: break; } } return ctype; } static inline void unrestrict(struct expression *expr, int class, struct symbol **ctype) { if (class & TYPE_RESTRICT) { if (class & TYPE_FOULED) *ctype = unfoul(*ctype); warning(expr->pos, "%s degrades to integer", show_typename(*ctype)); *ctype = (*ctype)->ctype.base_type; /* get to arithmetic type */ } } static struct symbol *usual_conversions(int op, struct expression *left, struct expression *right, int lclass, int rclass, struct symbol *ltype, struct symbol *rtype) { struct symbol *ctype; warn_for_different_enum_types(right->pos, left->ctype, right->ctype); if ((lclass | rclass) & TYPE_RESTRICT) goto Restr; Normal: if (!(lclass & TYPE_FLOAT)) { if (!(rclass & TYPE_FLOAT)) return bigger_int_type(ltype, rtype); else return rtype; } else if (rclass & TYPE_FLOAT) { unsigned long lmod = ltype->ctype.modifiers; unsigned long rmod = rtype->ctype.modifiers; if (rmod & ~lmod & (MOD_LONG_ALL)) return rtype; else return ltype; } else return ltype; Restr: ctype = restricted_binop_type(op, left, right, lclass, rclass, ltype, rtype); if (ctype) return ctype; unrestrict(left, lclass, <ype); unrestrict(right, rclass, &rtype); goto Normal; } static inline int lvalue_expression(struct expression *expr) { return expr->type == EXPR_PREOP && expr->op == '*'; } static struct symbol *evaluate_ptr_add(struct expression *expr, struct symbol *itype) { struct expression *index = expr->right; struct symbol *ctype, *base; int multiply; classify_type(degenerate(expr->left), &ctype); base = examine_pointer_target(ctype); /* * An address constant +/- an integer constant expression * yields an address constant again [6.6(7)]. */ if ((expr->left->flags & CEF_ADDR) && (expr->right->flags & CEF_ICE)) expr->flags = CEF_ADDR; if (!base) { expression_error(expr, "missing type information"); return NULL; } if (is_function(base)) { expression_error(expr, "arithmetics on pointers to functions"); return NULL; } /* Get the size of whatever the pointer points to */ multiply = is_void_type(base) ? 1 : bits_to_bytes(base->bit_size); if (ctype == &null_ctype) ctype = &ptr_ctype; expr->ctype = ctype; if (multiply == 1 && itype->bit_size >= bits_in_pointer) return ctype; if (index->type == EXPR_VALUE) { struct expression *val = alloc_expression(expr->pos, EXPR_VALUE); unsigned long long v = index->value, mask; mask = 1ULL << (itype->bit_size - 1); if (v & mask) v |= -mask; else v &= mask - 1; v *= multiply; mask = 1ULL << (bits_in_pointer - 1); v &= mask | (mask - 1); val->value = v; val->ctype = ssize_t_ctype; expr->right = val; return ctype; } if (itype->bit_size < bits_in_pointer) index = cast_to(index, ssize_t_ctype); if (multiply > 1) { struct expression *val = alloc_expression(expr->pos, EXPR_VALUE); struct expression *mul = alloc_expression(expr->pos, EXPR_BINOP); val->ctype = ssize_t_ctype; val->value = multiply; mul->op = '*'; mul->ctype = ssize_t_ctype; mul->left = index; mul->right = val; index = mul; } expr->right = index; return ctype; } static void examine_fn_arguments(struct symbol *fn); #define MOD_IGN (MOD_QUALIFIER | MOD_PURE) const char *type_difference(struct ctype *c1, struct ctype *c2, unsigned long mod1, unsigned long mod2) { struct ident *as1 = c1->as, *as2 = c2->as; struct symbol *t1 = c1->base_type; struct symbol *t2 = c2->base_type; int move1 = 1, move2 = 1; mod1 |= c1->modifiers; mod2 |= c2->modifiers; for (;;) { unsigned long diff; int type; struct symbol *base1 = t1->ctype.base_type; struct symbol *base2 = t2->ctype.base_type; /* * FIXME! Collect alignment and context too here! */ if (move1) { if (t1 && t1->type != SYM_PTR) { mod1 |= t1->ctype.modifiers; combine_address_space(t1->pos, &as1, t1->ctype.as); } move1 = 0; } if (move2) { if (t2 && t2->type != SYM_PTR) { mod2 |= t2->ctype.modifiers; combine_address_space(t2->pos, &as2, t2->ctype.as); } move2 = 0; } if (t1 == t2) break; if (!t1 || !t2) return "different types"; if (t1->type == SYM_NODE || t1->type == SYM_ENUM) { t1 = base1; move1 = 1; if (!t1) return "bad types"; continue; } if (t2->type == SYM_NODE || t2->type == SYM_ENUM) { t2 = base2; move2 = 1; if (!t2) return "bad types"; continue; } move1 = move2 = 1; type = t1->type; if (type != t2->type) return "different base types"; switch (type) { default: sparse_error(t1->pos, "internal error: bad type in derived(%d)", type); return "bad types"; case SYM_RESTRICT: return "different base types"; case SYM_UNION: case SYM_STRUCT: /* allow definition of incomplete structs and unions */ if (t1->ident == t2->ident) return NULL; return "different base types"; case SYM_ARRAY: /* XXX: we ought to compare sizes */ break; case SYM_PTR: if (as1 != as2) return "different address spaces"; /* MOD_SPECIFIER is due to idiocy in parse.c */ if ((mod1 ^ mod2) & ~MOD_IGNORE & ~MOD_SPECIFIER) return "different modifiers"; /* we could be lazier here */ base1 = examine_pointer_target(t1); base2 = examine_pointer_target(t2); mod1 = t1->ctype.modifiers; as1 = t1->ctype.as; mod2 = t2->ctype.modifiers; as2 = t2->ctype.as; break; case SYM_FN: { struct symbol *arg1, *arg2; int i; if (as1 != as2) return "different address spaces"; if ((mod1 ^ mod2) & ~MOD_IGNORE & ~MOD_SIGNEDNESS) return "different modifiers"; mod1 = t1->ctype.modifiers; as1 = t1->ctype.as; mod2 = t2->ctype.modifiers; as2 = t2->ctype.as; if (t1->variadic != t2->variadic) return "incompatible variadic arguments"; examine_fn_arguments(t1); examine_fn_arguments(t2); PREPARE_PTR_LIST(t1->arguments, arg1); PREPARE_PTR_LIST(t2->arguments, arg2); i = 1; for (;;) { const char *diffstr; if (!arg1 && !arg2) break; if (!arg1 || !arg2) return "different argument counts"; diffstr = type_difference(&arg1->ctype, &arg2->ctype, MOD_IGN, MOD_IGN); if (diffstr) { static char argdiff[80]; sprintf(argdiff, "incompatible argument %d (%s)", i, diffstr); return argdiff; } NEXT_PTR_LIST(arg1); NEXT_PTR_LIST(arg2); i++; } FINISH_PTR_LIST(arg2); FINISH_PTR_LIST(arg1); break; } case SYM_BASETYPE: if (as1 != as2) return "different address spaces"; if (base1 != base2) return "different base types"; diff = (mod1 ^ mod2) & ~MOD_IGNORE; if (!diff) return NULL; if (diff & MOD_SIZE) return "different type sizes"; else if (diff & ~MOD_SIGNEDNESS) return "different modifiers"; else return "different signedness"; } t1 = base1; t2 = base2; } if (as1 != as2) return "different address spaces"; if ((mod1 ^ mod2) & ~MOD_IGNORE & ~MOD_SIGNEDNESS) return "different modifiers"; return NULL; } static void bad_null(struct expression *expr) { if (Wnon_pointer_null) warning(expr->pos, "Using plain integer as NULL pointer"); } static unsigned long target_qualifiers(struct symbol *type) { unsigned long mod = type->ctype.modifiers & MOD_IGN; if (type->ctype.base_type && type->ctype.base_type->type == SYM_ARRAY) mod = 0; return mod; } static struct symbol *evaluate_ptr_sub(struct expression *expr) { const char *typediff; struct symbol *ltype, *rtype; struct expression *l = expr->left; struct expression *r = expr->right; struct symbol *lbase; classify_type(degenerate(l), <ype); classify_type(degenerate(r), &rtype); lbase = examine_pointer_target(ltype); examine_pointer_target(rtype); typediff = type_difference(<ype->ctype, &rtype->ctype, target_qualifiers(rtype), target_qualifiers(ltype)); if (typediff) expression_error(expr, "subtraction of different types can't work (%s)", typediff); if (is_function(lbase)) { expression_error(expr, "subtraction of functions? Share your drugs"); return NULL; } expr->ctype = ssize_t_ctype; if (lbase->bit_size > bits_in_char) { struct expression *sub = alloc_expression(expr->pos, EXPR_BINOP); struct expression *div = expr; struct expression *val = alloc_expression(expr->pos, EXPR_VALUE); unsigned long value = bits_to_bytes(lbase->bit_size); val->ctype = size_t_ctype; val->value = value; if (value & (value-1)) { if (Wptr_subtraction_blows) { warning(expr->pos, "potentially expensive pointer subtraction"); info(expr->pos, " '%s' has a non-power-of-2 size: %lu", show_typename(lbase), value); } } sub->op = '-'; sub->ctype = ssize_t_ctype; sub->left = l; sub->right = r; div->op = '/'; div->left = sub; div->right = val; } return ssize_t_ctype; } #define is_safe_type(type) ((type)->ctype.modifiers & MOD_SAFE) static struct symbol *evaluate_conditional(struct expression *expr, int iterator) { struct symbol *ctype; if (!expr) return NULL; if (!iterator && expr->type == EXPR_ASSIGNMENT && expr->op == '=') warning(expr->pos, "assignment expression in conditional"); ctype = evaluate_expression(expr); if (!valid_type(ctype)) return NULL; if (is_safe_type(ctype)) warning(expr->pos, "testing a 'safe expression'"); if (is_func_type(ctype)) { if (Waddress) warning(expr->pos, "the address of %s will always evaluate as true", "a function"); } else if (is_array_type(ctype)) { if (Waddress) warning(expr->pos, "the address of %s will always evaluate as true", "an array"); } else if (!is_scalar_type(ctype)) { sparse_error(expr->pos, "incorrect type in conditional (non-scalar type)"); info(expr->pos, " got %s", show_typename(ctype)); return NULL; } ctype = degenerate(expr); return ctype; } static struct symbol *evaluate_logical(struct expression *expr) { if (!evaluate_conditional(expr->left, 0)) return NULL; if (!evaluate_conditional(expr->right, 0)) return NULL; /* the result is int [6.5.13(3), 6.5.14(3)] */ expr->ctype = &int_ctype; expr->flags = expr->left->flags & expr->right->flags; expr->flags &= ~(CEF_CONST_MASK | CEF_ADDR); return &int_ctype; } static struct symbol *evaluate_binop(struct expression *expr) { struct symbol *ltype, *rtype, *ctype; int lclass = classify_type(expr->left->ctype, <ype); int rclass = classify_type(expr->right->ctype, &rtype); int op = expr->op; /* number op number */ if (lclass & rclass & TYPE_NUM) { expr->flags = expr->left->flags & expr->right->flags; expr->flags &= ~CEF_CONST_MASK; if ((lclass | rclass) & TYPE_FLOAT) { switch (op) { case '+': case '-': case '*': case '/': break; default: return bad_expr_type(expr); } } if (op == SPECIAL_LEFTSHIFT || op == SPECIAL_RIGHTSHIFT) { // shifts do integer promotions, but that's it. unrestrict(expr->left, lclass, <ype); unrestrict(expr->right, rclass, &rtype); ctype = ltype = integer_promotion(ltype); rtype = integer_promotion(rtype); } else { // The rest do usual conversions const unsigned left_not = expr->left->type == EXPR_PREOP && expr->left->op == '!'; const unsigned right_not = expr->right->type == EXPR_PREOP && expr->right->op == '!'; if ((op == '&' || op == '|') && (left_not || right_not)) warning(expr->pos, "dubious: %sx %c %sy", left_not ? "!" : "", op, right_not ? "!" : ""); ltype = usual_conversions(op, expr->left, expr->right, lclass, rclass, ltype, rtype); ctype = rtype = ltype; } expr->left = cast_to(expr->left, ltype); expr->right = cast_to(expr->right, rtype); expr->ctype = ctype; return ctype; } /* pointer (+|-) integer */ if (lclass & TYPE_PTR && is_int(rclass) && (op == '+' || op == '-')) { unrestrict(expr->right, rclass, &rtype); return evaluate_ptr_add(expr, rtype); } /* integer + pointer */ if (rclass & TYPE_PTR && is_int(lclass) && op == '+') { struct expression *index = expr->left; unrestrict(index, lclass, <ype); expr->left = expr->right; expr->right = index; return evaluate_ptr_add(expr, ltype); } /* pointer - pointer */ if (lclass & rclass & TYPE_PTR && expr->op == '-') return evaluate_ptr_sub(expr); return bad_expr_type(expr); } static struct symbol *evaluate_comma(struct expression *expr) { expr->ctype = degenerate(expr->right); if (expr->ctype == &null_ctype) expr->ctype = &ptr_ctype; expr->flags &= expr->left->flags & expr->right->flags; return expr->ctype; } static int modify_for_unsigned(int op) { if (op == '<') op = SPECIAL_UNSIGNED_LT; else if (op == '>') op = SPECIAL_UNSIGNED_GT; else if (op == SPECIAL_LTE) op = SPECIAL_UNSIGNED_LTE; else if (op == SPECIAL_GTE) op = SPECIAL_UNSIGNED_GTE; return op; } enum null_constant_type { NON_NULL, NULL_PTR, NULL_ZERO, }; static inline int is_null_pointer_constant(struct expression *e) { if (e->ctype == &null_ctype) return NULL_PTR; if (!(e->flags & CEF_ICE)) return NON_NULL; return is_zero_constant(e) ? NULL_ZERO : NON_NULL; } static struct symbol *evaluate_compare(struct expression *expr) { struct expression *left = expr->left, *right = expr->right; struct symbol *ltype, *rtype, *lbase, *rbase; int lclass = classify_type(degenerate(left), <ype); int rclass = classify_type(degenerate(right), &rtype); struct symbol *ctype; const char *typediff; /* Type types? */ if (is_type_type(ltype) && is_type_type(rtype)) { /* * __builtin_types_compatible_p() yields an integer * constant expression */ expr->flags = CEF_SET_ICE; goto OK; } if (is_safe_type(left->ctype) || is_safe_type(right->ctype)) warning(expr->pos, "testing a 'safe expression'"); expr->flags = left->flags & right->flags & ~CEF_CONST_MASK & ~CEF_ADDR; /* number on number */ if (lclass & rclass & TYPE_NUM) { ctype = usual_conversions(expr->op, expr->left, expr->right, lclass, rclass, ltype, rtype); expr->left = cast_to(expr->left, ctype); expr->right = cast_to(expr->right, ctype); if (ctype->ctype.modifiers & MOD_UNSIGNED) expr->op = modify_for_unsigned(expr->op); goto OK; } /* at least one must be a pointer */ if (!((lclass | rclass) & TYPE_PTR)) return bad_expr_type(expr); /* equality comparisons can be with null pointer constants */ if (expr->op == SPECIAL_EQUAL || expr->op == SPECIAL_NOTEQUAL) { int is_null1 = is_null_pointer_constant(left); int is_null2 = is_null_pointer_constant(right); if (is_null1 == NULL_ZERO) bad_null(left); if (is_null2 == NULL_ZERO) bad_null(right); if (is_null1 && is_null2) { int positive = expr->op == SPECIAL_EQUAL; expr->type = EXPR_VALUE; expr->value = positive; goto OK; } if (is_null1 && (rclass & TYPE_PTR)) { left = cast_to(left, rtype); goto OK; } if (is_null2 && (lclass & TYPE_PTR)) { right = cast_to(right, ltype); goto OK; } } /* both should be pointers */ if (!(lclass & rclass & TYPE_PTR)) return bad_expr_type(expr); expr->op = modify_for_unsigned(expr->op); lbase = examine_pointer_target(ltype); rbase = examine_pointer_target(rtype); /* they also have special treatment for pointers to void */ if (expr->op == SPECIAL_EQUAL || expr->op == SPECIAL_NOTEQUAL) { if (ltype->ctype.as == rtype->ctype.as) { if (lbase == &void_ctype) { right = cast_to(right, ltype); goto OK; } if (rbase == &void_ctype) { left = cast_to(left, rtype); goto OK; } } } typediff = type_difference(<ype->ctype, &rtype->ctype, target_qualifiers(rtype), target_qualifiers(ltype)); if (!typediff) goto OK; expression_error(expr, "incompatible types in comparison expression (%s):", typediff); info(expr->pos, " %s", show_typename(ltype)); info(expr->pos, " %s", show_typename(rtype)); return NULL; OK: /* the result is int [6.5.8(6), 6.5.9(3)]*/ expr->ctype = &int_ctype; return &int_ctype; } /* * NOTE! The degenerate case of "x ? : y", where we don't * have a true case, this will possibly promote "x" to the * same type as "y", and thus _change_ the conditional * test in the expression. But since promotion is "safe" * for testing, that's OK. */ static struct symbol *evaluate_conditional_expression(struct expression *expr) { struct expression **cond; struct symbol *ctype, *ltype, *rtype, *lbase, *rbase; int lclass, rclass; const char * typediff; int qual; if (!evaluate_conditional(expr->conditional, 0)) return NULL; if (!evaluate_expression(expr->cond_false)) return NULL; ctype = degenerate(expr->conditional); rtype = degenerate(expr->cond_false); cond = &expr->conditional; ltype = ctype; if (expr->cond_true) { if (!evaluate_expression(expr->cond_true)) return NULL; ltype = degenerate(expr->cond_true); cond = &expr->cond_true; } expr->flags = (expr->conditional->flags & (*cond)->flags & expr->cond_false->flags & ~CEF_CONST_MASK); /* * A conditional operator yields a particular constant * expression type only if all of its three subexpressions are * of that type [6.6(6), 6.6(8)]. * As an extension, relax this restriction by allowing any * constant expression type for the condition expression. * * A conditional operator never yields an address constant * [6.6(9)]. * However, as an extension, if the condition is any constant * expression, and the true and false expressions are both * address constants, mark the result as an address constant. */ if (expr->conditional->flags & (CEF_ACE | CEF_ADDR)) expr->flags = (*cond)->flags & expr->cond_false->flags & ~CEF_CONST_MASK; lclass = classify_type(ltype, <ype); rclass = classify_type(rtype, &rtype); if (lclass & rclass & TYPE_NUM) { ctype = usual_conversions('?', *cond, expr->cond_false, lclass, rclass, ltype, rtype); *cond = cast_to(*cond, ctype); expr->cond_false = cast_to(expr->cond_false, ctype); goto out; } if ((lclass | rclass) & TYPE_PTR) { int is_null1 = is_null_pointer_constant(*cond); int is_null2 = is_null_pointer_constant(expr->cond_false); if (is_null1 && is_null2) { *cond = cast_to(*cond, &ptr_ctype); expr->cond_false = cast_to(expr->cond_false, &ptr_ctype); ctype = &ptr_ctype; goto out; } if (is_null1 && (rclass & TYPE_PTR)) { if (is_null1 == NULL_ZERO) bad_null(*cond); *cond = cast_to(*cond, rtype); ctype = rtype; goto out; } if (is_null2 && (lclass & TYPE_PTR)) { if (is_null2 == NULL_ZERO) bad_null(expr->cond_false); expr->cond_false = cast_to(expr->cond_false, ltype); ctype = ltype; goto out; } if (!(lclass & rclass & TYPE_PTR)) { typediff = "different types"; goto Err; } /* OK, it's pointer on pointer */ if (ltype->ctype.as != rtype->ctype.as) { typediff = "different address spaces"; goto Err; } /* need to be lazier here */ lbase = examine_pointer_target(ltype); rbase = examine_pointer_target(rtype); qual = target_qualifiers(ltype) | target_qualifiers(rtype); if (lbase == &void_ctype) { /* XXX: pointers to function should warn here */ ctype = ltype; goto Qual; } if (rbase == &void_ctype) { /* XXX: pointers to function should warn here */ ctype = rtype; goto Qual; } /* XXX: that should be pointer to composite */ ctype = ltype; typediff = type_difference(<ype->ctype, &rtype->ctype, qual, qual); if (!typediff) goto Qual; goto Err; } /* void on void, struct on same struct, union on same union */ if (ltype == rtype) { ctype = ltype; goto out; } typediff = "different base types"; Err: expression_error(expr, "incompatible types in conditional expression (%s):", typediff); info(expr->pos, " %s", show_typename(ltype)); info(expr->pos, " %s", show_typename(rtype)); /* * if the condition is constant, the type is in fact known * so use it, as gcc & clang do. */ switch (expr_truth_value(expr->conditional)) { case 1: expr->ctype = ltype; break; case 0: expr->ctype = rtype; break; default: break; } return NULL; out: expr->ctype = ctype; return ctype; Qual: if (qual & ~ctype->ctype.modifiers) { struct symbol *sym = alloc_symbol(ctype->pos, SYM_PTR); *sym = *ctype; sym->ctype.modifiers |= qual; ctype = sym; } *cond = cast_to(*cond, ctype); expr->cond_false = cast_to(expr->cond_false, ctype); goto out; } /* FP assignments can not do modulo or bit operations */ static int compatible_float_op(int op) { return op == SPECIAL_ADD_ASSIGN || op == SPECIAL_SUB_ASSIGN || op == SPECIAL_MUL_ASSIGN || op == SPECIAL_DIV_ASSIGN; } static int evaluate_assign_op(struct expression *expr) { struct symbol *target = expr->left->ctype; struct symbol *source = expr->right->ctype; struct symbol *t, *s; int tclass = classify_type(target, &t); int sclass = classify_type(source, &s); int op = expr->op; if (tclass & sclass & TYPE_NUM) { if (tclass & TYPE_FLOAT && !compatible_float_op(op)) { expression_error(expr, "invalid assignment"); return 0; } if (tclass & TYPE_RESTRICT) { if (!restricted_binop(op, t)) { warning(expr->pos, "bad assignment (%s) to %s", show_special(op), show_typename(t)); expr->right = cast_to(expr->right, target); return 0; } /* allowed assignments unfoul */ if (sclass & TYPE_FOULED && unfoul(s) == t) goto Cast; if (!restricted_value(expr->right, t)) return 1; } else if (op == SPECIAL_SHR_ASSIGN || op == SPECIAL_SHL_ASSIGN) { // shifts do integer promotions, but that's it. unrestrict(expr->right, sclass, &s); target = integer_promotion(s); goto Cast; } else if (!(sclass & TYPE_RESTRICT)) goto usual; /* source and target would better be identical restricted */ if (t == s) return 1; warning(expr->pos, "invalid assignment: %s", show_special(op)); info(expr->pos, " left side has type %s", show_typename(t)); info(expr->pos, " right side has type %s", show_typename(s)); expr->right = cast_to(expr->right, target); return 0; } if (tclass == TYPE_PTR && is_int(sclass)) { if (op == SPECIAL_ADD_ASSIGN || op == SPECIAL_SUB_ASSIGN) { unrestrict(expr->right, sclass, &s); evaluate_ptr_add(expr, s); return 1; } expression_error(expr, "invalid pointer assignment"); return 0; } expression_error(expr, "invalid assignment"); return 0; usual: target = usual_conversions(op, expr->left, expr->right, tclass, sclass, target, source); Cast: expr->right = cast_to(expr->right, target); return 1; } static int whitelist_pointers(struct symbol *t1, struct symbol *t2) { if (t1 == t2) return 0; /* yes, 0 - we don't want a cast_to here */ if (t1 == &void_ctype) return 1; if (t2 == &void_ctype) return 1; if (classify_type(t1, &t1) != TYPE_NUM) return 0; if (classify_type(t2, &t2) != TYPE_NUM) return 0; if (t1 == t2) return 1; if (t1->ctype.modifiers & t2->ctype.modifiers & MOD_CHAR) return 1; if ((t1->ctype.modifiers ^ t2->ctype.modifiers) & MOD_SIZE) return 0; return !Wtypesign; } static int check_assignment_types(struct symbol *target, struct expression **rp, const char **typediff) { struct symbol *source = degenerate(*rp); struct symbol *t, *s; int tclass = classify_type(target, &t); int sclass = classify_type(source, &s); if (tclass & sclass & TYPE_NUM) { if (tclass & TYPE_RESTRICT) { /* allowed assignments unfoul */ if (sclass & TYPE_FOULED && unfoul(s) == t) goto Cast; if (!restricted_value(*rp, target)) return 1; if (s == t) return 1; } else if (!(sclass & TYPE_RESTRICT)) goto Cast; if (t == &bool_ctype) { if (is_fouled_type(s)) warning((*rp)->pos, "%s degrades to integer", show_typename(s->ctype.base_type)); goto Cast; } *typediff = "different base types"; return 0; } if (tclass == TYPE_PTR) { unsigned long mod1, mod2; struct symbol *b1, *b2; // NULL pointer is always OK int is_null = is_null_pointer_constant(*rp); if (is_null) { if (is_null == NULL_ZERO) bad_null(*rp); goto Cast; } if (!(sclass & TYPE_PTR)) { *typediff = "different base types"; return 0; } b1 = examine_pointer_target(t); b2 = examine_pointer_target(s); mod1 = target_qualifiers(t); mod2 = target_qualifiers(s); if (whitelist_pointers(b1, b2)) { /* * assignments to/from void * are OK, provided that * we do not remove qualifiers from pointed to [C] * or mix address spaces [sparse]. */ if (t->ctype.as != s->ctype.as) { *typediff = "different address spaces"; return 0; } /* * If this is a function pointer assignment, it is * actually fine to assign a pointer to const data to * it, as a function pointer points to const data * implicitly, i.e., dereferencing it does not produce * an lvalue. */ if (b1->type == SYM_FN) mod1 |= MOD_CONST; if (mod2 & ~mod1) { *typediff = "different modifiers"; return 0; } goto Cast; } /* It's OK if the target is more volatile or const than the source */ *typediff = type_difference(&t->ctype, &s->ctype, 0, mod1); if (*typediff) return 0; return 1; } if ((tclass & TYPE_COMPOUND) && s == t) return 1; if (tclass & TYPE_NUM) { /* XXX: need to turn into comparison with NULL */ if (t == &bool_ctype && (sclass & TYPE_PTR)) goto Cast; *typediff = "different base types"; return 0; } *typediff = "invalid types"; return 0; Cast: *rp = cast_to(*rp, target); return 1; } static int compatible_assignment_types(struct expression *expr, struct symbol *target, struct expression **rp, const char *where) { const char *typediff; struct symbol *source = degenerate(*rp); if (!check_assignment_types(target, rp, &typediff)) { warning(expr->pos, "incorrect type in %s (%s)", where, typediff); info(expr->pos, " expected %s", show_typename(target)); info(expr->pos, " got %s", show_typename(source)); *rp = cast_to(*rp, target); return 0; } return 1; } static int compatible_transparent_union(struct symbol *target, struct expression **rp) { struct symbol *t, *member; classify_type(target, &t); if (t->type != SYM_UNION || !t->transparent_union) return 0; FOR_EACH_PTR(t->symbol_list, member) { const char *typediff; if (check_assignment_types(member, rp, &typediff)) return 1; } END_FOR_EACH_PTR(member); return 0; } static int compatible_argument_type(struct expression *expr, struct symbol *target, struct expression **rp, const char *where) { if (compatible_transparent_union(target, rp)) return 1; return compatible_assignment_types(expr, target, rp, where); } static void mark_assigned(struct expression *expr) { struct symbol *sym; if (!expr) return; switch (expr->type) { case EXPR_SYMBOL: sym = expr->symbol; if (!sym) return; if (sym->type != SYM_NODE) return; sym->ctype.modifiers |= MOD_ASSIGNED; return; case EXPR_BINOP: mark_assigned(expr->left); mark_assigned(expr->right); return; case EXPR_CAST: case EXPR_FORCE_CAST: mark_assigned(expr->cast_expression); return; case EXPR_SLICE: mark_assigned(expr->base); return; default: /* Hmm? */ return; } } static void evaluate_assign_to(struct expression *left, struct symbol *type) { if (type->ctype.modifiers & MOD_CONST) expression_error(left, "assignment to const expression"); /* We know left is an lvalue, so it's a "preop-*" */ mark_assigned(left->unop); } static struct symbol *evaluate_assignment(struct expression *expr) { struct expression *left = expr->left; struct symbol *ltype; if (!lvalue_expression(left)) { expression_error(expr, "not an lvalue"); return NULL; } ltype = left->ctype; if (expr->op != '=') { if (!evaluate_assign_op(expr)) return NULL; } else { if (!compatible_assignment_types(expr, ltype, &expr->right, "assignment")) return NULL; } evaluate_assign_to(left, ltype); expr->ctype = ltype; return ltype; } static void examine_fn_arguments(struct symbol *fn) { struct symbol *s; FOR_EACH_PTR(fn->arguments, s) { struct symbol *arg = evaluate_symbol(s); /* Array/function arguments silently degenerate into pointers */ if (arg) { struct symbol *ptr; switch(arg->type) { case SYM_ARRAY: case SYM_FN: ptr = alloc_symbol(s->pos, SYM_PTR); if (arg->type == SYM_ARRAY) ptr->ctype = arg->ctype; else ptr->ctype.base_type = arg; combine_address_space(s->pos, &ptr->ctype.as, s->ctype.as); ptr->ctype.modifiers |= s->ctype.modifiers & MOD_PTRINHERIT; s->ctype.base_type = ptr; s->ctype.as = NULL; s->ctype.modifiers &= ~MOD_PTRINHERIT; s->bit_size = 0; s->examined = 0; examine_symbol_type(s); break; default: /* nothing */ break; } } } END_FOR_EACH_PTR(s); } static struct symbol *convert_to_as_mod(struct symbol *sym, struct ident *as, int mod) { /* Take the modifiers of the pointer, and apply them to the member */ mod |= sym->ctype.modifiers; if (sym->ctype.as != as || sym->ctype.modifiers != mod) { struct symbol *newsym = alloc_symbol(sym->pos, SYM_NODE); *newsym = *sym; newsym->ctype.as = as; newsym->ctype.modifiers = mod; sym = newsym; } return sym; } static struct symbol *create_pointer(struct expression *expr, struct symbol *sym, int degenerate) { struct symbol *node = alloc_symbol(expr->pos, SYM_NODE); struct symbol *ptr = alloc_symbol(expr->pos, SYM_PTR); node->ctype.base_type = ptr; ptr->bit_size = bits_in_pointer; ptr->ctype.alignment = pointer_alignment; node->bit_size = bits_in_pointer; node->ctype.alignment = pointer_alignment; access_symbol(sym); if (sym->ctype.modifiers & MOD_REGISTER) { warning(expr->pos, "taking address of 'register' variable '%s'", show_ident(sym->ident)); sym->ctype.modifiers &= ~MOD_REGISTER; } if (sym->type == SYM_NODE) { combine_address_space(sym->pos, &ptr->ctype.as, sym->ctype.as); ptr->ctype.modifiers |= sym->ctype.modifiers & MOD_PTRINHERIT; sym = sym->ctype.base_type; } if (degenerate && sym->type == SYM_ARRAY) { combine_address_space(sym->pos, &ptr->ctype.as, sym->ctype.as); ptr->ctype.modifiers |= sym->ctype.modifiers & MOD_PTRINHERIT; sym = sym->ctype.base_type; } ptr->ctype.base_type = sym; return node; } /* Arrays degenerate into pointers on pointer arithmetic */ static struct symbol *degenerate(struct expression *expr) { struct symbol *ctype, *base; if (!expr) return NULL; ctype = expr->ctype; if (!ctype) return NULL; base = examine_symbol_type(ctype); if (ctype->type == SYM_NODE) base = ctype->ctype.base_type; /* * Arrays degenerate into pointers to the entries, while * functions degenerate into pointers to themselves. * If array was part of non-lvalue compound, we create a copy * of that compound first and then act as if we were dealing with * the corresponding field in there. */ switch (base->type) { case SYM_ARRAY: if (expr->type == EXPR_SLICE) { struct symbol *a = alloc_symbol(expr->pos, SYM_NODE); struct expression *e0, *e1, *e2, *e3, *e4; a->ctype.base_type = expr->base->ctype; a->bit_size = expr->base->ctype->bit_size; a->array_size = expr->base->ctype->array_size; e0 = alloc_expression(expr->pos, EXPR_SYMBOL); e0->symbol = a; e0->ctype = &lazy_ptr_ctype; e1 = alloc_expression(expr->pos, EXPR_PREOP); e1->unop = e0; e1->op = '*'; e1->ctype = expr->base->ctype; /* XXX */ e2 = alloc_expression(expr->pos, EXPR_ASSIGNMENT); e2->left = e1; e2->right = expr->base; e2->op = '='; e2->ctype = expr->base->ctype; if (expr->r_bitpos) { e3 = alloc_expression(expr->pos, EXPR_BINOP); e3->op = '+'; e3->left = e0; e3->right = alloc_const_expression(expr->pos, bits_to_bytes(expr->r_bitpos)); e3->ctype = &lazy_ptr_ctype; } else { e3 = e0; } e4 = alloc_expression(expr->pos, EXPR_COMMA); e4->left = e2; e4->right = e3; e4->ctype = &lazy_ptr_ctype; expr->unop = e4; expr->type = EXPR_PREOP; expr->op = '*'; } case SYM_FN: if (expr->op != '*' || expr->type != EXPR_PREOP) { expression_error(expr, "strange non-value function or array"); return &bad_ctype; } *expr = *expr->unop; ctype = create_pointer(expr, ctype, 1); expr->ctype = ctype; default: /* nothing */; } return ctype; } static struct symbol *evaluate_addressof(struct expression *expr) { struct expression *op = expr->unop; struct symbol *ctype; if (op->op != '*' || op->type != EXPR_PREOP) { expression_error(expr, "not addressable"); return NULL; } ctype = op->ctype; *expr = *op->unop; if (expr->type == EXPR_SYMBOL) { struct symbol *sym = expr->symbol; sym->ctype.modifiers |= MOD_ADDRESSABLE; } /* * symbol expression evaluation is lazy about the type * of the sub-expression, so we may have to generate * the type here if so.. */ if (expr->ctype == &lazy_ptr_ctype) { ctype = create_pointer(expr, ctype, 0); expr->ctype = ctype; } return expr->ctype; } static struct symbol *evaluate_dereference(struct expression *expr) { struct expression *op = expr->unop; struct symbol *ctype = op->ctype, *node, *target; /* Simplify: *&(expr) => (expr) */ if (op->type == EXPR_PREOP && op->op == '&') { *expr = *op->unop; expr->flags = CEF_NONE; return expr->ctype; } examine_symbol_type(ctype); /* Dereferencing a node drops all the node information. */ if (ctype->type == SYM_NODE) ctype = ctype->ctype.base_type; target = ctype->ctype.base_type; examine_symbol_type(target); switch (ctype->type) { default: expression_error(expr, "cannot dereference this type"); return NULL; case SYM_FN: *expr = *op; return expr->ctype; case SYM_PTR: node = alloc_symbol(expr->pos, SYM_NODE); node->ctype.modifiers = target->ctype.modifiers & MOD_SPECIFIER; merge_type(node, ctype); break; case SYM_ARRAY: if (!lvalue_expression(op)) { expression_error(op, "non-lvalue array??"); return NULL; } /* Do the implied "addressof" on the array */ *op = *op->unop; /* * When an array is dereferenced, we need to pick * up the attributes of the original node too.. */ node = alloc_symbol(expr->pos, SYM_NODE); merge_type(node, op->ctype); merge_type(node, ctype); break; } node->bit_size = target->bit_size; node->array_size = target->array_size; expr->ctype = node; return node; } /* * Unary post-ops: x++ and x-- */ static struct symbol *evaluate_postop(struct expression *expr) { struct expression *op = expr->unop; struct symbol *ctype = op->ctype; int class = classify_type(ctype, &ctype); int multiply = 0; if (!class || class & TYPE_COMPOUND) { expression_error(expr, "need scalar for ++/--"); return NULL; } if (!lvalue_expression(expr->unop)) { expression_error(expr, "need lvalue expression for ++/--"); return NULL; } if ((class & TYPE_RESTRICT) && restricted_unop(expr->op, &ctype)) unrestrict(expr, class, &ctype); if (class & TYPE_NUM) { multiply = 1; } else if (class == TYPE_PTR) { struct symbol *target = examine_pointer_target(ctype); if (!is_function(target)) multiply = bits_to_bytes(target->bit_size); } if (multiply) { evaluate_assign_to(op, op->ctype); expr->op_value = multiply; expr->ctype = ctype; return ctype; } expression_error(expr, "bad argument type for ++/--"); return NULL; } static struct symbol *evaluate_sign(struct expression *expr) { struct symbol *ctype = expr->unop->ctype; int class = classify_type(ctype, &ctype); unsigned char flags = expr->unop->flags & ~CEF_CONST_MASK; /* should be an arithmetic type */ if (!(class & TYPE_NUM)) return bad_expr_type(expr); if (class & TYPE_RESTRICT) goto Restr; Normal: if (!(class & TYPE_FLOAT)) { ctype = integer_promotion(ctype); expr->unop = cast_to(expr->unop, ctype); } else if (expr->op != '~') { /* no conversions needed */ } else { return bad_expr_type(expr); } if (expr->op == '+') *expr = *expr->unop; expr->flags = flags; expr->ctype = ctype; return ctype; Restr: if (restricted_unop(expr->op, &ctype)) unrestrict(expr, class, &ctype); goto Normal; } static struct symbol *evaluate_preop(struct expression *expr) { struct symbol *ctype = expr->unop->ctype; switch (expr->op) { case '(': *expr = *expr->unop; return ctype; case '+': case '-': case '~': return evaluate_sign(expr); case '*': return evaluate_dereference(expr); case '&': return evaluate_addressof(expr); case SPECIAL_INCREMENT: case SPECIAL_DECREMENT: /* * From a type evaluation standpoint the preops are * the same as the postops */ return evaluate_postop(expr); case '!': ctype = degenerate(expr->unop); expr->flags = expr->unop->flags & ~CEF_CONST_MASK; /* * A logical negation never yields an address constant * [6.6(9)]. */ expr->flags &= ~CEF_ADDR; if (is_safe_type(ctype)) warning(expr->pos, "testing a 'safe expression'"); if (is_float_type(ctype)) { struct expression *arg = expr->unop; expr->type = EXPR_COMPARE; expr->op = SPECIAL_EQUAL; expr->left = arg; expr->right = alloc_expression(expr->pos, EXPR_FVALUE); expr->right->ctype = ctype; expr->right->fvalue = 0; } else if (is_fouled_type(ctype)) { warning(expr->pos, "%s degrades to integer", show_typename(ctype->ctype.base_type)); } /* the result is int [6.5.3.3(5)]*/ ctype = &int_ctype; break; default: break; } expr->ctype = ctype; return ctype; } struct symbol *find_identifier(struct ident *ident, struct symbol_list *_list, int *offset) { struct ptr_list *head = (struct ptr_list *)_list; struct ptr_list *list = head; if (!head) return NULL; do { int i; for (i = 0; i < list->nr; i++) { struct symbol *sym = (struct symbol *) list->list[i]; if (sym->ident) { if (sym->ident != ident) continue; *offset = sym->offset; return sym; } else { struct symbol *ctype = sym->ctype.base_type; struct symbol *sub; if (!ctype) continue; if (ctype->type != SYM_UNION && ctype->type != SYM_STRUCT) continue; sub = find_identifier(ident, ctype->symbol_list, offset); if (!sub) continue; *offset += sym->offset; return sub; } } } while ((list = list->next) != head); return NULL; } static struct expression *evaluate_offset(struct expression *expr, unsigned long offset) { struct expression *add; /* * Create a new add-expression * * NOTE! Even if we just add zero, we need a new node * for the member pointer, since it has a different * type than the original pointer. We could make that * be just a cast, but the fact is, a node is a node, * so we might as well just do the "add zero" here. */ add = alloc_expression(expr->pos, EXPR_BINOP); add->op = '+'; add->left = expr; add->right = alloc_expression(expr->pos, EXPR_VALUE); add->right->ctype = &int_ctype; add->right->value = offset; /* * The ctype of the pointer will be lazily evaluated if * we ever take the address of this member dereference.. */ add->ctype = &lazy_ptr_ctype; /* * The resulting address of a member access through an address * constant is an address constant again [6.6(9)]. */ add->flags = expr->flags; return add; } /* structure/union dereference */ static struct symbol *evaluate_member_dereference(struct expression *expr) { int offset; struct symbol *ctype, *member; struct expression *deref = expr->deref, *add; struct ident *ident = expr->member; struct ident *address_space; unsigned int mod; if (!evaluate_expression(deref)) return NULL; if (!ident) { expression_error(expr, "bad member name"); return NULL; } ctype = deref->ctype; examine_symbol_type(ctype); address_space = ctype->ctype.as; mod = ctype->ctype.modifiers; if (ctype->type == SYM_NODE) { ctype = ctype->ctype.base_type; combine_address_space(deref->pos, &address_space, ctype->ctype.as); mod |= ctype->ctype.modifiers; } if (!ctype || (ctype->type != SYM_STRUCT && ctype->type != SYM_UNION)) { expression_error(expr, "expected structure or union"); return NULL; } offset = 0; member = find_identifier(ident, ctype->symbol_list, &offset); if (!member) { const char *type = ctype->type == SYM_STRUCT ? "struct" : "union"; const char *name = ""; int namelen = 9; if (ctype->ident) { name = ctype->ident->name; namelen = ctype->ident->len; } if (ctype->symbol_list) expression_error(expr, "no member '%s' in %s %.*s", show_ident(ident), type, namelen, name); else expression_error(expr, "using member '%s' in " "incomplete %s %.*s", show_ident(ident), type, namelen, name); return NULL; } /* * The member needs to take on the address space and modifiers of * the "parent" type. */ member = convert_to_as_mod(member, address_space, mod); ctype = get_base_type(member); if (!lvalue_expression(deref)) { if (deref->type != EXPR_SLICE) { expr->base = deref; expr->r_bitpos = 0; } else { expr->base = deref->base; expr->r_bitpos = deref->r_bitpos; } expr->r_bitpos += bytes_to_bits(offset); expr->type = EXPR_SLICE; expr->r_nrbits = member->bit_size; expr->r_bitpos += member->bit_offset; expr->ctype = member; return member; } deref = deref->unop; expr->deref = deref; add = evaluate_offset(deref, offset); expr->type = EXPR_PREOP; expr->op = '*'; expr->unop = add; expr->ctype = member; return member; } static int is_promoted(struct expression *expr) { while (1) { switch (expr->type) { case EXPR_BINOP: case EXPR_SELECT: case EXPR_CONDITIONAL: return 1; case EXPR_COMMA: expr = expr->right; continue; case EXPR_PREOP: switch (expr->op) { case '(': expr = expr->unop; continue; case '+': case '-': case '~': return 1; default: return 0; } default: return 0; } } } static struct symbol *evaluate_cast(struct expression *); static struct symbol *evaluate_type_information(struct expression *expr) { struct symbol *sym = expr->cast_type; if (!sym) { sym = evaluate_expression(expr->cast_expression); if (!sym) return NULL; /* * Expressions of restricted types will possibly get * promoted - check that here */ if (is_restricted_type(sym)) { if (sym->bit_size < bits_in_int && is_promoted(expr)) sym = &int_ctype; } else if (is_fouled_type(sym)) { sym = &int_ctype; } } examine_symbol_type(sym); if (is_bitfield_type(sym)) { expression_error(expr, "trying to examine bitfield type"); return NULL; } return sym; } static struct symbol *evaluate_sizeof(struct expression *expr) { struct symbol *type; int size; type = evaluate_type_information(expr); if (!type) return NULL; size = type->bit_size; if (size < 0 && is_void_type(type)) { if (Wpointer_arith) warning(expr->pos, "expression using sizeof(void)"); size = bits_in_char; } if (is_bool_type(type)) { if (Wsizeof_bool) warning(expr->pos, "expression using sizeof _Bool"); size = bits_to_bytes(bits_in_bool) * bits_in_char; } if (is_function(type->ctype.base_type)) { if (Wpointer_arith) warning(expr->pos, "expression using sizeof on a function"); size = bits_in_char; } if (is_array_type(type) && size < 0) { // VLA, 1-dimension only struct expression *base, *size; struct symbol *base_type; if (type->type == SYM_NODE) type = type->ctype.base_type; // strip the SYM_NODE base_type = get_base_type(type); if (!base_type) goto error; if (base_type->bit_size <= 0) { base = alloc_expression(expr->pos, EXPR_SIZEOF); base->cast_type = base_type; if (!evaluate_sizeof(base)) goto error; } else { base = alloc_expression(expr->pos, EXPR_VALUE); base->value = bits_to_bytes(base_type->bit_size); base->ctype = size_t_ctype; } size = alloc_expression(expr->pos, EXPR_CAST); size->cast_type = size_t_ctype; size->cast_expression = type->array_size; if (!evaluate_expression(size)) goto error; expr->left = size; expr->right = base; expr->type = EXPR_BINOP; expr->op = '*'; return expr->ctype = size_t_ctype; } error: if ((size < 0) || (size & (bits_in_char - 1))) expression_error(expr, "cannot size expression"); expr->type = EXPR_VALUE; expr->value = bits_to_bytes(size); expr->taint = 0; expr->ctype = size_t_ctype; return size_t_ctype; } static struct symbol *evaluate_ptrsizeof(struct expression *expr) { struct symbol *type; int size; type = evaluate_type_information(expr); if (!type) return NULL; if (type->type == SYM_NODE) type = type->ctype.base_type; if (!type) return NULL; switch (type->type) { case SYM_ARRAY: break; case SYM_PTR: type = get_base_type(type); if (type) break; default: expression_error(expr, "expected pointer expression"); return NULL; } size = type->bit_size; if (size & (bits_in_char-1)) size = 0; expr->type = EXPR_VALUE; expr->value = bits_to_bytes(size); expr->taint = 0; expr->ctype = size_t_ctype; return size_t_ctype; } static struct symbol *evaluate_alignof(struct expression *expr) { struct symbol *type; type = evaluate_type_information(expr); if (!type) return NULL; expr->type = EXPR_VALUE; expr->value = type->ctype.alignment; expr->taint = 0; expr->ctype = size_t_ctype; return size_t_ctype; } static int evaluate_arguments(struct symbol *fn, struct expression_list *head) { struct expression *expr; struct symbol_list *argument_types = fn->arguments; struct symbol *argtype; int i = 1; PREPARE_PTR_LIST(argument_types, argtype); FOR_EACH_PTR (head, expr) { struct expression **p = THIS_ADDRESS(expr); struct symbol *ctype, *target; ctype = evaluate_expression(expr); if (!ctype) return 0; target = argtype; if (!target) { struct symbol *type; int class = classify_type(ctype, &type); if (is_int(class)) { *p = cast_to(expr, integer_promotion(type)); } else if (class & TYPE_FLOAT) { unsigned long mod = type->ctype.modifiers; if (!(mod & (MOD_LONG_ALL))) *p = cast_to(expr, &double_ctype); } else if (class & TYPE_PTR) { if (expr->ctype == &null_ctype) *p = cast_to(expr, &ptr_ctype); else degenerate(expr); } } else if (!target->forced_arg){ static char where[30]; examine_symbol_type(target); sprintf(where, "argument %d", i); compatible_argument_type(expr, target, p, where); } i++; NEXT_PTR_LIST(argtype); } END_FOR_EACH_PTR(expr); FINISH_PTR_LIST(argtype); return 1; } static void convert_index(struct expression *e) { struct expression *child = e->idx_expression; unsigned from = e->idx_from; unsigned to = e->idx_to + 1; e->type = EXPR_POS; e->init_offset = from * bits_to_bytes(e->ctype->bit_size); e->init_nr = to - from; e->init_expr = child; } static void convert_ident(struct expression *e) { struct expression *child = e->ident_expression; int offset = e->offset; e->type = EXPR_POS; e->init_offset = offset; e->init_nr = 1; e->init_expr = child; } static void convert_designators(struct expression *e) { while (e) { if (e->type == EXPR_INDEX) convert_index(e); else if (e->type == EXPR_IDENTIFIER) convert_ident(e); else break; e = e->init_expr; } } static void excess(struct expression *e, const char *s) { warning(e->pos, "excessive elements in %s initializer", s); } /* * implicit designator for the first element */ static struct expression *first_subobject(struct symbol *ctype, int class, struct expression **v) { struct expression *e = *v, *new; if (ctype->type == SYM_NODE) ctype = ctype->ctype.base_type; if (class & TYPE_PTR) { /* array */ if (!ctype->bit_size) return NULL; new = alloc_expression(e->pos, EXPR_INDEX); new->idx_expression = e; new->ctype = ctype->ctype.base_type; } else { struct symbol *field, *p; PREPARE_PTR_LIST(ctype->symbol_list, p); while (p && !p->ident && is_bitfield_type(p)) NEXT_PTR_LIST(p); field = p; FINISH_PTR_LIST(p); if (!field) return NULL; new = alloc_expression(e->pos, EXPR_IDENTIFIER); new->ident_expression = e; new->field = new->ctype = field; new->offset = field->offset; } *v = new; return new; } /* * sanity-check explicit designators; return the innermost one or NULL * in case of error. Assign types. */ static struct expression *check_designators(struct expression *e, struct symbol *ctype) { struct expression *last = NULL; const char *err; while (1) { if (ctype->type == SYM_NODE) ctype = ctype->ctype.base_type; if (e->type == EXPR_INDEX) { struct symbol *type; if (ctype->type != SYM_ARRAY) { err = "array index in non-array"; break; } type = ctype->ctype.base_type; if (ctype->bit_size >= 0 && type->bit_size >= 0) { unsigned offset = array_element_offset(type->bit_size, e->idx_to); if (offset >= ctype->bit_size) { err = "index out of bounds in"; break; } } e->ctype = ctype = type; ctype = type; last = e; if (!e->idx_expression) { err = "invalid"; break; } e = e->idx_expression; } else if (e->type == EXPR_IDENTIFIER) { int offset = 0; if (ctype->type != SYM_STRUCT && ctype->type != SYM_UNION) { err = "field name not in struct or union"; break; } ctype = find_identifier(e->expr_ident, ctype->symbol_list, &offset); if (!ctype) { err = "unknown field name in"; break; } e->offset = offset; e->field = e->ctype = ctype; last = e; if (!e->ident_expression) { err = "invalid"; break; } e = e->ident_expression; } else if (e->type == EXPR_POS) { err = "internal front-end error: EXPR_POS in"; break; } else return last; } expression_error(e, "%s initializer", err); return NULL; } /* * choose the next subobject to initialize. * * Get designators for next element, switch old ones to EXPR_POS. * Return the resulting expression or NULL if we'd run out of subobjects. * The innermost designator is returned in *v. Designators in old * are assumed to be already sanity-checked. */ static struct expression *next_designators(struct expression *old, struct symbol *ctype, struct expression *e, struct expression **v) { struct expression *new = NULL; if (!old) return NULL; if (old->type == EXPR_INDEX) { struct expression *copy; unsigned n; copy = next_designators(old->idx_expression, old->ctype, e, v); if (!copy) { n = old->idx_to + 1; if (array_element_offset(old->ctype->bit_size, n) == ctype->bit_size) { convert_index(old); return NULL; } copy = e; *v = new = alloc_expression(e->pos, EXPR_INDEX); } else { n = old->idx_to; new = alloc_expression(e->pos, EXPR_INDEX); } new->idx_from = new->idx_to = n; new->idx_expression = copy; new->ctype = old->ctype; convert_index(old); } else if (old->type == EXPR_IDENTIFIER) { struct expression *copy; struct symbol *field; int offset = 0; copy = next_designators(old->ident_expression, old->ctype, e, v); if (!copy) { field = old->field->next_subobject; if (!field) { convert_ident(old); return NULL; } copy = e; *v = new = alloc_expression(e->pos, EXPR_IDENTIFIER); /* * We can't necessarily trust "field->offset", * because the field might be in an anonymous * union, and the field offset is then the offset * within that union. * * The "old->offset - old->field->offset" * would be the offset of such an anonymous * union. */ offset = old->offset - old->field->offset; } else { field = old->field; new = alloc_expression(e->pos, EXPR_IDENTIFIER); } new->field = field; new->expr_ident = field->ident; new->ident_expression = copy; new->ctype = field; new->offset = field->offset + offset; convert_ident(old); } return new; } static int handle_initializer(struct expression **ep, int nested, int class, struct symbol *ctype, unsigned long mods); /* * deal with traversing subobjects [6.7.8(17,18,20)] */ static void handle_list_initializer(struct expression *expr, int class, struct symbol *ctype, unsigned long mods) { struct expression *e, *last = NULL, *top = NULL, *next; int jumped = 0; FOR_EACH_PTR(expr->expr_list, e) { struct expression **v; struct symbol *type; int lclass; if (e->type != EXPR_INDEX && e->type != EXPR_IDENTIFIER) { struct symbol *struct_sym; if (!top) { top = e; last = first_subobject(ctype, class, &top); } else { last = next_designators(last, ctype, e, &top); } if (!last) { excess(e, class & TYPE_PTR ? "array" : "struct or union"); DELETE_CURRENT_PTR(e); continue; } struct_sym = ctype->type == SYM_NODE ? ctype->ctype.base_type : ctype; if (Wdesignated_init && struct_sym->designated_init) warning(e->pos, "%s%.*s%spositional init of field in %s %s, declared with attribute designated_init", ctype->ident ? "in initializer for " : "", ctype->ident ? ctype->ident->len : 0, ctype->ident ? ctype->ident->name : "", ctype->ident ? ": " : "", get_type_name(struct_sym->type), show_ident(struct_sym->ident)); if (jumped) { warning(e->pos, "advancing past deep designator"); jumped = 0; } REPLACE_CURRENT_PTR(e, last); } else { next = check_designators(e, ctype); if (!next) { DELETE_CURRENT_PTR(e); continue; } top = next; /* deeper than one designator? */ jumped = top != e; convert_designators(last); last = e; } found: lclass = classify_type(top->ctype, &type); if (top->type == EXPR_INDEX) v = &top->idx_expression; else v = &top->ident_expression; mods |= ctype->ctype.modifiers & MOD_STORAGE; if (handle_initializer(v, 1, lclass, top->ctype, mods)) continue; if (!(lclass & TYPE_COMPOUND)) { warning(e->pos, "bogus scalar initializer"); DELETE_CURRENT_PTR(e); continue; } next = first_subobject(type, lclass, v); if (next) { warning(e->pos, "missing braces around initializer"); top = next; goto found; } DELETE_CURRENT_PTR(e); excess(e, lclass & TYPE_PTR ? "array" : "struct or union"); } END_FOR_EACH_PTR(e); convert_designators(last); expr->ctype = ctype; } static int is_string_literal(struct expression **v) { struct expression *e = *v; while (e && e->type == EXPR_PREOP && e->op == '(') e = e->unop; if (!e || e->type != EXPR_STRING) return 0; if (e != *v && Wparen_string) warning(e->pos, "array initialized from parenthesized string constant"); *v = e; return 1; } /* * We want a normal expression, possibly in one layer of braces. Warn * if the latter happens inside a list (it's legal, but likely to be * an effect of screwup). In case of anything not legal, we are definitely * having an effect of screwup, so just fail and let the caller warn. */ static struct expression *handle_scalar(struct expression *e, int nested) { struct expression *v = NULL, *p; int count = 0; /* normal case */ if (e->type != EXPR_INITIALIZER) return e; FOR_EACH_PTR(e->expr_list, p) { if (!v) v = p; count++; } END_FOR_EACH_PTR(p); if (count != 1) return NULL; switch(v->type) { case EXPR_INITIALIZER: case EXPR_INDEX: case EXPR_IDENTIFIER: return NULL; default: break; } if (nested) warning(e->pos, "braces around scalar initializer"); return v; } /* * deal with the cases that don't care about subobjects: * scalar <- assignment expression, possibly in braces [6.7.8(11)] * character array <- string literal, possibly in braces [6.7.8(14)] * struct or union <- assignment expression of compatible type [6.7.8(13)] * compound type <- initializer list in braces [6.7.8(16)] * The last one punts to handle_list_initializer() which, in turn will call * us for individual elements of the list. * * We do not handle 6.7.8(15) (wide char array <- wide string literal) for * the lack of support of wide char stuff in general. * * One note: we need to take care not to evaluate a string literal until * we know that we *will* handle it right here. Otherwise we would screw * the cases like struct { struct {char s[10]; ...} ...} initialized with * { "string", ...} - we need to preserve that string literal recognizable * until we dig into the inner struct. */ static int handle_initializer(struct expression **ep, int nested, int class, struct symbol *ctype, unsigned long mods) { int is_string = is_string_type(ctype); struct expression *e = *ep, *p; struct symbol *type; if (!e) return 0; /* scalar */ if (!(class & TYPE_COMPOUND)) { e = handle_scalar(e, nested); if (!e) return 0; *ep = e; if (!evaluate_expression(e)) return 1; compatible_assignment_types(e, ctype, ep, "initializer"); /* * Initializers for static storage duration objects * shall be constant expressions or a string literal [6.7.8(4)]. */ mods |= ctype->ctype.modifiers; mods &= (MOD_TOPLEVEL | MOD_STATIC); if (mods && !(e->flags & (CEF_ACE | CEF_ADDR))) if (Wconstexpr_not_const) warning(e->pos, "non-constant initializer for static object"); return 1; } /* * sublist; either a string, or we dig in; the latter will deal with * pathologies, so we don't need anything fancy here. */ if (e->type == EXPR_INITIALIZER) { if (is_string) { struct expression *v = NULL; int count = 0; FOR_EACH_PTR(e->expr_list, p) { if (!v) v = p; count++; } END_FOR_EACH_PTR(p); if (count == 1 && is_string_literal(&v)) { *ep = e = v; goto String; } } handle_list_initializer(e, class, ctype, mods); return 1; } /* string */ if (is_string_literal(&e)) { /* either we are doing array of char, or we'll have to dig in */ if (is_string) { *ep = e; goto String; } return 0; } /* struct or union can be initialized by compatible */ if (class != TYPE_COMPOUND) return 0; type = evaluate_expression(e); if (!type) return 0; if (ctype->type == SYM_NODE) ctype = ctype->ctype.base_type; if (type->type == SYM_NODE) type = type->ctype.base_type; if (ctype == type) return 1; return 0; String: p = alloc_expression(e->pos, EXPR_STRING); *p = *e; type = evaluate_expression(p); if (ctype->bit_size != -1) { if (ctype->bit_size + bits_in_char < type->bit_size) warning(e->pos, "too long initializer-string for array of char"); else if (Winit_cstring && ctype->bit_size + bits_in_char == type->bit_size) { warning(e->pos, "too long initializer-string for array of char(no space for nul char)"); } } *ep = p; return 1; } static void evaluate_initializer(struct symbol *ctype, struct expression **ep) { struct symbol *type; int class = classify_type(ctype, &type); if (!handle_initializer(ep, 0, class, ctype, 0)) expression_error(*ep, "invalid initializer"); } static struct symbol *cast_to_bool(struct expression *expr) { struct expression *old = expr->cast_expression; struct expression *zero; struct symbol *otype; int oclass = classify_type(degenerate(old), &otype); struct symbol *ctype; if (oclass & TYPE_COMPOUND) return NULL; zero = alloc_const_expression(expr->pos, 0); expr->op = SPECIAL_NOTEQUAL; ctype = usual_conversions(expr->op, old, zero, oclass, TYPE_NUM, otype, zero->ctype); expr->type = EXPR_COMPARE; expr->left = cast_to(old, ctype); expr->right = cast_to(zero, ctype); return expr->ctype; } static int cast_flags(struct expression *expr, struct expression *old) { struct symbol *t; int class; int flags = CEF_NONE; class = classify_type(expr->ctype, &t); if (class & TYPE_NUM) { flags = old->flags & ~CEF_CONST_MASK; /* * Casts to numeric types never result in address * constants [6.6(9)]. */ flags &= ~CEF_ADDR; /* * As an extension, treat address constants cast to * integer type as an arithmetic constant. */ if (old->flags & CEF_ADDR) flags = CEF_ACE; /* * Cast to float type -> not an integer constant * expression [6.6(6)]. */ if (class & TYPE_FLOAT) flags &= ~CEF_CLR_ICE; /* * Casts of float literals to integer type results in * a constant integer expression [6.6(6)]. */ else if (old->flags & CEF_FLOAT) flags = CEF_SET_ICE; } else if (class & TYPE_PTR) { /* * Casts of integer literals to pointer type yield * address constants [6.6(9)]. * * As an extension, treat address constants cast to a * different pointer type as address constants again. * * As another extension, treat integer constant * expressions (in contrast to literals) cast to * pointer type as address constants. */ if (old->flags & (CEF_ICE | CEF_ADDR)) flags = CEF_ADDR; } return flags; } static struct symbol *evaluate_cast(struct expression *expr) { struct expression *source = expr->cast_expression; struct symbol *ctype; struct symbol *ttype, *stype; int tclass, sclass; struct ident *tas = NULL, *sas = NULL; if (!source) return NULL; /* * Special case: a cast can be followed by an * initializer, in which case we need to pass * the type value down to that initializer rather * than trying to evaluate it as an expression * * A more complex case is when the initializer is * dereferenced as part of a post-fix expression. * We need to produce an expression that can be dereferenced. */ if (source->type == EXPR_INITIALIZER) { struct symbol *sym = expr->cast_type; struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL); sym->initializer = source; evaluate_symbol(sym); addr->ctype = &lazy_ptr_ctype; /* Lazy eval */ addr->symbol = sym; if (sym->ctype.modifiers & MOD_TOPLEVEL) addr->flags |= CEF_ADDR; expr->type = EXPR_PREOP; expr->op = '*'; expr->unop = addr; expr->ctype = sym; return sym; } ctype = examine_symbol_type(expr->cast_type); expr->ctype = ctype; expr->cast_type = ctype; evaluate_expression(source); degenerate(source); tclass = classify_type(ctype, &ttype); expr->flags = cast_flags(expr, source); /* * You can always throw a value away by casting to * "void" - that's an implicit "force". Note that * the same is _not_ true of "void *". */ if (ttype == &void_ctype) goto out; stype = source->ctype; if (!stype) { expression_error(expr, "cast from unknown type"); goto out; } sclass = classify_type(stype, &stype); if (expr->type == EXPR_FORCE_CAST) goto out; if (tclass & (TYPE_COMPOUND | TYPE_FN)) warning(expr->pos, "cast to non-scalar"); if (sclass & TYPE_COMPOUND) warning(expr->pos, "cast from non-scalar"); /* allowed cast unfouls */ if (sclass & TYPE_FOULED) stype = unfoul(stype); if (ttype != stype) { if ((tclass & TYPE_RESTRICT) && restricted_value(source, ttype)) warning(expr->pos, "cast to %s", show_typename(ttype)); if (sclass & TYPE_RESTRICT) { if (ttype == &bool_ctype) { if (sclass & TYPE_FOULED) warning(expr->pos, "%s degrades to integer", show_typename(stype)); } else { warning(expr->pos, "cast from %s", show_typename(stype)); } } } if ((ttype == &ulong_ctype || ttype == uintptr_ctype) && !Wcast_from_as) tas = &bad_address_space; else if (tclass == TYPE_PTR) { examine_pointer_target(ttype); tas = ttype->ctype.as; } if ((stype == &ulong_ctype || stype == uintptr_ctype)) sas = &bad_address_space; else if (sclass == TYPE_PTR) { examine_pointer_target(stype); sas = stype->ctype.as; } if (!tas && valid_as(sas)) warning(expr->pos, "cast removes address space '%s' of expression", show_as(sas)); if (valid_as(tas) && valid_as(sas) && tas != sas) warning(expr->pos, "cast between address spaces (%s -> %s)", show_as(sas), show_as(tas)); if (valid_as(tas) && !sas && !is_null_pointer_constant(source) && Wcast_to_as) warning(expr->pos, "cast adds address space '%s' to expression", show_as(tas)); if (!(ttype->ctype.modifiers & MOD_PTRINHERIT) && tclass == TYPE_PTR && !tas && (source->flags & CEF_ICE)) { if (ttype->ctype.base_type == &void_ctype) { if (is_zero_constant(source)) { /* NULL */ expr->type = EXPR_VALUE; expr->ctype = &null_ctype; expr->value = 0; return expr->ctype; } } } if (ttype == &bool_ctype) cast_to_bool(expr); // checks pointers to restricted while (Wbitwise_pointer && tclass == TYPE_PTR && sclass == TYPE_PTR) { tclass = classify_type(ttype->ctype.base_type, &ttype); sclass = classify_type(stype->ctype.base_type, &stype); if (ttype == stype) break; if (!ttype || !stype) break; if (ttype == &void_ctype || stype == &void_ctype) break; if (tclass & TYPE_RESTRICT) { warning(expr->pos, "cast to %s", show_typename(ctype)); break; } if (sclass & TYPE_RESTRICT) { warning(expr->pos, "cast from %s", show_typename(source->ctype)); break; } } out: return ctype; } /* * Evaluate a call expression with a symbol. This * should expand inline functions, and evaluate * builtins. */ static int evaluate_symbol_call(struct expression *expr) { struct expression *fn = expr->fn; struct symbol *ctype = fn->ctype; if (fn->type != EXPR_PREOP) return 0; if (ctype->op && ctype->op->evaluate) return ctype->op->evaluate(expr); if (ctype->ctype.modifiers & MOD_INLINE) { int ret; struct symbol *curr = current_fn; if (ctype->definition) ctype = ctype->definition; current_fn = ctype->ctype.base_type; ret = inline_function(expr, ctype); /* restore the old function */ current_fn = curr; return ret; } return 0; } static struct symbol *evaluate_call(struct expression *expr) { int args, fnargs; struct symbol *ctype, *sym; struct expression *fn = expr->fn; struct expression_list *arglist = expr->args; if (!evaluate_expression(fn)) return NULL; sym = ctype = fn->ctype; if (ctype->type == SYM_NODE) ctype = ctype->ctype.base_type; if (ctype->type == SYM_PTR) ctype = get_base_type(ctype); if (ctype->type != SYM_FN) { struct expression *arg; expression_error(expr, "not a function %s", show_ident(sym->ident)); /* do typechecking in arguments */ FOR_EACH_PTR (arglist, arg) { evaluate_expression(arg); } END_FOR_EACH_PTR(arg); return NULL; } examine_fn_arguments(ctype); if (sym->type == SYM_NODE && fn->type == EXPR_PREOP && sym->op && sym->op->args) { if (!sym->op->args(expr)) return NULL; } else { if (!evaluate_arguments(ctype, arglist)) return NULL; args = expression_list_size(expr->args); fnargs = symbol_list_size(ctype->arguments); if (args < fnargs) { expression_error(expr, "not enough arguments for function %s", show_ident(sym->ident)); return NULL; } if (args > fnargs && !ctype->variadic) expression_error(expr, "too many arguments for function %s", show_ident(sym->ident)); } expr->ctype = ctype->ctype.base_type; if (sym->type == SYM_NODE) { if (evaluate_symbol_call(expr)) return expr->ctype; } return expr->ctype; } static struct symbol *evaluate_offsetof(struct expression *expr) { struct expression *e = expr->down; struct symbol *ctype = expr->in; int class; if (expr->op == '.') { struct symbol *field; int offset = 0; if (!ctype) { expression_error(expr, "expected structure or union"); return NULL; } examine_symbol_type(ctype); class = classify_type(ctype, &ctype); if (class != TYPE_COMPOUND) { expression_error(expr, "expected structure or union"); return NULL; } field = find_identifier(expr->ident, ctype->symbol_list, &offset); if (!field) { expression_error(expr, "unknown member"); return NULL; } ctype = field; expr->type = EXPR_VALUE; expr->flags = CEF_SET_ICE; expr->value = offset; expr->taint = 0; expr->ctype = size_t_ctype; } else { if (!ctype) { expression_error(expr, "expected structure or union"); return NULL; } examine_symbol_type(ctype); class = classify_type(ctype, &ctype); if (class != (TYPE_COMPOUND | TYPE_PTR)) { expression_error(expr, "expected array"); return NULL; } ctype = ctype->ctype.base_type; if (!expr->index) { expr->type = EXPR_VALUE; expr->flags = CEF_SET_ICE; expr->value = 0; expr->taint = 0; expr->ctype = size_t_ctype; } else { struct expression *idx = expr->index, *m; struct symbol *i_type = evaluate_expression(idx); unsigned old_idx_flags; int i_class = classify_type(i_type, &i_type); if (!is_int(i_class)) { expression_error(expr, "non-integer index"); return NULL; } unrestrict(idx, i_class, &i_type); old_idx_flags = idx->flags; idx = cast_to(idx, size_t_ctype); idx->flags = old_idx_flags; m = alloc_const_expression(expr->pos, bits_to_bytes(ctype->bit_size)); m->ctype = size_t_ctype; m->flags = CEF_SET_INT; expr->type = EXPR_BINOP; expr->left = idx; expr->right = m; expr->op = '*'; expr->ctype = size_t_ctype; expr->flags = m->flags & idx->flags & ~CEF_CONST_MASK; } } if (e) { struct expression *copy = __alloc_expression(0); *copy = *expr; if (e->type == EXPR_OFFSETOF) e->in = ctype; if (!evaluate_expression(e)) return NULL; expr->type = EXPR_BINOP; expr->flags = e->flags & copy->flags & ~CEF_CONST_MASK; expr->op = '+'; expr->ctype = size_t_ctype; expr->left = copy; expr->right = e; } return size_t_ctype; } struct symbol *evaluate_expression(struct expression *expr) { if (!expr) return NULL; if (expr->ctype) return expr->ctype; switch (expr->type) { case EXPR_VALUE: case EXPR_FVALUE: expression_error(expr, "value expression without a type"); return NULL; case EXPR_STRING: return evaluate_string(expr); case EXPR_SYMBOL: return evaluate_symbol_expression(expr); case EXPR_BINOP: evaluate_expression(expr->left); evaluate_expression(expr->right); if (!valid_subexpr_type(expr)) return NULL; return evaluate_binop(expr); case EXPR_LOGICAL: return evaluate_logical(expr); case EXPR_COMMA: evaluate_expression(expr->left); if (!evaluate_expression(expr->right)) return NULL; return evaluate_comma(expr); case EXPR_COMPARE: evaluate_expression(expr->left); evaluate_expression(expr->right); if (!valid_subexpr_type(expr)) return NULL; return evaluate_compare(expr); case EXPR_ASSIGNMENT: evaluate_expression(expr->left); evaluate_expression(expr->right); if (!valid_subexpr_type(expr)) return NULL; return evaluate_assignment(expr); case EXPR_PREOP: if (!evaluate_expression(expr->unop)) return NULL; return evaluate_preop(expr); case EXPR_POSTOP: if (!evaluate_expression(expr->unop)) return NULL; return evaluate_postop(expr); case EXPR_CAST: case EXPR_FORCE_CAST: case EXPR_IMPLIED_CAST: return evaluate_cast(expr); case EXPR_SIZEOF: return evaluate_sizeof(expr); case EXPR_PTRSIZEOF: return evaluate_ptrsizeof(expr); case EXPR_ALIGNOF: return evaluate_alignof(expr); case EXPR_DEREF: return evaluate_member_dereference(expr); case EXPR_CALL: return evaluate_call(expr); case EXPR_SELECT: case EXPR_CONDITIONAL: return evaluate_conditional_expression(expr); case EXPR_STATEMENT: expr->ctype = evaluate_statement(expr->statement); return expr->ctype; case EXPR_LABEL: expr->ctype = &ptr_ctype; return &ptr_ctype; case EXPR_TYPE: /* Evaluate the type of the symbol .. */ evaluate_symbol(expr->symbol); /* .. but the type of the _expression_ is a "type" */ expr->ctype = &type_ctype; return &type_ctype; case EXPR_OFFSETOF: return evaluate_offsetof(expr); /* These can not exist as stand-alone expressions */ case EXPR_INITIALIZER: case EXPR_IDENTIFIER: case EXPR_INDEX: case EXPR_POS: expression_error(expr, "internal front-end error: initializer in expression"); return NULL; case EXPR_SLICE: expression_error(expr, "internal front-end error: SLICE re-evaluated"); return NULL; case EXPR_ASM_OPERAND: expression_error(expr, "internal front-end error: ASM_OPERAND evaluated"); return NULL; } return NULL; } void check_duplicates(struct symbol *sym) { int declared = 0; struct symbol *next = sym; int initialized = sym->initializer != NULL; while ((next = next->same_symbol) != NULL) { const char *typediff; evaluate_symbol(next); if (initialized && next->initializer) { sparse_error(sym->pos, "symbol '%s' has multiple initializers (originally initialized at %s:%d)", show_ident(sym->ident), stream_name(next->pos.stream), next->pos.line); /* Only warn once */ initialized = 0; } declared++; typediff = type_difference(&sym->ctype, &next->ctype, 0, 0); if (typediff) { sparse_error(sym->pos, "symbol '%s' redeclared with different type (originally declared at %s:%d) - %s", show_ident(sym->ident), stream_name(next->pos.stream), next->pos.line, typediff); return; } } if (!declared) { unsigned long mod = sym->ctype.modifiers; if (mod & (MOD_STATIC | MOD_REGISTER | MOD_EXT_VISIBLE)) return; if (!(mod & MOD_TOPLEVEL)) return; if (!Wdecl) return; if (sym->ident == &main_ident) return; warning(sym->pos, "symbol '%s' was not declared. Should it be static?", show_ident(sym->ident)); } } static struct symbol *evaluate_symbol(struct symbol *sym) { struct symbol *base_type; if (!sym) return sym; if (sym->evaluated) return sym; sym->evaluated = 1; sym = examine_symbol_type(sym); base_type = get_base_type(sym); if (!base_type) return NULL; /* Evaluate the initializers */ if (sym->initializer) evaluate_initializer(sym, &sym->initializer); /* And finally, evaluate the body of the symbol too */ if (base_type->type == SYM_FN) { struct symbol *curr = current_fn; if (sym->definition && sym->definition != sym) return evaluate_symbol(sym->definition); current_fn = base_type; examine_fn_arguments(base_type); if (!base_type->stmt && base_type->inline_stmt) uninline(sym); if (base_type->stmt) evaluate_statement(base_type->stmt); current_fn = curr; } return base_type; } void evaluate_symbol_list(struct symbol_list *list) { struct symbol *sym; FOR_EACH_PTR(list, sym) { has_error &= ~ERROR_CURR_PHASE; evaluate_symbol(sym); check_duplicates(sym); } END_FOR_EACH_PTR(sym); } static struct symbol *evaluate_return_expression(struct statement *stmt) { struct expression *expr = stmt->expression; struct symbol *fntype; evaluate_expression(expr); fntype = current_fn->ctype.base_type; if (!fntype || fntype == &void_ctype) { if (expr && expr->ctype != &void_ctype) expression_error(expr, "return expression in %s function", fntype?"void":"typeless"); if (expr && Wreturn_void) warning(stmt->pos, "returning void-valued expression"); return NULL; } if (!expr) { sparse_error(stmt->pos, "return with no return value"); return NULL; } if (!expr->ctype) return NULL; compatible_assignment_types(expr, fntype, &stmt->expression, "return expression"); return NULL; } static void evaluate_if_statement(struct statement *stmt) { if (!stmt->if_conditional) return; evaluate_conditional(stmt->if_conditional, 0); evaluate_statement(stmt->if_true); evaluate_statement(stmt->if_false); } static void evaluate_iterator(struct statement *stmt) { evaluate_symbol_list(stmt->iterator_syms); evaluate_conditional(stmt->iterator_pre_condition, 1); evaluate_conditional(stmt->iterator_post_condition,1); evaluate_statement(stmt->iterator_pre_statement); evaluate_statement(stmt->iterator_statement); evaluate_statement(stmt->iterator_post_statement); } static void verify_output_constraint(struct expression *expr, const char *constraint) { switch (*constraint) { case '=': /* Assignment */ case '+': /* Update */ break; default: expression_error(expr, "output constraint is not an assignment constraint (\"%s\")", constraint); } } static void verify_input_constraint(struct expression *expr, const char *constraint) { switch (*constraint) { case '=': /* Assignment */ case '+': /* Update */ expression_error(expr, "input constraint with assignment (\"%s\")", constraint); } } static void evaluate_asm_statement(struct statement *stmt) { struct expression *expr; struct expression *op; struct symbol *sym; expr = stmt->asm_string; if (!expr || expr->type != EXPR_STRING) { sparse_error(stmt->pos, "need constant string for inline asm"); return; } FOR_EACH_PTR(stmt->asm_outputs, op) { /* Identifier */ /* Constraint */ expr = op->constraint; if (!expr || expr->type != EXPR_STRING) { sparse_error(expr ? expr->pos : stmt->pos, "asm output constraint is not a string"); op->constraint = NULL; } else verify_output_constraint(expr, expr->string->data); /* Expression */ expr = op->expr; if (!evaluate_expression(expr)) return; if (!lvalue_expression(expr)) warning(expr->pos, "asm output is not an lvalue"); evaluate_assign_to(expr, expr->ctype); } END_FOR_EACH_PTR(op); FOR_EACH_PTR(stmt->asm_inputs, op) { /* Identifier */ /* Constraint */ expr = op->constraint; if (!expr || expr->type != EXPR_STRING) { sparse_error(expr ? expr->pos : stmt->pos, "asm input constraint is not a string"); op->constraint = NULL; } else verify_input_constraint(expr, expr->string->data); /* Expression */ if (!evaluate_expression(op->expr)) return; } END_FOR_EACH_PTR(op); FOR_EACH_PTR(stmt->asm_clobbers, expr) { if (!expr) { sparse_error(stmt->pos, "bad asm clobbers"); return; } if (expr->type == EXPR_STRING) continue; expression_error(expr, "asm clobber is not a string"); } END_FOR_EACH_PTR(expr); FOR_EACH_PTR(stmt->asm_labels, sym) { if (!sym || sym->type != SYM_LABEL) { sparse_error(stmt->pos, "bad asm label"); return; } } END_FOR_EACH_PTR(sym); } static void evaluate_case_statement(struct statement *stmt) { evaluate_expression(stmt->case_expression); evaluate_expression(stmt->case_to); evaluate_statement(stmt->case_statement); } static void check_case_type(struct expression *switch_expr, struct expression *case_expr, struct expression **enumcase) { struct symbol *switch_type, *case_type; int sclass, cclass; if (!case_expr) return; switch_type = switch_expr->ctype; case_type = evaluate_expression(case_expr); if (!switch_type || !case_type) goto Bad; if (enumcase) { if (*enumcase) warn_for_different_enum_types(case_expr->pos, case_type, (*enumcase)->ctype); else if (is_enum_type(case_type)) *enumcase = case_expr; } sclass = classify_type(switch_type, &switch_type); cclass = classify_type(case_type, &case_type); /* both should be arithmetic */ if (!(sclass & cclass & TYPE_NUM)) goto Bad; /* neither should be floating */ if ((sclass | cclass) & TYPE_FLOAT) goto Bad; /* if neither is restricted, we are OK */ if (!((sclass | cclass) & TYPE_RESTRICT)) return; if (!restricted_binop_type(SPECIAL_EQUAL, case_expr, switch_expr, cclass, sclass, case_type, switch_type)) { unrestrict(case_expr, cclass, &case_type); unrestrict(switch_expr, sclass, &switch_type); } return; Bad: expression_error(case_expr, "incompatible types for 'case' statement"); } static void evaluate_switch_statement(struct statement *stmt) { struct symbol *sym; struct expression *enumcase = NULL; struct expression **enumcase_holder = &enumcase; struct expression *sel = stmt->switch_expression; evaluate_expression(sel); evaluate_statement(stmt->switch_statement); if (!sel) return; if (sel->ctype && is_enum_type(sel->ctype)) enumcase_holder = NULL; /* Only check cases against switch */ FOR_EACH_PTR(stmt->switch_case->symbol_list, sym) { struct statement *case_stmt = sym->stmt; check_case_type(sel, case_stmt->case_expression, enumcase_holder); check_case_type(sel, case_stmt->case_to, enumcase_holder); } END_FOR_EACH_PTR(sym); } static void evaluate_goto_statement(struct statement *stmt) { struct symbol *label = stmt->goto_label; if (label && !label->stmt && label->ident && !lookup_keyword(label->ident, NS_KEYWORD)) sparse_error(stmt->pos, "label '%s' was not declared", show_ident(label->ident)); evaluate_expression(stmt->goto_expression); } struct symbol *evaluate_statement(struct statement *stmt) { if (!stmt) return NULL; switch (stmt->type) { case STMT_DECLARATION: { struct symbol *s; FOR_EACH_PTR(stmt->declaration, s) { evaluate_symbol(s); } END_FOR_EACH_PTR(s); return NULL; } case STMT_RETURN: return evaluate_return_expression(stmt); case STMT_EXPRESSION: if (!evaluate_expression(stmt->expression)) return NULL; if (stmt->expression->ctype == &null_ctype) stmt->expression = cast_to(stmt->expression, &ptr_ctype); return degenerate(stmt->expression); case STMT_COMPOUND: { struct statement *s; struct symbol *type = NULL; /* Evaluate the return symbol in the compound statement */ evaluate_symbol(stmt->ret); /* * Then, evaluate each statement, making the type of the * compound statement be the type of the last statement */ type = evaluate_statement(stmt->args); FOR_EACH_PTR(stmt->stmts, s) { type = evaluate_statement(s); } END_FOR_EACH_PTR(s); if (!type) type = &void_ctype; return type; } case STMT_IF: evaluate_if_statement(stmt); return NULL; case STMT_ITERATOR: evaluate_iterator(stmt); return NULL; case STMT_SWITCH: evaluate_switch_statement(stmt); return NULL; case STMT_CASE: evaluate_case_statement(stmt); return NULL; case STMT_LABEL: return evaluate_statement(stmt->label_statement); case STMT_GOTO: evaluate_goto_statement(stmt); return NULL; case STMT_NONE: break; case STMT_ASM: evaluate_asm_statement(stmt); return NULL; case STMT_CONTEXT: evaluate_expression(stmt->expression); return NULL; case STMT_RANGE: evaluate_expression(stmt->range_expression); evaluate_expression(stmt->range_low); evaluate_expression(stmt->range_high); return NULL; } return NULL; }