/* * sparse/evaluate.c * * Copyright (C) 2003 Transmeta Corp. * 2003-2004 Linus Torvalds * * Licensed under the Open Software License version 1.1 * * Evaluate constant expressions. */ #include #include #include #include #include #include #include #include #include #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; static struct symbol *degenerate(struct expression *expr); static struct symbol *evaluate_symbol(struct symbol *sym); 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 */ expr->type = EXPR_PREOP; expr->op = '*'; expr->unop = addr; /* 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 = bits_in_char * 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 = bits_in_char * length; array->ctype.alignment = 1; array->ctype.modifiers = MOD_STATIC; array->ctype.base_type = &char_ctype; addr->symbol = sym; addr->ctype = &lazy_ptr_ctype; 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) { struct symbol *orig_type = 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; orig_type = 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 orig_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 | MOD_LONGLONG)) 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, unsigned long *asp) { unsigned long mod, as; mod = 0; as = 0; while (node) { mod |= node->ctype.modifiers; 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, 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)); } } /* * 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->flags = old->flags; expr->ctype = type; expr->cast_type = type; expr->cast_expression = old; return expr; } static int is_type_type(struct symbol *type) { return (type->ctype.modifiers & MOD_TYPE) != 0; } int is_ptr_type(struct symbol *type) { if (type->type == SYM_NODE) type = type->ctype.base_type; return type->type == SYM_PTR || type->type == SYM_ARRAY || type->type == SYM_FN; } static inline int is_float_type(struct symbol *type) { if (type->type == SYM_NODE) type = type->ctype.base_type; return type->ctype.base_type == &fp_type; } static inline int is_byte_type(struct symbol *type) { return type->bit_size == bits_in_char && type->type != SYM_BITFIELD; } enum { TYPE_NUM = 1, TYPE_BITFIELD = 2, TYPE_RESTRICT = 4, TYPE_FLOAT = 8, TYPE_PTR = 16, TYPE_COMPOUND = 32, TYPE_FOULED = 64, }; 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, [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_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) { sparse_error(expr->pos, "incompatible types for operation (%s)", show_special(expr->op)); switch (expr->type) { case EXPR_BINOP: case EXPR_COMPARE: 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: info(expr->pos, " argument has type %s", show_typename(expr->unop->ctype)); break; default: break; } expr->flags = 0; 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; } 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 (ltype->ctype.base_type == rtype) ctype = ltype; } else if (rclass & TYPE_FOULED) { if (rtype->ctype.base_type == 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 = ctype->ctype.base_type; 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) { warning(expr->pos, "restricted degrades to integer"); if (class & TYPE_FOULED) /* unfoul it first */ *ctype = (*ctype)->ctype.base_type; *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 | MOD_LONGLONG)) 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 int ptr_object_size(struct symbol *ptr_type) { if (ptr_type->type == SYM_NODE) ptr_type = ptr_type->ctype.base_type; if (ptr_type->type == SYM_PTR) ptr_type = get_base_type(ptr_type); return ptr_type->bit_size; } static struct symbol *evaluate_ptr_add(struct expression *expr, struct symbol *ctype, struct symbol *itype) { struct expression *index = expr->right; int multiply; int bit_size; if (ctype == &null_ctype) ctype = &ptr_ctype; examine_symbol_type(ctype); if (!ctype->ctype.base_type) { expression_error(expr, "missing type information"); return NULL; } /* Get the size of whatever the pointer points to */ bit_size = ptr_object_size(ctype); multiply = bit_size >> 3; 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_VOLATILE | MOD_CONST) const char *type_difference(struct ctype *c1, struct ctype *c2, unsigned long mod1, unsigned long mod2) { unsigned long 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; as1 |= t1->ctype.as; } move1 = 0; } if (move2) { if (t2 && t2->type != SYM_PTR) { mod2 |= t2->ctype.modifiers; 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: case SYM_UNION: case SYM_STRUCT: return "different base types"; case SYM_ARRAY: /* XXX: we ought to compare sizes */ break; case SYM_PTR: if (Waddress_space && 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 (Waddress_space && 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 (base1->variadic != base2->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 (Waddress_space && 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"; if (diff & ~MOD_SIGNEDNESS) return "different modifiers"; /* Differs in signedness only.. */ if (Wtypesign) { /* * Warn if both are explicitly signed ("unsigned" is obviously * always explicit, and since we know one of them has to be * unsigned, we check if the signed one was explicit). */ if ((mod1 | mod2) & MOD_EXPLICITLY_SIGNED) return "different explicit signedness"; /* * "char" matches both "unsigned char" and "signed char", * so if the explicit test didn't trigger, then we should * not warn about a char. */ if (!(mod1 & MOD_CHAR)) return "different signedness"; } return NULL; } t1 = base1; t2 = base2; } if (Waddress_space && 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, *rbase; classify_type(degenerate(l), <ype); classify_type(degenerate(r), &rtype); lbase = examine_pointer_target(ltype); rbase = 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 (lbase->type == SYM_FN) { 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 = lbase->bit_size >> 3; val->ctype = size_t_ctype; val->value = value; if (value & (value-1)) { if (Wptr_subtraction_blows) warning(expr->pos, "potentially expensive pointer subtraction"); } 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 (ctype) { if (is_safe_type(ctype)) warning(expr->pos, "testing a 'safe expression'"); } 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; expr->ctype = &bool_ctype; if (expr->flags) { if (!(expr->left->flags & expr->right->flags & Int_const_expr)) expr->flags = 0; } return &bool_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; if (expr->flags) { if (!(expr->left->flags & expr->right->flags & Int_const_expr)) expr->flags = 0; } /* number op number */ if (lclass & rclass & TYPE_NUM) { 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 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, degenerate(expr->left), 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, degenerate(expr->left), 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 = expr->right->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; } static inline int is_null_pointer_constant(struct expression *e) { if (e->ctype == &null_ctype) return 1; if (!(e->flags & Int_const_expr)) return 0; return is_zero_constant(e) ? 2 : 0; } 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; if (expr->flags) { if (!(expr->left->flags & expr->right->flags & Int_const_expr)) expr->flags = 0; } /* Type types? */ if (is_type_type(ltype) && is_type_type(rtype)) goto OK; if (is_safe_type(left->ctype) || is_safe_type(right->ctype)) warning(expr->pos, "testing a 'safe expression'"); /* 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 == 2) bad_null(left); if (is_null2 == 2) 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) { left = cast_to(left, rtype); goto OK; } if (is_null2) { 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); return NULL; OK: expr->ctype = &bool_ctype; return &bool_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 **true; 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); true = &expr->conditional; ltype = ctype; if (expr->cond_true) { if (!evaluate_expression(expr->cond_true)) return NULL; ltype = degenerate(expr->cond_true); true = &expr->cond_true; } if (expr->flags) { int flags = expr->conditional->flags & Int_const_expr; flags &= (*true)->flags & expr->cond_false->flags; if (!flags) expr->flags = 0; } lclass = classify_type(ltype, <ype); rclass = classify_type(rtype, &rtype); if (lclass & rclass & TYPE_NUM) { ctype = usual_conversions('?', *true, expr->cond_false, lclass, rclass, ltype, rtype); *true = cast_to(*true, ctype); expr->cond_false = cast_to(expr->cond_false, ctype); goto out; } if ((lclass | rclass) & TYPE_PTR) { int is_null1 = is_null_pointer_constant(*true); int is_null2 = is_null_pointer_constant(expr->cond_false); if (is_null1 && is_null2) { *true = cast_to(*true, &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 == 2) bad_null(*true); *true = cast_to(*true, rtype); ctype = rtype; goto out; } if (is_null2 && (lclass & TYPE_PTR)) { if (is_null2 == 2) 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); 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; } *true = cast_to(*true, 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)) { expression_error(expr, "bad restricted assignment"); return 0; } /* allowed assignments unfoul */ if (sclass & TYPE_FOULED && s->ctype.base_type == t) goto Cast; if (!restricted_value(expr->right, t)) return 1; } else if (!(sclass & TYPE_RESTRICT)) goto Cast; /* source and target would better be identical restricted */ if (t == s) return 1; warning(expr->pos, "invalid restricted assignment"); 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, target, s); return 1; } expression_error(expr, "invalid pointer assignment"); return 0; } expression_error(expr, "invalid assignment"); return 0; Cast: expr->right = cast_to(expr->right, 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); 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 && s->ctype.base_type == t) goto Cast; if (!restricted_value(*rp, target)) return 1; if (s == t) return 1; } else if (!(sclass & TYPE_RESTRICT)) goto Cast; typediff = "different base types"; goto Err; } 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 == 2) bad_null(*rp); goto Cast; } if (!(sclass & TYPE_PTR)) { typediff = "different base types"; goto Err; } b1 = examine_pointer_target(t); b2 = examine_pointer_target(s); mod1 = target_qualifiers(t); mod2 = target_qualifiers(s); if (b1 == &void_ctype || b2 == &void_ctype) { /* * 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"; goto Err; } if (mod2 & ~mod1) { typediff = "different modifiers"; goto Err; } 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) goto Err; 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"; goto Err; } typediff = "invalid types"; Err: 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; Cast: *rp = cast_to(*rp, target); return 1; } 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 expression *where = expr; 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(where, 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; ptr->ctype.as |= s->ctype.as; ptr->ctype.modifiers |= s->ctype.modifiers & MOD_PTRINHERIT; s->ctype.base_type = ptr; s->ctype.as = 0; 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, int 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) { 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) { 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, expr->r_bitpos >> 3); 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; expr->flags = 0; 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 = 0; return expr->ctype; } /* Dereferencing a node drops all the node information. */ if (ctype->type == SYM_NODE) ctype = ctype->ctype.base_type; node = alloc_symbol(expr->pos, SYM_NODE); target = ctype->ctype.base_type; switch (ctype->type) { default: expression_error(expr, "cannot dereference this type"); return NULL; case SYM_PTR: 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.. */ 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; if (!lvalue_expression(expr->unop)) { expression_error(expr, "need lvalue expression for ++/--"); return NULL; } if (is_restricted_type(ctype) && restricted_unop(expr->op, &ctype)) { expression_error(expr, "bad operation on restricted"); return NULL; } else if (is_fouled_type(ctype) && restricted_unop(expr->op, &ctype)) { expression_error(expr, "bad operation on restricted"); return NULL; } evaluate_assign_to(op, ctype); expr->ctype = ctype; expr->op_value = 1; if (is_ptr_type(ctype)) expr->op_value = ptr_object_size(ctype) >> 3; return ctype; } static struct symbol *evaluate_sign(struct expression *expr) { struct symbol *ctype = expr->unop->ctype; int class = classify_type(ctype, &ctype); if (expr->flags && !(expr->unop->flags & Int_const_expr)) expr->flags = 0; /* should be an arithmetic type */ if (!(class & TYPE_NUM)) return bad_expr_type(expr); if (!(class & (TYPE_FLOAT|TYPE_RESTRICT))) { struct symbol *rtype = integer_promotion(ctype); expr->unop = cast_to(expr->unop, rtype); ctype = rtype; } else if ((class & TYPE_FLOAT) && expr->op != '~') { /* no conversions needed */ } else if ((class & TYPE_RESTRICT) && !restricted_unop(expr->op, &ctype)) { /* no conversions needed */ } else { return bad_expr_type(expr); } if (expr->op == '+') *expr = *expr->unop; expr->ctype = ctype; return ctype; } 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 '!': if (expr->flags && !(expr->unop->flags & Int_const_expr)) expr->flags = 0; 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_BINOP; 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, "restricted degrades to integer"); } ctype = &bool_ctype; break; default: break; } expr->ctype = ctype; return &bool_ctype; } static 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; 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; unsigned int mod; int address_space; if (!evaluate_expression(deref)) return NULL; if (!ident) { expression_error(expr, "bad member name"); return NULL; } ctype = deref->ctype; address_space = ctype->ctype.as; mod = ctype->ctype.modifiers; if (ctype->type == SYM_NODE) { ctype = ctype->ctype.base_type; 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; } examine_symbol_type(ctype); 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 += offset << 3; 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) || (size & 7)) expression_error(expr, "cannot size expression"); expr->type = EXPR_VALUE; expr->value = size >> 3; 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 & 7) size = 0; expr->type = EXPR_VALUE; expr->value = size >> 3; 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 *f, 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|MOD_LONGLONG))) *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 { static char where[30]; examine_symbol_type(target); sprintf(where, "argument %d", i); compatible_assignment_types(expr, target, p, where); } i++; NEXT_PTR_LIST(argtype); } END_FOR_EACH_PTR(expr); FINISH_PTR_LIST(argtype); return 1; } static struct symbol *find_struct_ident(struct symbol *ctype, struct ident *ident) { struct symbol *sym; FOR_EACH_PTR(ctype->symbol_list, sym) { if (sym->ident == ident) return sym; } END_FOR_EACH_PTR(sym); return NULL; } 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 * (e->ctype->bit_size>>3); e->init_nr = to - from; e->init_expr = child; } static void convert_ident(struct expression *e) { struct expression *child = e->ident_expression; struct symbol *sym = e->field; e->type = EXPR_POS; e->init_offset = sym->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; } *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 = e->idx_to * type->bit_size; 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) { if (ctype->type != SYM_STRUCT && ctype->type != SYM_UNION) { err = "field name not in struct or union"; break; } ctype = find_struct_ident(ctype, e->expr_ident); if (!ctype) { err = "unknown field name in"; break; } 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 (n * old->ctype->bit_size == 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; 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); } 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; convert_ident(old); } return new; } static int handle_simple_initializer(struct expression **ep, int nested, int class, struct symbol *ctype); /* * deal with traversing subobjects [6.7.8(17,18,20)] */ static void handle_list_initializer(struct expression *expr, int class, struct symbol *ctype) { 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) { 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; } 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; if (handle_simple_initializer(v, 1, lclass, top->ctype)) 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_simple_initializer(struct expression **ep, int nested, int class, struct symbol *ctype) { 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"); 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); 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 && ctype->bit_size + bits_in_char < type->bit_size) { warning(e->pos, "too long initializer-string for array of 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_simple_initializer(ep, 0, class, ctype)) expression_error(*ep, "invalid initializer"); } static struct symbol *evaluate_cast(struct expression *expr) { struct expression *target = expr->cast_expression; struct symbol *ctype; struct symbol *t1, *t2; int class1, class2; int as1 = 0, as2 = 0; if (!target) 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 (target->type == EXPR_INITIALIZER) { struct symbol *sym = expr->cast_type; struct expression *addr = alloc_expression(expr->pos, EXPR_SYMBOL); sym->initializer = target; evaluate_symbol(sym); addr->ctype = &lazy_ptr_ctype; /* Lazy eval */ addr->symbol = sym; 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(target); degenerate(target); class1 = classify_type(ctype, &t1); /* cast to non-integer type -> not an integer constant expression */ if (!is_int(class1)) expr->flags = 0; /* if argument turns out to be not an integer constant expression *and* it was not a floating literal to start with -> too bad */ else if (expr->flags == Int_const_expr && !(target->flags & Int_const_expr)) expr->flags = 0; /* * 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 (t1 == &void_ctype) goto out; if (class1 & TYPE_COMPOUND) warning(expr->pos, "cast to non-scalar"); t2 = target->ctype; if (!t2) { expression_error(expr, "cast from unknown type"); goto out; } class2 = classify_type(t2, &t2); if (class2 & TYPE_COMPOUND) warning(expr->pos, "cast from non-scalar"); if (expr->type == EXPR_FORCE_CAST) goto out; /* allowed cast unfouls */ if (class2 & TYPE_FOULED) t2 = t2->ctype.base_type; if (t1 != t2) { if (class1 & TYPE_RESTRICT) warning(expr->pos, "cast to restricted type"); if (class2 & TYPE_RESTRICT) warning(expr->pos, "cast from restricted type"); } if (t1 == &ulong_ctype) as1 = -1; else if (class1 == TYPE_PTR) { examine_pointer_target(t1); as1 = t1->ctype.as; } if (t2 == &ulong_ctype) as2 = -1; else if (class2 == TYPE_PTR) { examine_pointer_target(t2); as2 = t2->ctype.as; } if (!as1 && as2 > 0) warning(expr->pos, "cast removes address space of expression"); if (as1 > 0 && as2 > 0 && as1 != as2) warning(expr->pos, "cast between address spaces (->)", as2, as1); if (as1 > 0 && !as2 && !is_null_pointer_constant(target) && Wcast_to_address_space) warning(expr->pos, "cast adds address space to expression ()", as1); if (!(t1->ctype.modifiers & MOD_PTRINHERIT) && class1 == TYPE_PTR && !as1 && (target->flags & Int_const_expr)) { if (t1->ctype.base_type == &void_ctype) { if (is_zero_constant(target)) { /* NULL */ expr->type = EXPR_VALUE; expr->ctype = &null_ctype; expr->value = 0; return ctype; } } } 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; 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->type == SYM_ARRAY) ctype = get_base_type(ctype); 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(sym, ctype, arglist)) return NULL; if (ctype->type != SYM_FN) { expression_error(expr, "not a function %s", show_ident(sym->ident)); 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)); if (args > fnargs && !ctype->variadic) expression_error(expr, "too many arguments for function %s", show_ident(sym->ident)); } if (sym->type == SYM_NODE) { if (evaluate_symbol_call(expr)) return expr->ctype; } expr->ctype = ctype->ctype.base_type; 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 = Int_const_expr; 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 = Int_const_expr; 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); 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); idx = cast_to(idx, size_t_ctype); m = alloc_const_expression(expr->pos, ctype->bit_size >> 3); m->ctype = size_t_ctype; m->flags = Int_const_expr; expr->type = EXPR_BINOP; expr->left = idx; expr->right = m; expr->op = '*'; expr->ctype = size_t_ctype; expr->flags = m->flags & idx->flags & Int_const_expr; } } 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 & Int_const_expr; 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: if (!evaluate_expression(expr->left)) return NULL; if (!evaluate_expression(expr->right)) 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: if (!evaluate_expression(expr->left)) return NULL; if (!evaluate_expression(expr->right)) return NULL; return evaluate_compare(expr); case EXPR_ASSIGNMENT: if (!evaluate_expression(expr->left)) return NULL; if (!evaluate_expression(expr->right)) 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; } return NULL; } static void check_duplicates(struct symbol *sym) { int declared = 0; struct symbol *next = sym; while ((next = next->same_symbol) != NULL) { const char *typediff; evaluate_symbol(next); 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)) 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; 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) { 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_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; int state; expr = stmt->asm_string; if (!expr || expr->type != EXPR_STRING) { sparse_error(stmt->pos, "need constant string for inline asm"); return; } state = 0; FOR_EACH_PTR(stmt->asm_outputs, expr) { struct ident *ident; switch (state) { case 0: /* Identifier */ state = 1; ident = (struct ident *)expr; continue; case 1: /* Constraint */ state = 2; if (!expr || expr->type != EXPR_STRING) { sparse_error(expr ? expr->pos : stmt->pos, "asm output constraint is not a string"); *THIS_ADDRESS(expr) = NULL; continue; } verify_output_constraint(expr, expr->string->data); continue; case 2: /* Expression */ state = 0; if (!evaluate_expression(expr)) return; if (!lvalue_expression(expr)) warning(expr->pos, "asm output is not an lvalue"); evaluate_assign_to(expr, expr->ctype); continue; } } END_FOR_EACH_PTR(expr); state = 0; FOR_EACH_PTR(stmt->asm_inputs, expr) { struct ident *ident; switch (state) { case 0: /* Identifier */ state = 1; ident = (struct ident *)expr; continue; case 1: /* Constraint */ state = 2; if (!expr || expr->type != EXPR_STRING) { sparse_error(expr ? expr->pos : stmt->pos, "asm input constraint is not a string"); *THIS_ADDRESS(expr) = NULL; continue; } verify_input_constraint(expr, expr->string->data); continue; case 2: /* Expression */ state = 0; if (!evaluate_expression(expr)) return; continue; } } END_FOR_EACH_PTR(expr); FOR_EACH_PTR(stmt->asm_clobbers, expr) { if (!expr) { sparse_error(stmt->pos, "bad asm output"); return; } if (expr->type == EXPR_STRING) continue; expression_error(expr, "asm clobber is not a string"); } END_FOR_EACH_PTR(expr); } 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)) warning(case_expr->pos, "restricted degrades to integer"); 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); } 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_expression(stmt->goto_expression); 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; }