diff options
| author | Josh Triplett <josh@freedesktop.org> | 2007-06-26 15:43:08 -0700 |
|---|---|---|
| committer | Josh Triplett <josh@freedesktop.org> | 2007-06-26 15:43:08 -0700 |
| commit | 36e13ae4117a23f725f05b6a03ea7ae12c6edc39 (patch) | |
| tree | 64d295da21135e07b541bcc5703cbf05dab91118 | |
| parent | 185d8836c3d6139f285152f533cefce8a8289442 (diff) | |
| parent | a24a3adf3f0e3c22b0d98837090c55307f6fec84 (diff) | |
| download | sparse-dev-36e13ae4117a23f725f05b6a03ea7ae12c6edc39.tar.gz | |
Merge commit 'viro/integer-constant'
* commit 'viro/integer-constant':
[PATCH] fix handling of integer constant expressions
[PATCH] implement __builtin_offsetof()
| -rw-r--r-- | evaluate.c | 127 | ||||
| -rw-r--r-- | expand.c | 17 | ||||
| -rw-r--r-- | expression.c | 135 | ||||
| -rw-r--r-- | expression.h | 19 | ||||
| -rw-r--r-- | ident-list.h | 1 | ||||
| -rw-r--r-- | inline.c | 18 | ||||
| -rw-r--r-- | lib.c | 1 | ||||
| -rw-r--r-- | parse.c | 10 | ||||
| -rw-r--r-- | show-parse.c | 1 |
9 files changed, 314 insertions, 15 deletions
@@ -311,6 +311,7 @@ static struct expression * cast_to(struct expression *old, struct symbol *type) } expr = alloc_expression(old->pos, EXPR_IMPLIED_CAST); + expr->flags = old->flags; expr->ctype = type; expr->cast_type = type; expr->cast_expression = old; @@ -403,6 +404,7 @@ static struct symbol *bad_expr_type(struct expression *expr) break; } + expr->flags = 0; return expr->ctype = &bad_ctype; } @@ -880,6 +882,10 @@ static struct symbol *evaluate_logical(struct expression *expr) 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; } @@ -890,6 +896,11 @@ static struct symbol *evaluate_binop(struct expression *expr) 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) { @@ -968,6 +979,11 @@ static struct symbol *evaluate_compare(struct expression *expr) struct symbol *ctype; int lclass, rclass; + 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; @@ -1057,6 +1073,13 @@ static struct symbol *evaluate_conditional_expression(struct expression *expr) 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) { @@ -1436,6 +1459,7 @@ static struct symbol *evaluate_addressof(struct expression *expr) } ctype = op->ctype; *expr = *op->unop; + expr->flags = 0; if (expr->type == EXPR_SYMBOL) { struct symbol *sym = expr->symbol; @@ -1463,6 +1487,7 @@ static struct symbol *evaluate_dereference(struct expression *expr) /* Simplify: *&(expr) => (expr) */ if (op->type == EXPR_PREOP && op->op == '&') { *expr = *op->unop; + expr->flags = 0; return expr->ctype; } @@ -1540,6 +1565,8 @@ static struct symbol *evaluate_postop(struct expression *expr) static struct symbol *evaluate_sign(struct expression *expr) { struct symbol *ctype = expr->unop->ctype; + if (expr->flags && !(expr->unop->flags & Int_const_expr)) + expr->flags = 0; if (is_int_type(ctype)) { struct symbol *rtype = rtype = integer_promotion(ctype); expr->unop = cast_to(expr->unop, rtype); @@ -1588,6 +1615,8 @@ static struct symbol *evaluate_preop(struct expression *expr) 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)) { @@ -2477,6 +2506,15 @@ static struct symbol *evaluate_cast(struct expression *expr) 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 @@ -2608,6 +2646,92 @@ static struct symbol *evaluate_call(struct expression *expr) 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->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->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) @@ -2688,6 +2812,9 @@ struct symbol *evaluate_expression(struct expression *expr) 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: @@ -968,6 +968,7 @@ static int expand_expression(struct expression *expr) case EXPR_SIZEOF: case EXPR_PTRSIZEOF: case EXPR_ALIGNOF: + case EXPR_OFFSETOF: expression_error(expr, "internal front-end error: sizeof in expansion?"); return UNSAFE; } @@ -1143,7 +1144,7 @@ static int expand_statement(struct statement *stmt) return SIDE_EFFECTS; } -long long get_expression_value(struct expression *expr) +static long long __get_expression_value(struct expression *expr, int strict) { long long value, mask; struct symbol *ctype; @@ -1160,6 +1161,10 @@ long long get_expression_value(struct expression *expr) expression_error(expr, "bad constant expression"); return 0; } + if (strict && !(expr->flags & Int_const_expr)) { + expression_error(expr, "bad integer constant expression"); + return 0; + } value = expr->value; mask = 1ULL << (ctype->bit_size-1); @@ -1172,3 +1177,13 @@ long long get_expression_value(struct expression *expr) } return value; } + +long long get_expression_value(struct expression *expr) +{ + return __get_expression_value(expr, 0); +} + +long long const_expression_value(struct expression *expr) +{ + return __get_expression_value(expr, 1); +} diff --git a/expression.c b/expression.c index a40ab2bc..d36c3d2f 100644 --- a/expression.c +++ b/expression.c @@ -117,6 +117,7 @@ static struct token *parse_type(struct token *token, struct expression **tree) { struct symbol *sym; *tree = alloc_expression(token->pos, EXPR_TYPE); + (*tree)->flags = Int_const_expr; /* sic */ token = typename(token, &sym); if (sym->ident) sparse_error(token->pos, @@ -131,6 +132,7 @@ static struct token *builtin_types_compatible_p_expr(struct token *token, { struct expression *expr = alloc_expression( token->pos, EXPR_COMPARE); + expr->flags = Int_const_expr; expr->op = SPECIAL_EQUAL; token = token->next; if (!match_op(token, '(')) @@ -152,6 +154,72 @@ static struct token *builtin_types_compatible_p_expr(struct token *token, return token; } +static struct token *builtin_offsetof_expr(struct token *token, + struct expression **tree) +{ + struct expression *expr = NULL; + struct expression **p = &expr; + struct symbol *sym; + int op = '.'; + + token = token->next; + if (!match_op(token, '(')) + return expect(token, '(', "after __builtin_offset"); + + token = token->next; + token = typename(token, &sym); + if (sym->ident) + sparse_error(token->pos, + "type expression should not include identifier " + "\"%s\"", sym->ident->name); + + if (!match_op(token, ',')) + return expect(token, ',', "in __builtin_offset"); + + while (1) { + struct expression *e; + switch (op) { + case ')': + expr->in = sym; + *tree = expr; + default: + return expect(token, ')', "at end of __builtin_offset"); + case SPECIAL_DEREFERENCE: + e = alloc_expression(token->pos, EXPR_OFFSETOF); + e->flags = Int_const_expr; + e->op = '['; + *p = e; + p = &e->down; + /* fall through */ + case '.': + token = token->next; + e = alloc_expression(token->pos, EXPR_OFFSETOF); + e->flags = Int_const_expr; + e->op = '.'; + if (token_type(token) != TOKEN_IDENT) { + sparse_error(token->pos, "Expected member name"); + return token; + } + e->ident = token->ident; + token = token->next; + break; + case '[': + token = token->next; + e = alloc_expression(token->pos, EXPR_OFFSETOF); + e->flags = Int_const_expr; + e->op = '['; + token = parse_expression(token, &e->index); + token = expect(token, ']', + "at end of array dereference"); + if (!e->index) + return token; + } + *p = e; + p = &e->down; + op = token_type(token) == TOKEN_SPECIAL ? token->special : 0; + } +} + static struct token *string_expression(struct token *token, struct expression *expr) { struct string *string = token->string; @@ -290,6 +358,7 @@ got_it: "likely to produce unsigned long (and a warning) here", show_token(token)); expr->type = EXPR_VALUE; + expr->flags = Int_const_expr; expr->ctype = ctype_integer(modifiers); expr->value = value; return; @@ -314,6 +383,7 @@ Float: else goto Enoint; + expr->flags = Float_literal; expr->type = EXPR_FVALUE; return; @@ -328,6 +398,7 @@ struct token *primary_expression(struct token *token, struct expression **tree) switch (token_type(token)) { case TOKEN_CHAR: expr = alloc_expression(token->pos, EXPR_VALUE); + expr->flags = Int_const_expr; expr->ctype = &int_ctype; expr->value = (unsigned char) token->character; token = token->next; @@ -335,12 +406,13 @@ struct token *primary_expression(struct token *token, struct expression **tree) case TOKEN_NUMBER: expr = alloc_expression(token->pos, EXPR_VALUE); - get_number_value(expr, token); + get_number_value(expr, token); /* will see if it's an integer */ token = token->next; break; case TOKEN_ZERO_IDENT: { expr = alloc_expression(token->pos, EXPR_SYMBOL); + expr->flags = Int_const_expr; expr->ctype = &int_ctype; expr->symbol = &zero_int; expr->symbol_name = token->ident; @@ -359,11 +431,16 @@ struct token *primary_expression(struct token *token, struct expression **tree) token = builtin_types_compatible_p_expr(token, &expr); break; } + if (token->ident == &__builtin_offsetof_ident) { + token = builtin_offsetof_expr(token, &expr); + break; + } } else if (sym->enum_member) { expr = alloc_expression(token->pos, EXPR_VALUE); *expr = *sym->initializer; /* we want the right position reported, thus the copy */ expr->pos = token->pos; + expr->flags = Int_const_expr; token = next; break; } @@ -398,10 +475,13 @@ struct token *primary_expression(struct token *token, struct expression **tree) expr = alloc_expression(token->pos, EXPR_PREOP); expr->op = '('; token = parens_expression(token, &expr->unop, "in expression"); + if (expr->unop) + expr->flags = expr->unop->flags; break; } if (token->special == '[' && lookup_type(token->next)) { expr = alloc_expression(token->pos, EXPR_TYPE); + expr->flags = Int_const_expr; /* sic */ token = typename(token->next, &expr->symbol); token = expect(token, ']', "in type expression"); break; @@ -516,6 +596,7 @@ static struct token *type_info_expression(struct token *token, struct expression *expr = alloc_expression(token->pos, type); *tree = expr; + expr->flags = Int_const_expr; /* XXX: VLA support will need that changed */ token = token->next; if (!match_op(token, '(') || !lookup_type(token->next)) return unary_expression(token, &expr->cast_expression); @@ -565,7 +646,7 @@ static struct token *unary_expression(struct token *token, struct expression **t if (token_type(token) == TOKEN_SPECIAL) { if (match_oplist(token->special, SPECIAL_INCREMENT, SPECIAL_DECREMENT, - '&', '*', '+', '-', '~', '!', 0)) { + '&', '*', 0)) { struct expression *unop; struct expression *unary; struct token *next; @@ -581,7 +662,24 @@ static struct token *unary_expression(struct token *token, struct expression **t *tree = unary; return next; } + /* possibly constant ones */ + if (match_oplist(token->special, '+', '-', '~', '!', 0)) { + struct expression *unop; + struct expression *unary; + struct token *next; + next = cast_expression(token->next, &unop); + if (!unop) { + sparse_error(token->pos, "Syntax error in unary expression"); + return next; + } + unary = alloc_expression(token->pos, EXPR_PREOP); + unary->op = token->special; + unary->unop = unop; + unary->flags = unop->flags & Int_const_expr; + *tree = unary; + return next; + } /* Gcc extension: &&label gives the address of a label */ if (match_op(token, SPECIAL_LOGICAL_AND) && token_type(token->next) == TOKEN_IDENT) { @@ -615,6 +713,7 @@ static struct token *cast_expression(struct token *token, struct expression **tr struct token *next = token->next; if (lookup_type(next)) { struct expression *cast = alloc_expression(next->pos, EXPR_CAST); + struct expression *v; struct symbol *sym; token = typename(next, &sym); @@ -625,7 +724,14 @@ static struct token *cast_expression(struct token *token, struct expression **tr return postfix_expression(token, tree, cast); } *tree = cast; - token = cast_expression(token, &cast->cast_expression); + token = cast_expression(token, &v); + if (!v) + return token; + cast->cast_expression = v; + if (v->flags & Int_const_expr) + cast->flags = Int_const_expr; + else if (v->flags & Float_literal) /* and _not_ int */ + cast->flags = Int_const_expr | Float_literal; return token; } } @@ -645,9 +751,9 @@ static struct token *cast_expression(struct token *token, struct expression **tr * than create a data structure for it. */ -#define LR_BINOP_EXPRESSION(token, tree, type, inner, compare) \ +#define __LR_BINOP_EXPRESSION(__token, tree, type, inner, compare, is_const) \ struct expression *left = NULL; \ - struct token * next = inner(token, &left); \ + struct token * next = inner(__token, &left); \ \ if (left) { \ while (token_type(next) == TOKEN_SPECIAL) { \ @@ -662,6 +768,9 @@ static struct token *cast_expression(struct token *token, struct expression **tr sparse_error(next->pos, "No right hand side of '%s'-expression", show_special(op)); \ break; \ } \ + if (is_const) \ + top->flags = left->flags & right->flags \ + & Int_const_expr; \ top->op = op; \ top->left = left; \ top->right = right; \ @@ -672,6 +781,12 @@ out: \ *tree = left; \ return next; \ +#define LR_BINOP_EXPRESSION(token, tree, type, inner, compare) \ + __LR_BINOP_EXPRESSION((token), (tree), (type), (inner), (compare), 1) + +#define LR_BINOP_EXPRESSION_NONCONST(token, tree, type, inner, compare) \ + __LR_BINOP_EXPRESSION((token), (tree), (type), (inner), (compare), 0) + static struct token *multiplicative_expression(struct token *token, struct expression **tree) { @@ -765,6 +880,14 @@ struct token *conditional_expression(struct token *token, struct expression **tr token = parse_expression(token->next, &expr->cond_true); token = expect(token, ':', "in conditional expression"); token = conditional_expression(token, &expr->cond_false); + if (expr->left && expr->cond_true) { + int is_const = expr->left->flags & + expr->cond_false->flags & + Int_const_expr; + if (expr->cond_true) + is_const &= expr->cond_true->flags; + expr->flags = is_const; + } } return token; } @@ -795,7 +918,7 @@ struct token *assignment_expression(struct token *token, struct expression **tre static struct token *comma_expression(struct token *token, struct expression **tree) { - LR_BINOP_EXPRESSION( + LR_BINOP_EXPRESSION_NONCONST( token, tree, EXPR_COMMA, assignment_expression, (op == ',') ); diff --git a/expression.h b/expression.h index 1bf02c4a..a9131532 100644 --- a/expression.h +++ b/expression.h @@ -44,10 +44,17 @@ enum expression_type { EXPR_POS, // position in initializer EXPR_FVALUE, EXPR_SLICE, + EXPR_OFFSETOF, }; +enum { + Int_const_expr = 1, + Float_literal = 2, +}; /* for expr->flags */ + struct expression { - enum expression_type type; + enum expression_type type:8; + unsigned flags:8; int op; struct position pos; struct symbol *ctype; @@ -127,11 +134,21 @@ struct expression { unsigned int init_offset, init_nr; struct expression *init_expr; }; + // EXPR_OFFSETOF + struct { + struct symbol *in; + struct expression *down; + union { + struct ident *ident; + struct expression *index; + }; + }; }; }; /* Constant expression values */ long long get_expression_value(struct expression *); +long long const_expression_value(struct expression *); /* Expression parsing */ struct token *parse_expression(struct token *token, struct expression **tree); diff --git a/ident-list.h b/ident-list.h index 0f654bff..b183eac0 100644 --- a/ident-list.h +++ b/ident-list.h @@ -29,6 +29,7 @@ IDENT(asm); IDENT_RESERVED(__asm); IDENT_RESERVED(__asm__); IDENT(alignof); IDENT_RESERVED(__alignof); IDENT_RESERVED(__alignof__); IDENT_RESERVED(__sizeof_ptr__); IDENT_RESERVED(__builtin_types_compatible_p); +IDENT_RESERVED(__builtin_offsetof); /* Attribute names */ IDENT(packed); IDENT(__packed__); @@ -237,7 +237,23 @@ static struct expression * copy_expression(struct expression *expr) expr->init_expr = val; break; } - + case EXPR_OFFSETOF: { + struct expression *val = copy_expression(expr->down); + if (expr->op == '.') { + if (expr->down != val) { + expr = dup_expression(expr); + expr->down = val; + } + } else { + struct expression *idx = copy_expression(expr->index); + if (expr->down != val || expr->index != idx) { + expr = dup_expression(expr); + expr->down = val; + expr->index = idx; + } + } + break; + } default: warning(expr->pos, "trying to copy expression type %d", expr->type); } @@ -609,7 +609,6 @@ void create_builtin_stream(void) add_pre_buffer("#define __builtin_va_arg_incr(x) ((x) + 1)\n"); add_pre_buffer("#define __builtin_va_copy(dest, src) ({ dest = src; (void)0; })\n"); add_pre_buffer("#define __builtin_va_end(arg)\n"); - add_pre_buffer("#define __builtin_offsetof(type, name) ((__SIZE_TYPE__)&((type *)(0ul))->name)\n"); /* FIXME! We need to do these as special magic macros at expansion time! */ add_pre_buffer("#define __BASE_FILE__ \"base_file.c\"\n"); @@ -802,7 +802,7 @@ static struct token *attribute_aligned(struct token *token, struct symbol *attr, if (match_op(token, '(')) { token = parens_expression(token, &expr, "in attribute"); if (expr) - alignment = get_expression_value(expr); + alignment = const_expression_value(expr); } ctype->alignment = alignment; return token; @@ -820,7 +820,7 @@ static struct token *attribute_address_space(struct token *token, struct symbol token = expect(token, '(', "after address_space attribute"); token = conditional_expression(token, &expr); if (expr) - ctype->as = get_expression_value(expr); + ctype->as = const_expression_value(expr); token = expect(token, ')', "after address_space attribute"); return token; } @@ -1258,7 +1258,7 @@ static struct token *handle_bitfield(struct token *token, struct symbol *decl) bitfield = alloc_indirect_symbol(token->pos, ctype, SYM_BITFIELD); token = conditional_expression(token->next, &expr); - width = get_expression_value(expr); + width = const_expression_value(expr); bitfield->bit_size = width; if (width < 0 || width > INT_MAX) { @@ -1844,10 +1844,10 @@ static struct expression *index_expression(struct expression *from, struct expre int idx_from, idx_to; struct expression *expr = alloc_expression(from->pos, EXPR_INDEX); - idx_from = get_expression_value(from); + idx_from = const_expression_value(from); idx_to = idx_from; if (to) { - idx_to = get_expression_value(to); + idx_to = const_expression_value(to); if (idx_to < idx_from || idx_from < 0) warning(from->pos, "nonsense array initializer index range"); } diff --git a/show-parse.c b/show-parse.c index 0bef01cb..07ee7635 100644 --- a/show-parse.c +++ b/show-parse.c @@ -1049,6 +1049,7 @@ int show_expression(struct expression *expr) case EXPR_SIZEOF: case EXPR_PTRSIZEOF: case EXPR_ALIGNOF: + case EXPR_OFFSETOF: warning(expr->pos, "invalid expression after evaluation"); return 0; case EXPR_CAST: |
