X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=a859dc4601b3ddc2bed45dec81fef3e51be2097e;hb=152becd590dc065f730deea680aa32b7d1032286;hp=e5fb27f5d19e6bacec15d6b187c577d45803937f;hpb=1d924b2425abebc57596a4f9133583de03dc273b;p=cparser diff --git a/parser.c b/parser.c index e5fb27f..a859dc4 100644 --- a/parser.c +++ b/parser.c @@ -34,6 +34,7 @@ #include "type_hash.h" #include "ast_t.h" #include "lang_features.h" +#include "walk_statements.h" #include "warning.h" #include "adt/bitfiddle.h" #include "adt/error.h" @@ -105,15 +106,21 @@ typedef struct parse_initializer_env_t { typedef declaration_t* (*parsed_declaration_func) (declaration_t *declaration, bool is_definition); +/** The current token. */ static token_t token; +/** The lookahead ring-buffer. */ static token_t lookahead_buffer[MAX_LOOKAHEAD]; +/** Position of the next token in the lookahead buffer. */ static int lookahead_bufpos; static stack_entry_t *environment_stack = NULL; static stack_entry_t *label_stack = NULL; static stack_entry_t *local_label_stack = NULL; -static scope_t *global_scope = NULL; +/** The global file scope. */ +static scope_t *file_scope = NULL; +/** The current scope. */ static scope_t *scope = NULL; static declaration_t *last_declaration = NULL; +/** Point to the current function declaration if inside a function. */ static declaration_t *current_function = NULL; static declaration_t *current_init_decl = NULL; static switch_statement_t *current_switch = NULL; @@ -124,16 +131,20 @@ static goto_statement_t *goto_first = NULL; static goto_statement_t *goto_last = NULL; static label_statement_t *label_first = NULL; static label_statement_t *label_last = NULL; +/** current translation unit. */ static translation_unit_t *unit = NULL; +/** true if we are in a type property context (evaluation only for type. */ +static bool in_type_prop = false; +/** true in we are in a __extension__ context. */ +static bool in_gcc_extension = false; static struct obstack temp_obst; + #define PUSH_PARENT(stmt) \ statement_t *const prev_parent = current_parent; \ - current_parent = (stmt); + ((void)(current_parent = (stmt))) #define POP_PARENT ((void)(current_parent = prev_parent)) -static source_position_t null_position = { NULL, 0 }; - /** special symbol used for anonymous entities. */ static const symbol_t *sym_anonymous = NULL; @@ -163,12 +174,15 @@ static unsigned char token_anchor_set[T_LAST_TOKEN]; /** The current source position. */ #define HERE (&token.source_position) +/** true if we are in GCC mode. */ +#define GNU_MODE ((c_mode & _GNUC) || in_gcc_extension) + static type_t *type_valist; static statement_t *parse_compound_statement(bool inside_expression_statement); static statement_t *parse_statement(void); -static expression_t *parse_sub_expression(unsigned precedence); +static expression_t *parse_sub_expression(precedence_t); static expression_t *parse_expression(void); static type_t *parse_typename(void); @@ -341,8 +355,9 @@ static statement_t *allocate_statement_zero(statement_kind_t kind) size_t size = get_statement_struct_size(kind); statement_t *res = allocate_ast_zero(size); - res->base.kind = kind; - res->base.parent = current_parent; + res->base.kind = kind; + res->base.parent = current_parent; + res->base.source_position = token.source_position; return res; } @@ -375,9 +390,7 @@ static expression_t *create_invalid_expression(void) */ static statement_t *create_invalid_statement(void) { - statement_t *statement = allocate_statement_zero(STATEMENT_INVALID); - statement->base.source_position = token.source_position; - return statement; + return allocate_statement_zero(STATEMENT_INVALID); } /** @@ -385,9 +398,7 @@ static statement_t *create_invalid_statement(void) */ static statement_t *create_empty_statement(void) { - statement_t *statement = allocate_statement_zero(STATEMENT_EMPTY); - statement->base.source_position = token.source_position; - return statement; + return allocate_statement_zero(STATEMENT_EMPTY); } /** @@ -423,16 +434,14 @@ static size_t get_type_struct_size(type_kind_t kind) * fields with zero. * * @param kind type kind to allocate - * @param source_position the source position of the type definition */ -static type_t *allocate_type_zero(type_kind_t kind, const source_position_t *source_position) +static type_t *allocate_type_zero(type_kind_t kind) { size_t size = get_type_struct_size(kind); type_t *res = obstack_alloc(type_obst, size); memset(res, 0, size); + res->base.kind = kind; - res->base.kind = kind; - res->base.source_position = *source_position; return res; } @@ -625,13 +634,9 @@ check_stop: */ static void eat_until_anchor(void) { - if (token.type == T_EOF) - return; while (token_anchor_set[token.type] == 0) { if (token.type == '(' || token.type == '{' || token.type == '[') eat_until_matching_token(token.type); - if (token.type == T_EOF) - break; next_token(); } } @@ -643,16 +648,6 @@ static void eat_block(void) next_token(); } -/** - * eat all token until a ';' is reached or a stop token is found. - */ -static void eat_statement(void) -{ - eat_until_matching_token(';'); - if (token.type == ';') - next_token(); -} - #define eat(token_type) do { assert(token.type == token_type); next_token(); } while (0) /** @@ -711,16 +706,25 @@ static void type_error_incompatible(const char *msg, next_token(); \ } while (0) -static void set_scope(scope_t *new_scope) +static void scope_push(scope_t *new_scope) { if (scope != NULL) { scope->last_declaration = last_declaration; + new_scope->depth = scope->depth + 1; } - scope = new_scope; + new_scope->parent = scope; + scope = new_scope; last_declaration = new_scope->last_declaration; } +static void scope_pop(void) +{ + scope->last_declaration = last_declaration; + scope = scope->parent; + last_declaration = scope->last_declaration; +} + /** * Search a symbol in a given namespace and returns its declaration or * NULL if this symbol was not found. @@ -747,28 +751,20 @@ static void stack_push(stack_entry_t **stack_ptr, declaration_t *declaration) namespace_t namespc = (namespace_t) declaration->namespc; /* replace/add declaration into declaration list of the symbol */ - declaration_t *iter = symbol->declaration; - if (iter == NULL) { - symbol->declaration = declaration; - } else { - declaration_t *iter_last = NULL; - for( ; iter != NULL; iter_last = iter, iter = iter->symbol_next) { - /* replace an entry? */ - if (iter->namespc == namespc) { - if (iter_last == NULL) { - symbol->declaration = declaration; - } else { - iter_last->symbol_next = declaration; - } - declaration->symbol_next = iter->symbol_next; - break; - } - } - if (iter == NULL) { - assert(iter_last->symbol_next == NULL); - iter_last->symbol_next = declaration; + declaration_t **anchor; + declaration_t *iter; + for (anchor = &symbol->declaration;; anchor = &iter->symbol_next) { + iter = *anchor; + if (iter == NULL) + break; + + /* replace an entry? */ + if (iter->namespc == namespc) { + declaration->symbol_next = iter->symbol_next; + break; } } + *anchor = declaration; /* remember old declaration */ stack_entry_t entry; @@ -833,29 +829,23 @@ static void stack_pop_to(stack_entry_t **stack_ptr, size_t new_top) namespace_t namespc = (namespace_t)entry->namespc; /* replace/remove declaration */ - declaration_t *declaration = symbol->declaration; - assert(declaration != NULL); - if (declaration->namespc == namespc) { - if (old_declaration == NULL) { - symbol->declaration = declaration->symbol_next; - } else { - symbol->declaration = old_declaration; - } - } else { - declaration_t *iter_last = declaration; - declaration_t *iter = declaration->symbol_next; - for( ; iter != NULL; iter_last = iter, iter = iter->symbol_next) { - /* replace an entry? */ - if (iter->namespc == namespc) { - assert(iter_last != NULL); - iter_last->symbol_next = old_declaration; - if (old_declaration != NULL) { - old_declaration->symbol_next = iter->symbol_next; - } - break; - } - } + declaration_t **anchor; + declaration_t *iter; + for (anchor = &symbol->declaration;; anchor = &iter->symbol_next) { + iter = *anchor; assert(iter != NULL); + /* replace an entry? */ + if (iter->namespc == namespc) + break; + } + + /* Not all declarations adhere scopes (e.g. jump labels), so this + * correction is necessary */ + if (old_declaration != NULL) { + old_declaration->symbol_next = iter->symbol_next; + *anchor = old_declaration; + } else { + *anchor = iter->symbol_next; } } @@ -1012,36 +1002,42 @@ static void report_assign_error(assign_error_t error, type_t *orig_type_left, return; case ASSIGN_ERROR_POINTER_QUALIFIER_MISSING: { - type_t *points_to_left - = skip_typeref(type_left->pointer.points_to); - type_t *points_to_right - = skip_typeref(type_right->pointer.points_to); - - /* the left type has all qualifiers from the right type */ - unsigned missing_qualifiers - = points_to_right->base.qualifiers & ~points_to_left->base.qualifiers; - warningf(source_position, - "destination type '%T' in %s from type '%T' lacks qualifiers '%Q' in pointer target type", - orig_type_left, context, orig_type_right, missing_qualifiers); + if (warning.other) { + type_t *points_to_left = skip_typeref(type_left->pointer.points_to); + type_t *points_to_right = skip_typeref(type_right->pointer.points_to); + + /* the left type has all qualifiers from the right type */ + unsigned missing_qualifiers + = points_to_right->base.qualifiers & ~points_to_left->base.qualifiers; + warningf(source_position, + "destination type '%T' in %s from type '%T' lacks qualifiers '%Q' in pointer target type", + orig_type_left, context, orig_type_right, missing_qualifiers); + } return; } case ASSIGN_WARNING_POINTER_INCOMPATIBLE: - warningf(source_position, - "destination type '%T' in %s is incompatible with '%E' of type '%T'", - orig_type_left, context, right, orig_type_right); + if (warning.other) { + warningf(source_position, + "destination type '%T' in %s is incompatible with '%E' of type '%T'", + orig_type_left, context, right, orig_type_right); + } return; case ASSIGN_WARNING_POINTER_FROM_INT: - warningf(source_position, - "%s makes pointer '%T' from integer '%T' without a cast", - context, orig_type_left, orig_type_right); + if (warning.other) { + warningf(source_position, + "%s makes pointer '%T' from integer '%T' without a cast", + context, orig_type_left, orig_type_right); + } return; case ASSIGN_WARNING_INT_FROM_POINTER: - warningf(source_position, - "%s makes integer '%T' from pointer '%T' without a cast", - context, orig_type_left, orig_type_right); + if (warning.other) { + warningf(source_position, + "%s makes integer '%T' from pointer '%T' without a cast", + context, orig_type_left, orig_type_right); + } return; default: @@ -1113,8 +1109,7 @@ static assign_error_t semantic_assign(type_t *orig_type_left, static expression_t *parse_constant_expression(void) { - /* start parsing at precedence 7 (conditional expression) */ - expression_t *result = parse_sub_expression(7); + expression_t *result = parse_sub_expression(PREC_CONDITIONAL); if (!is_constant_expression(result)) { errorf(&result->base.source_position, @@ -1126,8 +1121,7 @@ static expression_t *parse_constant_expression(void) static expression_t *parse_assignment_expression(void) { - /* start parsing at precedence 2 (assignment expression) */ - return parse_sub_expression(2); + return parse_sub_expression(PREC_ASSIGNMENT); } static type_t *make_global_typedef(const char *name, type_t *type) @@ -1145,7 +1139,7 @@ static type_t *make_global_typedef(const char *name, type_t *type) record_declaration(declaration, false); - type_t *typedef_type = allocate_type_zero(TYPE_TYPEDEF, &builtin_source_position); + type_t *typedef_type = allocate_type_zero(TYPE_TYPEDEF); typedef_type->typedeft.declaration = declaration; return typedef_type; @@ -1430,7 +1424,8 @@ static void parse_gnu_attribute_mode_arg(gnu_attribute_t *attribute) } else if (strcmp_underscore("DI", symbol_str) == 0) { attribute->u.akind = ATOMIC_TYPE_LONGLONG; } else { - warningf(HERE, "ignoring unknown mode '%s'", symbol_str); + if (warning.other) + warningf(HERE, "ignoring unknown mode '%s'", symbol_str); attribute->invalid = true; } next_token(); @@ -1669,7 +1664,6 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) } switch(kind) { - case GNU_AK_CONST: case GNU_AK_VOLATILE: case GNU_AK_NAKED: case GNU_AK_MALLOC: @@ -1709,6 +1703,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) case GNU_AK_UNUSED: modifiers |= DM_UNUSED; goto no_arg; case GNU_AK_USED: modifiers |= DM_USED; goto no_arg; case GNU_AK_PURE: modifiers |= DM_PURE; goto no_arg; + case GNU_AK_CONST: modifiers |= DM_CONST; goto no_arg; case GNU_AK_ALWAYS_INLINE: modifiers |= DM_FORCEINLINE; goto no_arg; case GNU_AK_DLLIMPORT: modifiers |= DM_DLLIMPORT; goto no_arg; case GNU_AK_DLLEXPORT: modifiers |= DM_DLLEXPORT; goto no_arg; @@ -1868,7 +1863,8 @@ static decl_modifiers_t parse_attributes(gnu_attribute_t **attributes) case T___thiscall: /* TODO record modifier */ - warningf(HERE, "Ignoring declaration modifier %K", &token); + if (warning.other) + warningf(HERE, "Ignoring declaration modifier %K", &token); break; end_error: @@ -1879,6 +1875,215 @@ end_error: } } +static void mark_decls_read(expression_t *expr, declaration_t *lhs_decl); + +static declaration_t *determine_lhs_decl(expression_t *const expr, declaration_t *lhs_decl) +{ + switch (expr->kind) { + case EXPR_REFERENCE: { + declaration_t *const decl = expr->reference.declaration; + return decl; + } + + case EXPR_ARRAY_ACCESS: { + expression_t *const ref = expr->array_access.array_ref; + declaration_t * decl = NULL; + if (is_type_array(skip_typeref(revert_automatic_type_conversion(ref)))) { + decl = determine_lhs_decl(ref, lhs_decl); + lhs_decl = decl; + } else { + mark_decls_read(expr->select.compound, lhs_decl); + } + mark_decls_read(expr->array_access.index, lhs_decl); + return decl; + } + + case EXPR_SELECT: { + if (is_type_compound(skip_typeref(expr->base.type))) { + return determine_lhs_decl(expr->select.compound, lhs_decl); + } else { + mark_decls_read(expr->select.compound, lhs_decl); + return NULL; + } + } + + case EXPR_UNARY_DEREFERENCE: { + expression_t *const val = expr->unary.value; + if (val->kind == EXPR_UNARY_TAKE_ADDRESS) { + /* *&x is a NOP */ + return determine_lhs_decl(val->unary.value, lhs_decl); + } else { + mark_decls_read(val, NULL); + return NULL; + } + } + + default: + mark_decls_read(expr, NULL); + return NULL; + } +} + +#define DECL_ANY ((declaration_t*)-1) + +/** + * Mark declarations, which are read. This is used to deted variables, which + * are never read. + * Example: + * x = x + 1; + * x is not marked as "read", because it is only read to calculate its own new + * value. + * + * x += y; y += x; + * x and y are not detected as "not read", because multiple variables are + * involved. + */ +static void mark_decls_read(expression_t *const expr, declaration_t *lhs_decl) +{ + switch (expr->kind) { + case EXPR_REFERENCE: { + declaration_t *const decl = expr->reference.declaration; + if (lhs_decl != decl && lhs_decl != DECL_ANY) + decl->read = true; + return; + } + + case EXPR_CALL: + // TODO respect pure/const + mark_decls_read(expr->call.function, NULL); + for (call_argument_t *arg = expr->call.arguments; arg != NULL; arg = arg->next) { + mark_decls_read(arg->expression, NULL); + } + return; + + case EXPR_CONDITIONAL: + // TODO lhs_decl should depend on whether true/false have an effect + mark_decls_read(expr->conditional.condition, NULL); + if (expr->conditional.true_expression != NULL) + mark_decls_read(expr->conditional.true_expression, lhs_decl); + mark_decls_read(expr->conditional.false_expression, lhs_decl); + return; + + case EXPR_SELECT: + if (lhs_decl == DECL_ANY && !is_type_compound(skip_typeref(expr->base.type))) + lhs_decl = NULL; + mark_decls_read(expr->select.compound, lhs_decl); + return; + + case EXPR_ARRAY_ACCESS: { + expression_t *const ref = expr->array_access.array_ref; + mark_decls_read(ref, lhs_decl); + lhs_decl = determine_lhs_decl(ref, lhs_decl); + mark_decls_read(expr->array_access.index, lhs_decl); + return; + } + + case EXPR_VA_ARG: + mark_decls_read(expr->va_arge.ap, lhs_decl); + return; + + case EXPR_UNARY_CAST: + /* Special case: Use void cast to mark a variable as "read" */ + if (is_type_atomic(skip_typeref(expr->base.type), ATOMIC_TYPE_VOID)) + lhs_decl = NULL; + goto unary; + + case EXPR_UNARY_DEREFERENCE: + if (lhs_decl == DECL_ANY) + lhs_decl = NULL; + goto unary; + + case EXPR_UNARY_NEGATE: + case EXPR_UNARY_PLUS: + case EXPR_UNARY_BITWISE_NEGATE: + case EXPR_UNARY_NOT: + case EXPR_UNARY_TAKE_ADDRESS: + case EXPR_UNARY_POSTFIX_INCREMENT: + case EXPR_UNARY_POSTFIX_DECREMENT: + case EXPR_UNARY_PREFIX_INCREMENT: + case EXPR_UNARY_PREFIX_DECREMENT: + case EXPR_UNARY_CAST_IMPLICIT: + case EXPR_UNARY_ASSUME: +unary: + mark_decls_read(expr->unary.value, lhs_decl); + return; + + case EXPR_BINARY_ADD: + case EXPR_BINARY_SUB: + case EXPR_BINARY_MUL: + case EXPR_BINARY_DIV: + case EXPR_BINARY_MOD: + case EXPR_BINARY_EQUAL: + case EXPR_BINARY_NOTEQUAL: + case EXPR_BINARY_LESS: + case EXPR_BINARY_LESSEQUAL: + case EXPR_BINARY_GREATER: + case EXPR_BINARY_GREATEREQUAL: + case EXPR_BINARY_BITWISE_AND: + case EXPR_BINARY_BITWISE_OR: + case EXPR_BINARY_BITWISE_XOR: + case EXPR_BINARY_LOGICAL_AND: + case EXPR_BINARY_LOGICAL_OR: + case EXPR_BINARY_SHIFTLEFT: + case EXPR_BINARY_SHIFTRIGHT: + case EXPR_BINARY_COMMA: + case EXPR_BINARY_ISGREATER: + case EXPR_BINARY_ISGREATEREQUAL: + case EXPR_BINARY_ISLESS: + case EXPR_BINARY_ISLESSEQUAL: + case EXPR_BINARY_ISLESSGREATER: + case EXPR_BINARY_ISUNORDERED: + mark_decls_read(expr->binary.left, lhs_decl); + mark_decls_read(expr->binary.right, lhs_decl); + return; + + case EXPR_BINARY_ASSIGN: + case EXPR_BINARY_MUL_ASSIGN: + case EXPR_BINARY_DIV_ASSIGN: + case EXPR_BINARY_MOD_ASSIGN: + case EXPR_BINARY_ADD_ASSIGN: + case EXPR_BINARY_SUB_ASSIGN: + case EXPR_BINARY_SHIFTLEFT_ASSIGN: + case EXPR_BINARY_SHIFTRIGHT_ASSIGN: + case EXPR_BINARY_BITWISE_AND_ASSIGN: + case EXPR_BINARY_BITWISE_XOR_ASSIGN: + case EXPR_BINARY_BITWISE_OR_ASSIGN: { + if (lhs_decl == DECL_ANY) + lhs_decl = NULL; + lhs_decl = determine_lhs_decl(expr->binary.left, lhs_decl); + mark_decls_read(expr->binary.right, lhs_decl); + return; + } + + case EXPR_VA_START: + determine_lhs_decl(expr->va_starte.ap, lhs_decl); + return; + + case EXPR_UNKNOWN: + case EXPR_INVALID: + case EXPR_CONST: + case EXPR_CHARACTER_CONSTANT: + case EXPR_WIDE_CHARACTER_CONSTANT: + case EXPR_STRING_LITERAL: + case EXPR_WIDE_STRING_LITERAL: + case EXPR_COMPOUND_LITERAL: // TODO init? + case EXPR_SIZEOF: + case EXPR_CLASSIFY_TYPE: + case EXPR_ALIGNOF: + case EXPR_FUNCNAME: + case EXPR_BUILTIN_SYMBOL: + case EXPR_BUILTIN_CONSTANT_P: + case EXPR_BUILTIN_PREFETCH: + case EXPR_OFFSETOF: + case EXPR_STATEMENT: // TODO + case EXPR_LABEL_ADDRESS: + case EXPR_BINARY_BUILTIN_EXPECT: + return; + } + + panic("unhandled expression"); +} + static designator_t *parse_designation(void) { designator_t *result = NULL; @@ -1998,6 +2203,11 @@ static initializer_t *initializer_from_expression(type_t *orig_type, &expression->base.source_position); initializer_t *const result = allocate_initializer_zero(INITIALIZER_VALUE); +#if 0 + if (type->kind == TYPE_BITFIELD) { + type = type->bitfield.base_type; + } +#endif result->value.value = create_implicit_cast(expression, type); return result; @@ -2023,7 +2233,8 @@ static initializer_t *parse_scalar_initializer(type_t *type, /* there might be extra {} hierarchies */ int braces = 0; if (token.type == '{') { - warningf(HERE, "extra curly braces around scalar initializer"); + if (warning.other) + warningf(HERE, "extra curly braces around scalar initializer"); do { ++braces; next_token(); @@ -2031,6 +2242,7 @@ static initializer_t *parse_scalar_initializer(type_t *type, } expression_t *expression = parse_assignment_expression(); + mark_decls_read(expression, NULL); if (must_be_constant && !is_initializer_constant(expression)) { errorf(&expression->base.source_position, "Initialisation expression '%E' is not constant\n", @@ -2053,7 +2265,7 @@ static initializer_t *parse_scalar_initializer(type_t *type, next_token(); } if (token.type != '}') { - if (!additional_warning_displayed) { + if (!additional_warning_displayed && warning.other) { warningf(HERE, "additional elements in scalar initializer"); additional_warning_displayed = true; } @@ -2218,34 +2430,37 @@ static bool walk_designator(type_path_t *path, const designator_t *designator, "'.%Y' designator used for non-compound type '%T'", symbol, orig_type); } - goto failed; - } - declaration_t *declaration = type->compound.declaration; - declaration_t *iter = declaration->scope.declarations; - for( ; iter != NULL; iter = iter->next) { - if (iter->symbol == symbol) { - break; + top->type = type_error_type; + top->v.compound_entry = NULL; + orig_type = type_error_type; + } else { + declaration_t *declaration = type->compound.declaration; + declaration_t *iter = declaration->scope.declarations; + for( ; iter != NULL; iter = iter->next) { + if (iter->symbol == symbol) { + break; + } } - } - if (iter == NULL) { - errorf(&designator->source_position, - "'%T' has no member named '%Y'", orig_type, symbol); - goto failed; - } - if (used_in_offsetof) { - type_t *real_type = skip_typeref(iter->type); - if (real_type->kind == TYPE_BITFIELD) { + if (iter == NULL) { errorf(&designator->source_position, - "offsetof designator '%Y' may not specify bitfield", - symbol); + "'%T' has no member named '%Y'", orig_type, symbol); goto failed; } - } + if (used_in_offsetof) { + type_t *real_type = skip_typeref(iter->type); + if (real_type->kind == TYPE_BITFIELD) { + errorf(&designator->source_position, + "offsetof designator '%Y' may not specify bitfield", + symbol); + goto failed; + } + } - top->type = orig_type; - top->v.compound_entry = iter; - orig_type = iter->type; + top->type = orig_type; + top->v.compound_entry = iter; + orig_type = iter->type; + } } else { expression_t *array_index = designator->array_index; assert(designator->array_index != NULL); @@ -2258,24 +2473,18 @@ static bool walk_designator(type_path_t *path, const designator_t *designator, } goto failed; } - if (!is_type_valid(array_index->base.type)) { - goto failed; - } long index = fold_constant(array_index); if (!used_in_offsetof) { if (index < 0) { errorf(&designator->source_position, "array index [%E] must be positive", array_index); - goto failed; - } - if (type->array.size_constant == true) { + } else if (type->array.size_constant) { long array_size = type->array.size; if (index >= array_size) { errorf(&designator->source_position, "designator [%E] (%d) exceeds array size %d", array_index, index, array_size); - goto failed; } } } @@ -2313,7 +2522,7 @@ static void advance_current_object(type_path_t *path, size_t top_path_level) path->top_type = entry->type; return; } - } else { + } else if (is_type_array(type)) { assert(is_type_array(type)); top->v.index++; @@ -2321,6 +2530,9 @@ static void advance_current_object(type_path_t *path, size_t top_path_level) if (!type->array.size_constant || top->v.index < type->array.size) { return; } + } else { + assert(!is_type_valid(type)); + return; } /* we're past the last member of the current sub-aggregate, try if we @@ -2392,13 +2604,6 @@ static initializer_t *parse_sub_initializer(type_path_t *path, /* We are initializing an empty compound. */ } else { type = skip_typeref(orig_type); - - /* we can't do usefull stuff if we didn't even parse the type. Skip the - * initializers in this case. */ - if (!is_type_valid(type)) { - skip_initializers(); - return create_empty_initializer(); - } } initializer_t **initializers = NEW_ARR_F(initializer_t*, 0); @@ -2475,8 +2680,9 @@ finish_designator: if (type == NULL) { /* we are already outside, ... */ - if (is_type_compound(outer_type) && - !outer_type->compound.declaration->init.complete) { + type_t *const outer_type_skip = skip_typeref(outer_type); + if (is_type_compound(outer_type_skip) && + !outer_type_skip->compound.declaration->init.complete) { goto error_parse_next; } goto error_excess; @@ -2491,7 +2697,7 @@ finish_designator: if (token.type == ',') { next_token(); } - if (token.type != '}') { + if (token.type != '}' && warning.other) { warningf(HERE, "excessive elements in initializer for type '%T'", orig_type); } @@ -2538,11 +2744,14 @@ finish_designator: ARR_APP1(initializer_t*, initializers, sub); } else { error_excess: - if (env->declaration != NULL) - warningf(HERE, "excess elements in struct initializer for '%Y'", - env->declaration->symbol); - else - warningf(HERE, "excess elements in struct initializer"); + if (warning.other) { + if (env->declaration != NULL) { + warningf(HERE, "excess elements in struct initializer for '%Y'", + env->declaration->symbol); + } else { + warningf(HERE, "excess elements in struct initializer"); + } + } } error_parse_next: @@ -2820,7 +3029,7 @@ static type_t *parse_enum_specifier(void) declaration->parent_scope = scope; } - type_t *const type = allocate_type_zero(TYPE_ENUM, &declaration->source_position); + type_t *const type = allocate_type_zero(TYPE_ENUM); type->enumt.declaration = declaration; if (token.type == '{') { @@ -2863,16 +3072,16 @@ static type_t *parse_typeof(void) expression_t *expression = NULL; -restart: - switch(token.type) { - case T___extension__: - /* This can be a prefix to a typename or an expression. We simply eat - * it now. */ - do { - next_token(); - } while (token.type == T___extension__); - goto restart; + bool old_type_prop = in_type_prop; + bool old_gcc_extension = in_gcc_extension; + in_type_prop = true; + while (token.type == T___extension__) { + /* This can be a prefix to a typename or an expression. */ + next_token(); + in_gcc_extension = true; + } + switch (token.type) { case T_IDENTIFIER: if (is_typedef_symbol(token.v.symbol)) { type = parse_typename(); @@ -2891,11 +3100,13 @@ restart: type = expression->base.type; break; } + in_type_prop = old_type_prop; + in_gcc_extension = old_gcc_extension; rem_anchor_token(')'); expect(')'); - type_t *typeof_type = allocate_type_zero(TYPE_TYPEOF, &expression->base.source_position); + type_t *typeof_type = allocate_type_zero(TYPE_TYPEOF); typeof_type->typeoft.expression = expression; typeof_type->typeoft.typeof_type = type; @@ -2928,7 +3139,7 @@ typedef enum specifiers_t { static type_t *create_builtin_type(symbol_t *const symbol, type_t *const real_type) { - type_t *type = allocate_type_zero(TYPE_BUILTIN, &builtin_source_position); + type_t *type = allocate_type_zero(TYPE_BUILTIN); type->builtin.symbol = symbol; type->builtin.real_type = real_type; @@ -2947,7 +3158,7 @@ static type_t *get_typedef_type(symbol_t *symbol) declaration->storage_class != STORAGE_CLASS_TYPEDEF) return NULL; - type_t *type = allocate_type_zero(TYPE_TYPEDEF, &declaration->source_position); + type_t *type = allocate_type_zero(TYPE_TYPEDEF); type->typedeft.declaration = declaration; return type; @@ -2963,7 +3174,7 @@ static bool check_alignment_value(long long intvalue) return false; } unsigned v = (unsigned)intvalue; - for(unsigned i = 1; i <= 8192; i += i) { + for (unsigned i = 1; i <= 8192; i += i) { if (i == v) return true; } @@ -2972,7 +3183,7 @@ static bool check_alignment_value(long long intvalue) } #define DET_MOD(name, tag) do { \ - if (*modifiers & tag) warningf(HERE, #name " used more than once"); \ + if (*modifiers & tag && warning.other) warningf(HERE, #name " used more than once"); \ *modifiers |= tag; \ } while (0) @@ -2994,7 +3205,7 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe if (token.type != T_INTEGER) goto end_error; if (check_alignment_value(token.v.intvalue)) { - if (specifiers->alignment != 0) + if (specifiers->alignment != 0 && warning.other) warningf(HERE, "align used more than once"); specifiers->alignment = (unsigned char)token.v.intvalue; } @@ -3034,7 +3245,7 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe } else if (symbol == sym_property) { next_token(); expect('('); - for(;;) { + for (;;) { bool is_get = false; if (token.type != T_IDENTIFIER) goto end_error; @@ -3082,7 +3293,7 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe expect(')'); } else if (symbol == sym_deprecated) { next_token(); - if (specifiers->deprecated != 0) + if (specifiers->deprecated != 0 && warning.other) warningf(HERE, "deprecated used more than once"); specifiers->deprecated = 1; if (token.type == '(') { @@ -3099,7 +3310,8 @@ static void parse_microsoft_extended_decl_modifier(declaration_specifiers_t *spe next_token(); DET_MOD(noalias, DM_NOALIAS); } else { - warningf(HERE, "Unknown modifier %Y ignored", token.v.symbol); + if (warning.other) + warningf(HERE, "Unknown modifier %Y ignored", token.v.symbol); next_token(); if (token.type == '(') skip_until(')'); @@ -3118,7 +3330,7 @@ static declaration_t *create_error_declaration(symbol_t *symbol, storage_class_t decl->source_position = *HERE; decl->declared_storage_class = storage_class; decl->storage_class = - storage_class != STORAGE_CLASS_NONE || scope == global_scope ? + storage_class != STORAGE_CLASS_NONE || scope == file_scope ? storage_class : STORAGE_CLASS_AUTO; decl->symbol = symbol; decl->implicit = true; @@ -3224,12 +3436,13 @@ static void finish_union_type(compound_type_t *type) { static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) { - type_t *type = NULL; - type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE; - type_modifiers_t modifiers = TYPE_MODIFIER_NONE; - unsigned type_specifiers = 0; - bool newtype = false; - bool saw_error = false; + type_t *type = NULL; + type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE; + type_modifiers_t modifiers = TYPE_MODIFIER_NONE; + unsigned type_specifiers = 0; + bool newtype = false; + bool saw_error = false; + bool old_gcc_extension = in_gcc_extension; specifiers->source_position = token.source_position; @@ -3239,7 +3452,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) if (specifiers->modifiers & DM_TRANSPARENT_UNION) modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; - switch(token.type) { + switch (token.type) { /* storage class */ #define MATCH_STORAGE_CLASS(token, class) \ @@ -3304,8 +3517,8 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) MATCH_TYPE_QUALIFIER(T___sptr, TYPE_QUALIFIER_SPTR); case T___extension__: - /* TODO */ next_token(); + in_gcc_extension = true; break; /* type specifiers */ @@ -3358,19 +3571,19 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) break; case T_struct: { - type = allocate_type_zero(TYPE_COMPOUND_STRUCT, HERE); + type = allocate_type_zero(TYPE_COMPOUND_STRUCT); type->compound.declaration = parse_compound_type_specifier(true); finish_struct_type(&type->compound); break; } case T_union: { - type = allocate_type_zero(TYPE_COMPOUND_UNION, HERE); + type = allocate_type_zero(TYPE_COMPOUND_UNION); type->compound.declaration = parse_compound_type_specifier(false); if (type->compound.declaration->modifiers & DM_TRANSPARENT_UNION) modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; - break; finish_union_type(&type->compound); + break; } case T_enum: type = parse_enum_specifier(); @@ -3423,7 +3636,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) declaration_t *const decl = create_error_declaration(token.v.symbol, STORAGE_CLASS_TYPEDEF); - type = allocate_type_zero(TYPE_TYPEDEF, HERE); + type = allocate_type_zero(TYPE_TYPEDEF); type->typedeft.declaration = decl; next_token(); @@ -3450,6 +3663,8 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) } finish_specifiers: + in_gcc_extension = old_gcc_extension; + if (type == NULL || (saw_error && type_specifiers != 0)) { atomic_type_kind_t atomic_type; @@ -3612,13 +3827,13 @@ warn_about_long_long: } if (type_specifiers & SPECIFIER_COMPLEX) { - type = allocate_type_zero(TYPE_COMPLEX, &builtin_source_position); + type = allocate_type_zero(TYPE_COMPLEX); type->complex.akind = atomic_type; } else if (type_specifiers & SPECIFIER_IMAGINARY) { - type = allocate_type_zero(TYPE_IMAGINARY, &builtin_source_position); + type = allocate_type_zero(TYPE_IMAGINARY); type->imaginary.akind = atomic_type; } else { - type = allocate_type_zero(TYPE_ATOMIC, &builtin_source_position); + type = allocate_type_zero(TYPE_ATOMIC); type->atomic.akind = atomic_type; } newtype = true; @@ -3667,7 +3882,13 @@ static type_qualifiers_t parse_type_qualifiers(void) } } -static declaration_t *parse_identifier_list(void) +/** + * Parses an K&R identifier list and return a list of declarations. + * + * @param last points to the last declaration in the list + * @return the list of declarations + */ +static declaration_t *parse_identifier_list(declaration_t **last) { declaration_t *declarations = NULL; declaration_t *last_declaration = NULL; @@ -3691,6 +3912,7 @@ static declaration_t *parse_identifier_list(void) next_token(); } while (token.type == T_IDENTIFIER); + *last = last_declaration; return declarations; } @@ -3743,7 +3965,13 @@ static declaration_t *parse_parameter(void) return declaration; } -static declaration_t *parse_parameters(function_type_t *type) +/** + * Parses a function type parameter list and return a list of declarations. + * + * @param last point to the last element of the list + * @return the parameter list + */ +static declaration_t *parse_parameters(function_type_t *type, declaration_t **last) { declaration_t *declarations = NULL; @@ -3756,7 +3984,7 @@ static declaration_t *parse_parameters(function_type_t *type) token_type_t la1_type = (token_type_t)look_ahead(1)->type; if (la1_type == ',' || la1_type == ')') { type->kr_style_parameters = true; - declarations = parse_identifier_list(); + declarations = parse_identifier_list(last); goto parameters_finished; } } @@ -3822,10 +4050,12 @@ parameters_finished: expect(')'); restore_anchor_state(',', saved_comma_state); + *last = last_declaration; return declarations; end_error: restore_anchor_state(',', saved_comma_state); + *last = NULL; return NULL; } @@ -3914,16 +4144,15 @@ static construct_type_t *parse_array_declarator(void) rem_anchor_token(']'); expect(']'); - return (construct_type_t*) array; end_error: - return NULL; + return (construct_type_t*) array; } static construct_type_t *parse_function_declarator(declaration_t *declaration) { type_t *type; if (declaration != NULL) { - type = allocate_type_zero(TYPE_FUNCTION, &declaration->source_position); + type = allocate_type_zero(TYPE_FUNCTION); unsigned mask = declaration->modifiers & (DM_CDECL|DM_STDCALL|DM_FASTCALL|DM_THISCALL); @@ -3959,12 +4188,14 @@ static construct_type_t *parse_function_declarator(declaration_t *declaration) else if (declaration->modifiers & DM_THISCALL) type->function.calling_convention = CC_THISCALL; } else { - type = allocate_type_zero(TYPE_FUNCTION, HERE); + type = allocate_type_zero(TYPE_FUNCTION); } - declaration_t *parameters = parse_parameters(&type->function); + declaration_t *last; + declaration_t *parameters = parse_parameters(&type->function, &last); if (declaration != NULL) { - declaration->scope.declarations = parameters; + declaration->scope.declarations = parameters; + declaration->scope.last_declaration = last; } construct_function_type_t *construct_function_type = @@ -4055,13 +4286,7 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration, if (may_be_abstract) break; parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL); - /* avoid a loop in the outermost scope, because eat_statement doesn't - * eat '}' */ - if (token.type == '}' && current_function == NULL) { - next_token(); - } else { - eat_statement(); - } + eat_until_anchor(); return NULL; } @@ -4160,31 +4385,31 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, function_type->function.return_type = type; type_t *skipped_return_type = skip_typeref(type); + /* §6.7.5.3(1) */ if (is_type_function(skipped_return_type)) { errorf(HERE, "function returning function is not allowed"); - type = type_error_type; } else if (is_type_array(skipped_return_type)) { errorf(HERE, "function returning array is not allowed"); - type = type_error_type; } else { - type = function_type; + if (skipped_return_type->base.qualifiers != 0 && warning.other) { + warningf(HERE, + "type qualifiers in return type of function type are meaningless"); + } } + + type = function_type; break; } case CONSTRUCT_POINTER: { parsed_pointer_t *parsed_pointer = (parsed_pointer_t*) iter; - type_t *pointer_type = allocate_type_zero(TYPE_POINTER, &null_position); - pointer_type->pointer.points_to = type; - pointer_type->base.qualifiers = parsed_pointer->type_qualifiers; - - type = pointer_type; - break; + type = make_pointer_type(type, parsed_pointer->type_qualifiers); + continue; } case CONSTRUCT_ARRAY: { parsed_array_t *parsed_array = (parsed_array_t*) iter; - type_t *array_type = allocate_type_zero(TYPE_ARRAY, &null_position); + type_t *array_type = allocate_type_zero(TYPE_ARRAY); expression_t *size_expression = parsed_array->size; if (size_expression != NULL) { @@ -4209,12 +4434,13 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, } type_t *skipped_type = skip_typeref(type); - if (is_type_atomic(skipped_type, ATOMIC_TYPE_VOID)) { - errorf(HERE, "array of void is not allowed"); - type = type_error_type; - } else { - type = array_type; + /* §6.7.5.2(1) */ + if (is_type_incomplete(skipped_type)) { + errorf(HERE, "array of incomplete type '%T' is not allowed", type); + } else if (is_type_function(skipped_type)) { + errorf(HERE, "array of functions is not allowed"); } + type = array_type; break; } } @@ -4246,8 +4472,8 @@ static declaration_t *parse_declarator( declaration->is_inline = specifiers->is_inline; declaration->storage_class = specifiers->declared_storage_class; - if (declaration->storage_class == STORAGE_CLASS_NONE - && scope != global_scope) { + if (declaration->storage_class == STORAGE_CLASS_NONE && + scope != file_scope) { declaration->storage_class = STORAGE_CLASS_AUTO; } @@ -4374,7 +4600,7 @@ static declaration_t *record_declaration( previous_declaration == NULL) { warningf(&declaration->source_position, "function declaration '%#T' is not a prototype", - orig_type, declaration->symbol); + orig_type, symbol); } if (warning.main && is_type_function(type) && is_sym_main(symbol)) { @@ -4383,14 +4609,23 @@ static declaration_t *record_declaration( if (warning.nested_externs && declaration->storage_class == STORAGE_CLASS_EXTERN && - scope != global_scope) { + scope != file_scope) { warningf(&declaration->source_position, "nested extern declaration of '%#T'", declaration->type, symbol); } assert(declaration != previous_declaration); - if (previous_declaration != NULL - && previous_declaration->parent_scope == scope) { + if (previous_declaration != NULL && + previous_declaration->parent_scope == ¤t_function->scope && + scope->depth == previous_declaration->parent_scope->depth + 1) { + errorf(&declaration->source_position, + "declaration '%#T' redeclares the parameter '%#T' (declared %P)", + orig_type, symbol, previous_declaration->type, symbol, + &previous_declaration->source_position); + goto finish; + } + if (previous_declaration != NULL && + previous_declaration->parent_scope == scope) { /* can happen for K&R style declarations */ if (previous_declaration->type == NULL) { previous_declaration->type = declaration->type; @@ -4514,7 +4749,7 @@ warn_redundant_declaration: } } else { if (warning.missing_declarations && - scope == global_scope && ( + scope == file_scope && ( declaration->storage_class == STORAGE_CLASS_NONE || declaration->storage_class == STORAGE_CLASS_THREAD )) { @@ -4522,7 +4757,7 @@ warn_redundant_declaration: "no previous declaration for '%#T'", orig_type, symbol); } } - +finish: assert(declaration->parent_scope == NULL); assert(scope != NULL); @@ -4542,7 +4777,7 @@ static void parser_error_multiple_definition(declaration_t *declaration, static bool is_declaration_specifier(const token_t *token, bool only_specifiers_qualifiers) { - switch(token->type) { + switch (token->type) { TYPE_SPECIFIERS TYPE_QUALIFIERS return true; @@ -4570,9 +4805,9 @@ static void parse_init_declarator_rest(declaration_t *declaration) } bool must_be_constant = false; - if (declaration->storage_class == STORAGE_CLASS_STATIC - || declaration->storage_class == STORAGE_CLASS_THREAD_STATIC - || declaration->parent_scope == global_scope) { + if (declaration->storage_class == STORAGE_CLASS_STATIC || + declaration->storage_class == STORAGE_CLASS_THREAD_STATIC || + declaration->parent_scope == file_scope) { must_be_constant = true; } @@ -4605,38 +4840,42 @@ static void parse_anonymous_declaration_rest( { eat(';'); - declaration_t *const declaration = allocate_declaration_zero(); - declaration->type = specifiers->type; - declaration->declared_storage_class = specifiers->declared_storage_class; - declaration->source_position = specifiers->source_position; - declaration->modifiers = specifiers->modifiers; - - if (declaration->declared_storage_class != STORAGE_CLASS_NONE) { - warningf(&declaration->source_position, - "useless storage class in empty declaration"); - } - declaration->storage_class = STORAGE_CLASS_NONE; + if (warning.other) { + if (specifiers->declared_storage_class != STORAGE_CLASS_NONE) { + warningf(&specifiers->source_position, + "useless storage class in empty declaration"); + } - type_t *type = declaration->type; - switch (type->kind) { - case TYPE_COMPOUND_STRUCT: - case TYPE_COMPOUND_UNION: { - if (type->compound.declaration->symbol == NULL) { - warningf(&declaration->source_position, - "unnamed struct/union that defines no instances"); + type_t *type = specifiers->type; + switch (type->kind) { + case TYPE_COMPOUND_STRUCT: + case TYPE_COMPOUND_UNION: { + if (type->compound.declaration->symbol == NULL) { + warningf(&specifiers->source_position, + "unnamed struct/union that defines no instances"); + } + break; } - break; - } - case TYPE_ENUM: - break; + case TYPE_ENUM: + break; - default: - warningf(&declaration->source_position, "empty declaration"); - break; + default: + warningf(&specifiers->source_position, "empty declaration"); + break; + } } +#ifdef RECORD_EMPTY_DECLARATIONS + declaration_t *const declaration = allocate_declaration_zero(); + declaration->type = specifiers->type; + declaration->declared_storage_class = specifiers->declared_storage_class; + declaration->source_position = specifiers->source_position; + declaration->modifiers = specifiers->modifiers; + declaration->storage_class = STORAGE_CLASS_NONE; + append_declaration(declaration); +#endif } static void parse_declaration_rest(declaration_t *ndeclaration, @@ -4644,7 +4883,6 @@ static void parse_declaration_rest(declaration_t *ndeclaration, parsed_declaration_func finished_declaration) { add_anchor_token(';'); - add_anchor_token('='); add_anchor_token(','); while(true) { declaration_t *declaration = @@ -4653,8 +4891,9 @@ static void parse_declaration_rest(declaration_t *ndeclaration, type_t *orig_type = declaration->type; type_t *type = skip_typeref(orig_type); - if (type->kind != TYPE_FUNCTION && - declaration->is_inline && + if (warning.other && + type->kind != TYPE_FUNCTION && + declaration->is_inline && is_type_valid(type)) { warningf(&declaration->source_position, "variable '%Y' declared 'inline'\n", declaration->symbol); @@ -4668,13 +4907,14 @@ static void parse_declaration_rest(declaration_t *ndeclaration, break; eat(','); + add_anchor_token('='); ndeclaration = parse_declarator(specifiers, /*may_be_abstract=*/false); + rem_anchor_token('='); } expect(';'); end_error: rem_anchor_token(';'); - rem_anchor_token('='); rem_anchor_token(','); } @@ -4717,7 +4957,10 @@ static void parse_declaration(parsed_declaration_func finished_declaration) { declaration_specifiers_t specifiers; memset(&specifiers, 0, sizeof(specifiers)); + + add_anchor_token(';'); parse_declaration_specifiers(&specifiers); + rem_anchor_token(';'); if (token.type == ';') { parse_anonymous_declaration_rest(&specifiers); @@ -4750,10 +4993,11 @@ static void parse_kr_declaration_list(declaration_t *declaration) if (!type->function.kr_style_parameters) return; + add_anchor_token('{'); + /* push function parameters */ - int top = environment_top(); - scope_t *last_scope = scope; - set_scope(&declaration->scope); + size_t const top = environment_top(); + scope_push(&declaration->scope); declaration_t *parameter = declaration->scope.declarations; for ( ; parameter != NULL; parameter = parameter->next) { @@ -4769,7 +5013,7 @@ static void parse_kr_declaration_list(declaration_t *declaration) /* pop function parameters */ assert(scope == &declaration->scope); - set_scope(last_scope); + scope_pop(); environment_pop_to(top); /* update function type */ @@ -4828,6 +5072,8 @@ static void parse_kr_declaration_list(declaration_t *declaration) } declaration->type = type; + + rem_anchor_token('{'); } static bool first_err = true; @@ -4886,6 +5132,45 @@ static void check_labels(void) label_first = label_last = NULL; } +static void warn_unused_decl(declaration_t *decl, declaration_t *end, char const *const what) +{ + for (; decl != NULL; decl = decl->next) { + if (decl->implicit) + continue; + + if (!decl->used) { + print_in_function(); + warningf(&decl->source_position, "%s '%Y' is unused", what, decl->symbol); + } else if (!decl->read) { + print_in_function(); + warningf(&decl->source_position, "%s '%Y' is never read", what, decl->symbol); + } + + if (decl == end) + break; + } +} + +static void check_unused_variables(statement_t *const stmt, void *const env) +{ + (void)env; + + switch (stmt->kind) { + case STATEMENT_DECLARATION: { + declaration_statement_t const *const decls = &stmt->declaration; + warn_unused_decl(decls->declarations_begin, decls->declarations_end, "variable"); + return; + } + + case STATEMENT_FOR: + warn_unused_decl(stmt->fors.scope.declarations, NULL, "variable"); + return; + + default: + return; + } +} + /** * Check declarations of current_function for unused entities. */ @@ -4894,20 +5179,13 @@ static void check_declarations(void) if (warning.unused_parameter) { const scope_t *scope = ¤t_function->scope; - if (is_sym_main(current_function->symbol)) { - /* do not issue unused warnings for main */ - return; - } - const declaration_t *parameter = scope->declarations; - for (; parameter != NULL; parameter = parameter->next) { - if (! parameter->used) { - print_in_function(); - warningf(¶meter->source_position, - "unused parameter '%Y'", parameter->symbol); - } + /* do not issue unused warnings for main */ + if (!is_sym_main(current_function->symbol)) { + warn_unused_decl(scope->declarations, NULL, "parameter"); } } if (warning.unused_variable) { + walk_statements(current_function->init.statement, check_unused_variables, NULL); } } @@ -5270,57 +5548,12 @@ continue_for:; check_reachable(next); } -static void check_unreachable(statement_t const* const stmt) +static void check_unreachable(statement_t* const stmt, void *const env) { - if (!stmt->base.reachable && - stmt->kind != STATEMENT_DO_WHILE && - stmt->kind != STATEMENT_FOR && - (stmt->kind != STATEMENT_COMPOUND || stmt->compound.statements == NULL)) { - warningf(&stmt->base.source_position, "statement is unreachable"); - } + (void)env; switch (stmt->kind) { - case STATEMENT_INVALID: - case STATEMENT_EMPTY: - case STATEMENT_RETURN: - case STATEMENT_DECLARATION: - case STATEMENT_EXPRESSION: - case STATEMENT_CONTINUE: - case STATEMENT_BREAK: - case STATEMENT_GOTO: - case STATEMENT_ASM: - case STATEMENT_LEAVE: - break; - - case STATEMENT_COMPOUND: - if (stmt->compound.statements) - check_unreachable(stmt->compound.statements); - break; - - case STATEMENT_IF: - check_unreachable(stmt->ifs.true_statement); - if (stmt->ifs.false_statement != NULL) - check_unreachable(stmt->ifs.false_statement); - break; - - case STATEMENT_SWITCH: - check_unreachable(stmt->switchs.body); - break; - - case STATEMENT_LABEL: - check_unreachable(stmt->label.statement); - break; - - case STATEMENT_CASE_LABEL: - check_unreachable(stmt->case_label.statement); - break; - - case STATEMENT_WHILE: - check_unreachable(stmt->whiles.body); - break; - case STATEMENT_DO_WHILE: - check_unreachable(stmt->do_while.body); if (!stmt->base.reachable) { expression_t const *const cond = stmt->do_while.condition; if (determine_truth(cond) >= 0) { @@ -5328,7 +5561,7 @@ static void check_unreachable(statement_t const* const stmt) "condition of do-while-loop is unreachable"); } } - break; + return; case STATEMENT_FOR: { for_statement_t const* const fors = &stmt->fors; @@ -5352,20 +5585,19 @@ static void check_unreachable(statement_t const* const stmt) "step of for-statement is unreachable"); } } - - check_unreachable(fors->body); - break; + return; } - case STATEMENT_MS_TRY: { - ms_try_statement_t const *const ms_try = &stmt->ms_try; - check_unreachable(ms_try->try_statement); - check_unreachable(ms_try->final_statement); - } - } + case STATEMENT_COMPOUND: + if (stmt->compound.statements != NULL) + return; + /* FALLTHROUGH*/ - if (stmt->base.next) - check_unreachable(stmt->base.next); + default: + if (!stmt->base.reachable) + warningf(&stmt->base.source_position, "statement is unreachable"); + return; + } } static void parse_external_declaration(void) @@ -5388,13 +5620,15 @@ static void parse_external_declaration(void) add_anchor_token(','); add_anchor_token('='); add_anchor_token(';'); + add_anchor_token('{'); /* declarator is common to both function-definitions and declarations */ declaration_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false); - rem_anchor_token(','); - rem_anchor_token('='); + rem_anchor_token('{'); rem_anchor_token(';'); + rem_anchor_token('='); + rem_anchor_token(','); /* must be a declaration */ switch (token.type) { @@ -5463,9 +5697,8 @@ static void parse_external_declaration(void) type = skip_typeref(declaration->type); /* push function parameters and switch scope */ - int top = environment_top(); - scope_t *last_scope = scope; - set_scope(&declaration->scope); + size_t const top = environment_top(); + scope_push(&declaration->scope); declaration_t *parameter = declaration->scope.declarations; for( ; parameter != NULL; parameter = parameter->next) { @@ -5503,7 +5736,7 @@ static void parse_external_declaration(void) noreturn_candidate = true; check_reachable(body); if (warning.unreachable_code) - check_unreachable(body); + walk_statements(body, check_unreachable, NULL); if (warning.missing_noreturn && noreturn_candidate && !(declaration->modifiers & DM_NORETURN)) { @@ -5520,7 +5753,7 @@ static void parse_external_declaration(void) } assert(scope == &declaration->scope); - set_scope(last_scope); + scope_pop(); environment_pop_to(top); } @@ -5528,7 +5761,7 @@ static type_t *make_bitfield_type(type_t *base_type, expression_t *size, source_position_t *source_position, const symbol_t *symbol) { - type_t *type = allocate_type_zero(TYPE_BITFIELD, source_position); + type_t *type = allocate_type_zero(TYPE_BITFIELD); type->bitfield.base_type = base_type; type->bitfield.size_expression = size; @@ -5685,7 +5918,11 @@ static void parse_compound_type_entries(declaration_t *compound_declaration) eat('{'); add_anchor_token('}'); - while (token.type != '}' && token.type != T_EOF) { + while (token.type != '}') { + if (token.type == T_EOF) { + errorf(HERE, "EOF while parsing struct"); + break; + } declaration_specifiers_t specifiers; memset(&specifiers, 0, sizeof(specifiers)); parse_declaration_specifiers(&specifiers); @@ -5693,10 +5930,6 @@ static void parse_compound_type_entries(declaration_t *compound_declaration) parse_compound_declarators(compound_declaration, &specifiers); } rem_anchor_token('}'); - - if (token.type == T_EOF) { - errorf(HERE, "EOF while parsing struct"); - } next_token(); } @@ -5720,13 +5953,11 @@ static type_t *parse_typename(void) -typedef expression_t* (*parse_expression_function) (unsigned precedence); -typedef expression_t* (*parse_expression_infix_function) (unsigned precedence, - expression_t *left); +typedef expression_t* (*parse_expression_function)(void); +typedef expression_t* (*parse_expression_infix_function)(expression_t *left); typedef struct expression_parser_function_t expression_parser_function_t; struct expression_parser_function_t { - unsigned precedence; parse_expression_function parser; unsigned infix_precedence; parse_expression_infix_function infix_parser; @@ -5825,8 +6056,7 @@ static expression_t *parse_character_constant(void) cnst->conste.v.character = token.v.string; if (cnst->conste.v.character.size != 1) { - if (warning.multichar && (c_mode & _GNUC)) { - /* TODO */ + if (warning.multichar && GNU_MODE) { warningf(HERE, "multi-character character constant"); } else { errorf(HERE, "more than 1 characters in character constant"); @@ -5849,8 +6079,7 @@ static expression_t *parse_wide_character_constant(void) cnst->conste.v.wide_character = token.v.wide_string; if (cnst->conste.v.wide_character.size != 1) { - if (warning.multichar && (c_mode & _GNUC)) { - /* TODO */ + if (warning.multichar && GNU_MODE) { warningf(HERE, "multi-character character constant"); } else { errorf(HERE, "more than 1 characters in character constant"); @@ -5878,7 +6107,7 @@ static expression_t *parse_float_const(void) static declaration_t *create_implicit_function(symbol_t *symbol, const source_position_t *source_position) { - type_t *ntype = allocate_type_zero(TYPE_FUNCTION, source_position); + type_t *ntype = allocate_type_zero(TYPE_FUNCTION); ntype->function.return_type = type_int; ntype->function.unspecified_parameters = true; @@ -5921,7 +6150,7 @@ static type_t *make_function_2_type(type_t *return_type, type_t *argument_type1, parameter1->type = argument_type1; parameter1->next = parameter2; - type_t *type = allocate_type_zero(TYPE_FUNCTION, &builtin_source_position); + type_t *type = allocate_type_zero(TYPE_FUNCTION); type->function.return_type = return_type; type->function.parameters = parameter1; @@ -5947,7 +6176,7 @@ static type_t *make_function_1_type(type_t *return_type, type_t *argument_type) memset(parameter, 0, sizeof(parameter[0])); parameter->type = argument_type; - type_t *type = allocate_type_zero(TYPE_FUNCTION, &builtin_source_position); + type_t *type = allocate_type_zero(TYPE_FUNCTION); type->function.return_type = return_type; type->function.parameters = parameter; @@ -5961,7 +6190,7 @@ static type_t *make_function_1_type(type_t *return_type, type_t *argument_type) static type_t *make_function_0_type(type_t *return_type) { - type_t *type = allocate_type_zero(TYPE_FUNCTION, &builtin_source_position); + type_t *type = allocate_type_zero(TYPE_FUNCTION); type->function.return_type = return_type; type->function.parameters = NULL; @@ -5985,11 +6214,17 @@ static type_t *get_builtin_symbol_type(symbol_t *symbol) return make_function_1_type(type_void_ptr, type_size_t); case T___builtin_huge_val: return make_function_0_type(type_double); + case T___builtin_inf: + return make_function_0_type(type_double); + case T___builtin_inff: + return make_function_0_type(type_float); + case T___builtin_infl: + return make_function_0_type(type_long_double); case T___builtin_nan: return make_function_1_type(type_double, type_char_ptr); case T___builtin_nanf: return make_function_1_type(type_float, type_char_ptr); - case T___builtin_nand: + case T___builtin_nanl: return make_function_1_type(type_long_double, type_char_ptr); case T___builtin_va_end: return make_function_1_type(type_void, type_valist); @@ -6098,11 +6333,11 @@ static expression_t *parse_reference(void) } } - type_t *type = declaration->type; + type_t *orig_type = declaration->type; /* we always do the auto-type conversions; the & and sizeof parser contains * code to revert this! */ - type = automatic_type_conversion(type); + type_t *type = automatic_type_conversion(orig_type); ref->declaration = declaration; ref->base.type = type; @@ -6110,6 +6345,14 @@ static expression_t *parse_reference(void) /* this declaration is used */ declaration->used = true; + if (declaration->parent_scope != file_scope && + declaration->parent_scope->depth < current_function->scope.depth && + is_type_valid(orig_type) && !is_type_function(orig_type)) { + /* access of a variable from an outer function */ + declaration->address_taken = true; + current_function->need_closure = true; + } + /* check for deprecated functions */ if (warning.deprecated_declarations && declaration->modifiers & DM_DEPRECATED) { @@ -6125,7 +6368,7 @@ static expression_t *parse_reference(void) declaration->symbol, &declaration->source_position); } } - if (warning.init_self && declaration == current_init_decl) { + if (warning.init_self && declaration == current_init_decl && !in_type_prop) { current_init_decl = NULL; warningf(HERE, "variable '%#T' is initialized by itself", declaration->type, declaration->symbol); @@ -6222,7 +6465,7 @@ static expression_t *parse_cast(void) expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST); cast->base.source_position = source_position; - expression_t *value = parse_sub_expression(20); + expression_t *value = parse_sub_expression(PREC_CAST); cast->base.type = type; cast->unary.value = value; @@ -6258,7 +6501,7 @@ static expression_t *parse_statement_expression(void) if (stmt->kind == STATEMENT_EXPRESSION) { type = stmt->expression.expression->base.type; } - } else { + } else if (warning.other) { warningf(&expression->base.source_position, "empty statement expression ({})"); } expression->base.type = type; @@ -6601,7 +6844,6 @@ static expression_t *parse_compare_builtin(void) break; default: internal_errorf(HERE, "invalid compare builtin found"); - break; } expression->base.source_position = *HERE; next_token(); @@ -6691,7 +6933,10 @@ static declaration_t *get_label(symbol_t *symbol) candidate = get_declaration(symbol, NAMESPACE_LOCAL_LABEL); /* if we found a local label, we already created the declaration */ if (candidate != NULL) { - assert(candidate->parent_scope == scope); + if (candidate->parent_scope != scope) { + assert(candidate->parent_scope->depth < scope->depth); + current_function->goto_to_outer = true; + } return candidate; } @@ -6806,9 +7051,12 @@ static expression_t *parse_primary_expression(void) case T___builtin_va_arg: return parse_va_arg(); case T___builtin_expect: case T___builtin_alloca: + case T___builtin_inf: + case T___builtin_inff: + case T___builtin_infl: case T___builtin_nan: - case T___builtin_nand: case T___builtin_nanf: + case T___builtin_nanl: case T___builtin_huge_val: case T___builtin_va_end: return parse_builtin_symbol(); case T___builtin_isgreater: @@ -6821,7 +7069,7 @@ static expression_t *parse_primary_expression(void) case T___builtin_prefetch: return parse_builtin_prefetch(); case T__assume: return parse_assume(); case T_ANDAND: - if (c_mode & _GNUC) + if (GNU_MODE) return parse_label_address(); break; @@ -6848,11 +7096,8 @@ static void check_for_char_index_type(const expression_t *expression) } } -static expression_t *parse_array_expression(unsigned precedence, - expression_t *left) +static expression_t *parse_array_expression(expression_t *left) { - (void) precedence; - eat('['); add_anchor_token(']'); @@ -6903,15 +7148,17 @@ static expression_t *parse_array_expression(unsigned precedence, } static expression_t *parse_typeprop(expression_kind_t const kind, - source_position_t const pos, - unsigned const precedence) + source_position_t const pos) { - expression_t *tp_expression = allocate_expression_zero(kind); + expression_t *tp_expression = allocate_expression_zero(kind); tp_expression->base.type = type_size_t; tp_expression->base.source_position = pos; char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; + /* we only refer to a type property, mark this case */ + bool old = in_type_prop; + in_type_prop = true; if (token.type == '(' && is_declaration_specifier(look_ahead(1), true)) { next_token(); add_anchor_token(')'); @@ -6932,7 +7179,7 @@ static expression_t *parse_typeprop(expression_kind_t const kind, rem_anchor_token(')'); expect(')'); } else { - expression_t *expression = parse_sub_expression(precedence); + expression_t *expression = parse_sub_expression(PREC_UNARY); type_t* const orig_type = revert_automatic_type_conversion(expression); expression->base.type = orig_type; @@ -6952,27 +7199,26 @@ static expression_t *parse_typeprop(expression_kind_t const kind, } end_error: + in_type_prop = old; return tp_expression; } -static expression_t *parse_sizeof(unsigned precedence) +static expression_t *parse_sizeof(void) { source_position_t pos = *HERE; eat(T_sizeof); - return parse_typeprop(EXPR_SIZEOF, pos, precedence); + return parse_typeprop(EXPR_SIZEOF, pos); } -static expression_t *parse_alignof(unsigned precedence) +static expression_t *parse_alignof(void) { source_position_t pos = *HERE; eat(T___alignof__); - return parse_typeprop(EXPR_ALIGNOF, pos, precedence); + return parse_typeprop(EXPR_ALIGNOF, pos); } -static expression_t *parse_select_expression(unsigned precedence, - expression_t *compound) +static expression_t *parse_select_expression(expression_t *compound) { - (void) precedence; assert(token.type == '.' || token.type == T_MINUSGREATER); bool is_pointer = (token.type == T_MINUSGREATER); @@ -7117,10 +7363,8 @@ static void check_call_argument(const function_parameter_t *parameter, * * @param expression the function address */ -static expression_t *parse_call_expression(unsigned precedence, - expression_t *expression) +static expression_t *parse_call_expression(expression_t *expression) { - (void) precedence; expression_t *result = allocate_expression_zero(EXPR_CALL); result->base.source_position = expression->base.source_position; @@ -7227,8 +7471,7 @@ static bool same_compound_type(const type_t *type1, const type_t *type2) * * @param expression the conditional expression */ -static expression_t *parse_conditional_expression(unsigned precedence, - expression_t *expression) +static expression_t *parse_conditional_expression(expression_t *expression) { expression_t *result = allocate_expression_zero(EXPR_CONDITIONAL); @@ -7249,13 +7492,13 @@ static expression_t *parse_conditional_expression(unsigned precedence, expression_t *true_expression = expression; bool gnu_cond = false; - if ((c_mode & _GNUC) && token.type == ':') { + if (GNU_MODE && token.type == ':') { gnu_cond = true; } else true_expression = parse_expression(); rem_anchor_token(':'); expect(':'); - expression_t *false_expression = parse_sub_expression(precedence); + expression_t *false_expression = parse_sub_expression(PREC_CONDITIONAL); type_t *const orig_true_type = true_expression->base.type; type_t *const orig_false_type = false_expression->base.type; @@ -7264,10 +7507,12 @@ static expression_t *parse_conditional_expression(unsigned precedence, /* 6.5.15.3 */ type_t *result_type; - if (is_type_atomic(true_type, ATOMIC_TYPE_VOID) || - is_type_atomic(false_type, ATOMIC_TYPE_VOID)) { - if (!is_type_atomic(true_type, ATOMIC_TYPE_VOID) - || !is_type_atomic(false_type, ATOMIC_TYPE_VOID)) { + if (is_type_atomic(true_type, ATOMIC_TYPE_VOID) || + is_type_atomic(false_type, ATOMIC_TYPE_VOID)) { + if (warning.other && ( + !is_type_atomic(true_type, ATOMIC_TYPE_VOID) || + !is_type_atomic(false_type, ATOMIC_TYPE_VOID) + )) { warningf(&conditional->base.source_position, "ISO C forbids conditional expression with only one void side"); } @@ -7314,9 +7559,11 @@ static expression_t *parse_conditional_expression(unsigned precedence, get_unqualified_type(to2))) { to = to1; } else { - warningf(&conditional->base.source_position, - "pointer types '%T' and '%T' in conditional expression are incompatible", - true_type, false_type); + if (warning.other) { + warningf(&conditional->base.source_position, + "pointer types '%T' and '%T' in conditional expression are incompatible", + true_type, false_type); + } to = type_void; } @@ -7324,17 +7571,19 @@ static expression_t *parse_conditional_expression(unsigned precedence, get_qualified_type(to, to1->base.qualifiers | to2->base.qualifiers); result_type = make_pointer_type(type, TYPE_QUALIFIER_NONE); } else if (is_type_integer(other_type)) { - warningf(&conditional->base.source_position, - "pointer/integer type mismatch in conditional expression ('%T' and '%T')", true_type, false_type); + if (warning.other) { + warningf(&conditional->base.source_position, + "pointer/integer type mismatch in conditional expression ('%T' and '%T')", true_type, false_type); + } result_type = pointer_type; } else { - type_error_incompatible("while parsing conditional", - &expression->base.source_position, true_type, false_type); + if (is_type_valid(other_type)) { + type_error_incompatible("while parsing conditional", + &expression->base.source_position, true_type, false_type); + } result_type = type_error_type; } } else { - /* TODO: one pointer to void*, other some pointer */ - if (is_type_valid(true_type) && is_type_valid(false_type)) { type_error_incompatible("while parsing conditional", &conditional->base.source_position, true_type, @@ -7356,20 +7605,21 @@ end_error: /** * Parse an extension expression. */ -static expression_t *parse_extension(unsigned precedence) +static expression_t *parse_extension(void) { eat(T___extension__); - /* TODO enable extensions */ - expression_t *expression = parse_sub_expression(precedence); - /* TODO disable extensions */ + bool old_gcc_extension = in_gcc_extension; + in_gcc_extension = true; + expression_t *expression = parse_sub_expression(PREC_UNARY); + in_gcc_extension = old_gcc_extension; return expression; } /** * Parse a __builtin_classify_type() expression. */ -static expression_t *parse_builtin_classify_type(const unsigned precedence) +static expression_t *parse_builtin_classify_type(void) { eat(T___builtin_classify_type); @@ -7378,7 +7628,7 @@ static expression_t *parse_builtin_classify_type(const unsigned precedence) expect('('); add_anchor_token(')'); - expression_t *expression = parse_sub_expression(precedence); + expression_t *expression = parse_expression(); rem_anchor_token(')'); expect(')'); result->classify_type.type_expression = expression; @@ -7396,7 +7646,7 @@ static bool check_pointer_arithmetic(const source_position_t *source_position, points_to = skip_typeref(points_to); if (is_type_incomplete(points_to)) { - if (!(c_mode & _GNUC) || !is_type_atomic(points_to, ATOMIC_TYPE_VOID)) { + if (!GNU_MODE || !is_type_atomic(points_to, ATOMIC_TYPE_VOID)) { errorf(source_position, "arithmetic with pointer to incomplete type '%T' not allowed", orig_pointer_type); @@ -7407,7 +7657,7 @@ static bool check_pointer_arithmetic(const source_position_t *source_position, orig_pointer_type); } } else if (is_type_function(points_to)) { - if (!(c_mode && _GNUC)) { + if (!GNU_MODE) { errorf(source_position, "arithmetic with pointer to function type '%T' not allowed", orig_pointer_type); @@ -7431,7 +7681,10 @@ static bool is_lvalue(const expression_t *expression) return true; default: - return false; + /* Claim it is an lvalue, if the type is invalid. There was a parse + * error before, which maybe prevented properly recognizing it as + * lvalue. */ + return !is_type_valid(skip_typeref(expression->base.type)); } } @@ -7481,6 +7734,46 @@ static void semantic_unexpr_plus(unary_expression_t *expression) "traditional C rejects the unary plus operator"); } +static expression_t const *get_reference_address(expression_t const *expr) +{ + bool regular_take_address = true; + for (;;) { + if (expr->kind == EXPR_UNARY_TAKE_ADDRESS) { + expr = expr->unary.value; + } else { + regular_take_address = false; + } + + if (expr->kind != EXPR_UNARY_DEREFERENCE) + break; + + expr = expr->unary.value; + } + + if (expr->kind != EXPR_REFERENCE) + return NULL; + + if (!regular_take_address && + !is_type_function(skip_typeref(expr->reference.declaration->type))) { + return NULL; + } + + return expr; +} + +static void warn_function_address_as_bool(expression_t const* expr) +{ + if (!warning.address) + return; + + expr = get_reference_address(expr); + if (expr != NULL) { + warningf(&expr->base.source_position, + "the address of '%Y' will always evaluate as 'true'", + expr->reference.declaration->symbol); + } +} + static void semantic_not(unary_expression_t *expression) { type_t *const orig_type = expression->value->base.type; @@ -7490,6 +7783,8 @@ static void semantic_not(unary_expression_t *expression) "operand of ! must be of scalar type"); } + warn_function_address_as_bool(expression->value); + expression->base.type = type_int; } @@ -7559,7 +7854,7 @@ static void semantic_take_addr(unary_expression_t *expression) value->base.type = revert_automatic_type_conversion(value); type_t *orig_type = value->base.type; - if (!is_type_valid(orig_type)) + if (!is_type_valid(skip_typeref(orig_type))) return; set_address_taken(value, false); @@ -7567,18 +7862,18 @@ static void semantic_take_addr(unary_expression_t *expression) expression->base.type = make_pointer_type(orig_type, TYPE_QUALIFIER_NONE); } -#define CREATE_UNARY_EXPRESSION_PARSER(token_type, unexpression_type, sfunc) \ -static expression_t *parse_##unexpression_type(unsigned precedence) \ -{ \ - expression_t *unary_expression \ - = allocate_expression_zero(unexpression_type); \ - unary_expression->base.source_position = *HERE; \ - eat(token_type); \ - unary_expression->unary.value = parse_sub_expression(precedence); \ - \ - sfunc(&unary_expression->unary); \ - \ - return unary_expression; \ +#define CREATE_UNARY_EXPRESSION_PARSER(token_type, unexpression_type, sfunc) \ +static expression_t *parse_##unexpression_type(void) \ +{ \ + expression_t *unary_expression \ + = allocate_expression_zero(unexpression_type); \ + unary_expression->base.source_position = *HERE; \ + eat(token_type); \ + unary_expression->unary.value = parse_sub_expression(PREC_UNARY); \ + \ + sfunc(&unary_expression->unary); \ + \ + return unary_expression; \ } CREATE_UNARY_EXPRESSION_PARSER('-', EXPR_UNARY_NEGATE, @@ -7600,11 +7895,8 @@ CREATE_UNARY_EXPRESSION_PARSER(T_MINUSMINUS, EXPR_UNARY_PREFIX_DECREMENT, #define CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(token_type, unexpression_type, \ sfunc) \ -static expression_t *parse_##unexpression_type(unsigned precedence, \ - expression_t *left) \ +static expression_t *parse_##unexpression_type(expression_t *left) \ { \ - (void) precedence; \ - \ expression_t *unary_expression \ = allocate_expression_zero(unexpression_type); \ unary_expression->base.source_position = *HERE; \ @@ -7823,11 +8115,11 @@ static void semantic_sub(binary_expression_t *expression) "subtracting pointers to incompatible types '%T' and '%T'", orig_type_left, orig_type_right); } else if (!is_type_object(unqual_left)) { - if (is_type_atomic(unqual_left, ATOMIC_TYPE_VOID)) { - warningf(pos, "subtracting pointers to void"); - } else { + if (!is_type_atomic(unqual_left, ATOMIC_TYPE_VOID)) { errorf(pos, "subtracting pointers to non-object types '%T'", orig_type_left); + } else if (warning.other) { + warningf(pos, "subtracting pointers to void"); } } expression->base.type = type_ptrdiff_t; @@ -7837,6 +8129,22 @@ static void semantic_sub(binary_expression_t *expression) } } +static void warn_string_literal_address(expression_t const* expr) +{ + while (expr->kind == EXPR_UNARY_TAKE_ADDRESS) { + expr = expr->unary.value; + if (expr->kind != EXPR_UNARY_DEREFERENCE) + return; + expr = expr->unary.value; + } + + if (expr->kind == EXPR_STRING_LITERAL || + expr->kind == EXPR_WIDE_STRING_LITERAL) { + warningf(&expr->base.source_position, + "comparison with string literal results in unspecified behaviour"); + } +} + /** * Check the semantics of comparison expressions. * @@ -7844,13 +8152,32 @@ static void semantic_sub(binary_expression_t *expression) */ static void semantic_comparison(binary_expression_t *expression) { - expression_t *left = expression->left; - expression_t *right = expression->right; - type_t *orig_type_left = left->base.type; - type_t *orig_type_right = right->base.type; + expression_t *left = expression->left; + expression_t *right = expression->right; - type_t *type_left = skip_typeref(orig_type_left); - type_t *type_right = skip_typeref(orig_type_right); + if (warning.address) { + warn_string_literal_address(left); + warn_string_literal_address(right); + + expression_t const* const func_left = get_reference_address(left); + if (func_left != NULL && is_null_pointer_constant(right)) { + warningf(&expression->base.source_position, + "the address of '%Y' will never be NULL", + func_left->reference.declaration->symbol); + } + + expression_t const* const func_right = get_reference_address(right); + if (func_right != NULL && is_null_pointer_constant(right)) { + warningf(&expression->base.source_position, + "the address of '%Y' will never be NULL", + func_right->reference.declaration->symbol); + } + } + + type_t *orig_type_left = left->base.type; + type_t *orig_type_right = right->base.type; + type_t *type_left = skip_typeref(orig_type_left); + type_t *type_right = skip_typeref(orig_type_right); /* TODO non-arithmetic types */ if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) { @@ -8043,6 +8370,9 @@ static void semantic_logical_op(binary_expression_t *expression) type_t *const type_left = skip_typeref(orig_type_left); type_t *const type_right = skip_typeref(orig_type_right); + warn_function_address_as_bool(left); + warn_function_address_as_bool(right); + if (!is_type_scalar(type_left) || !is_type_scalar(type_right)) { /* TODO: improve error message */ if (is_type_valid(type_left) && is_type_valid(type_right)) { @@ -8218,78 +8548,58 @@ static void semantic_comma(binary_expression_t *expression) expression->base.type = expression->right->base.type; } -#define CREATE_BINEXPR_PARSER(token_type, binexpression_type, sfunc, lr) \ -static expression_t *parse_##binexpression_type(unsigned precedence, \ - expression_t *left) \ -{ \ - expression_t *binexpr = allocate_expression_zero(binexpression_type); \ - binexpr->base.source_position = *HERE; \ - binexpr->binary.left = left; \ - eat(token_type); \ - \ - expression_t *right = parse_sub_expression(precedence + lr); \ - \ - binexpr->binary.right = right; \ - sfunc(&binexpr->binary); \ - \ - return binexpr; \ -} - -CREATE_BINEXPR_PARSER(',', EXPR_BINARY_COMMA, semantic_comma, 1) -CREATE_BINEXPR_PARSER('*', EXPR_BINARY_MUL, semantic_binexpr_arithmetic, 1) -CREATE_BINEXPR_PARSER('/', EXPR_BINARY_DIV, semantic_divmod_arithmetic, 1) -CREATE_BINEXPR_PARSER('%', EXPR_BINARY_MOD, semantic_divmod_arithmetic, 1) -CREATE_BINEXPR_PARSER('+', EXPR_BINARY_ADD, semantic_add, 1) -CREATE_BINEXPR_PARSER('-', EXPR_BINARY_SUB, semantic_sub, 1) -CREATE_BINEXPR_PARSER('<', EXPR_BINARY_LESS, semantic_comparison, 1) -CREATE_BINEXPR_PARSER('>', EXPR_BINARY_GREATER, semantic_comparison, 1) -CREATE_BINEXPR_PARSER('=', EXPR_BINARY_ASSIGN, semantic_binexpr_assign, 0) - -CREATE_BINEXPR_PARSER(T_EQUALEQUAL, EXPR_BINARY_EQUAL, - semantic_comparison, 1) -CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, EXPR_BINARY_NOTEQUAL, - semantic_comparison, 1) -CREATE_BINEXPR_PARSER(T_LESSEQUAL, EXPR_BINARY_LESSEQUAL, - semantic_comparison, 1) -CREATE_BINEXPR_PARSER(T_GREATEREQUAL, EXPR_BINARY_GREATEREQUAL, - semantic_comparison, 1) - -CREATE_BINEXPR_PARSER('&', EXPR_BINARY_BITWISE_AND, - semantic_binexpr_arithmetic, 1) -CREATE_BINEXPR_PARSER('|', EXPR_BINARY_BITWISE_OR, - semantic_binexpr_arithmetic, 1) -CREATE_BINEXPR_PARSER('^', EXPR_BINARY_BITWISE_XOR, - semantic_binexpr_arithmetic, 1) -CREATE_BINEXPR_PARSER(T_ANDAND, EXPR_BINARY_LOGICAL_AND, - semantic_logical_op, 1) -CREATE_BINEXPR_PARSER(T_PIPEPIPE, EXPR_BINARY_LOGICAL_OR, - semantic_logical_op, 1) -CREATE_BINEXPR_PARSER(T_LESSLESS, EXPR_BINARY_SHIFTLEFT, - semantic_shift_op, 1) -CREATE_BINEXPR_PARSER(T_GREATERGREATER, EXPR_BINARY_SHIFTRIGHT, - semantic_shift_op, 1) -CREATE_BINEXPR_PARSER(T_PLUSEQUAL, EXPR_BINARY_ADD_ASSIGN, - semantic_arithmetic_addsubb_assign, 0) -CREATE_BINEXPR_PARSER(T_MINUSEQUAL, EXPR_BINARY_SUB_ASSIGN, - semantic_arithmetic_addsubb_assign, 0) -CREATE_BINEXPR_PARSER(T_ASTERISKEQUAL, EXPR_BINARY_MUL_ASSIGN, - semantic_arithmetic_assign, 0) -CREATE_BINEXPR_PARSER(T_SLASHEQUAL, EXPR_BINARY_DIV_ASSIGN, - semantic_divmod_assign, 0) -CREATE_BINEXPR_PARSER(T_PERCENTEQUAL, EXPR_BINARY_MOD_ASSIGN, - semantic_divmod_assign, 0) -CREATE_BINEXPR_PARSER(T_LESSLESSEQUAL, EXPR_BINARY_SHIFTLEFT_ASSIGN, - semantic_arithmetic_assign, 0) -CREATE_BINEXPR_PARSER(T_GREATERGREATEREQUAL, EXPR_BINARY_SHIFTRIGHT_ASSIGN, - semantic_arithmetic_assign, 0) -CREATE_BINEXPR_PARSER(T_ANDEQUAL, EXPR_BINARY_BITWISE_AND_ASSIGN, - semantic_arithmetic_assign, 0) -CREATE_BINEXPR_PARSER(T_PIPEEQUAL, EXPR_BINARY_BITWISE_OR_ASSIGN, - semantic_arithmetic_assign, 0) -CREATE_BINEXPR_PARSER(T_CARETEQUAL, EXPR_BINARY_BITWISE_XOR_ASSIGN, - semantic_arithmetic_assign, 0) - -static expression_t *parse_sub_expression(unsigned precedence) +/** + * @param prec_r precedence of the right operand + */ +#define CREATE_BINEXPR_PARSER(token_type, binexpression_type, prec_r, sfunc) \ +static expression_t *parse_##binexpression_type(expression_t *left) \ +{ \ + expression_t *binexpr = allocate_expression_zero(binexpression_type); \ + binexpr->base.source_position = *HERE; \ + binexpr->binary.left = left; \ + eat(token_type); \ + \ + expression_t *right = parse_sub_expression(prec_r); \ + \ + binexpr->binary.right = right; \ + sfunc(&binexpr->binary); \ + \ + return binexpr; \ +} + +CREATE_BINEXPR_PARSER('*', EXPR_BINARY_MUL, PREC_CAST, semantic_binexpr_arithmetic) +CREATE_BINEXPR_PARSER('/', EXPR_BINARY_DIV, PREC_CAST, semantic_divmod_arithmetic) +CREATE_BINEXPR_PARSER('%', EXPR_BINARY_MOD, PREC_CAST, semantic_divmod_arithmetic) +CREATE_BINEXPR_PARSER('+', EXPR_BINARY_ADD, PREC_MULTIPLICATIVE, semantic_add) +CREATE_BINEXPR_PARSER('-', EXPR_BINARY_SUB, PREC_MULTIPLICATIVE, semantic_sub) +CREATE_BINEXPR_PARSER(T_LESSLESS, EXPR_BINARY_SHIFTLEFT, PREC_ADDITIVE, semantic_shift_op) +CREATE_BINEXPR_PARSER(T_GREATERGREATER, EXPR_BINARY_SHIFTRIGHT, PREC_ADDITIVE, semantic_shift_op) +CREATE_BINEXPR_PARSER('<', EXPR_BINARY_LESS, PREC_SHIFT, semantic_comparison) +CREATE_BINEXPR_PARSER('>', EXPR_BINARY_GREATER, PREC_SHIFT, semantic_comparison) +CREATE_BINEXPR_PARSER(T_LESSEQUAL, EXPR_BINARY_LESSEQUAL, PREC_SHIFT, semantic_comparison) +CREATE_BINEXPR_PARSER(T_GREATEREQUAL, EXPR_BINARY_GREATEREQUAL, PREC_SHIFT, semantic_comparison) +CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, EXPR_BINARY_NOTEQUAL, PREC_RELATIONAL, semantic_comparison) +CREATE_BINEXPR_PARSER(T_EQUALEQUAL, EXPR_BINARY_EQUAL, PREC_RELATIONAL, semantic_comparison) +CREATE_BINEXPR_PARSER('&', EXPR_BINARY_BITWISE_AND, PREC_EQUALITY, semantic_binexpr_arithmetic) +CREATE_BINEXPR_PARSER('^', EXPR_BINARY_BITWISE_XOR, PREC_AND, semantic_binexpr_arithmetic) +CREATE_BINEXPR_PARSER('|', EXPR_BINARY_BITWISE_OR, PREC_XOR, semantic_binexpr_arithmetic) +CREATE_BINEXPR_PARSER(T_ANDAND, EXPR_BINARY_LOGICAL_AND, PREC_OR, semantic_logical_op) +CREATE_BINEXPR_PARSER(T_PIPEPIPE, EXPR_BINARY_LOGICAL_OR, PREC_LOGICAL_AND, semantic_logical_op) +CREATE_BINEXPR_PARSER('=', EXPR_BINARY_ASSIGN, PREC_ASSIGNMENT, semantic_binexpr_assign) +CREATE_BINEXPR_PARSER(T_PLUSEQUAL, EXPR_BINARY_ADD_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_addsubb_assign) +CREATE_BINEXPR_PARSER(T_MINUSEQUAL, EXPR_BINARY_SUB_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_addsubb_assign) +CREATE_BINEXPR_PARSER(T_ASTERISKEQUAL, EXPR_BINARY_MUL_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign) +CREATE_BINEXPR_PARSER(T_SLASHEQUAL, EXPR_BINARY_DIV_ASSIGN, PREC_ASSIGNMENT, semantic_divmod_assign) +CREATE_BINEXPR_PARSER(T_PERCENTEQUAL, EXPR_BINARY_MOD_ASSIGN, PREC_ASSIGNMENT, semantic_divmod_assign) +CREATE_BINEXPR_PARSER(T_LESSLESSEQUAL, EXPR_BINARY_SHIFTLEFT_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign) +CREATE_BINEXPR_PARSER(T_GREATERGREATEREQUAL, EXPR_BINARY_SHIFTRIGHT_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign) +CREATE_BINEXPR_PARSER(T_ANDEQUAL, EXPR_BINARY_BITWISE_AND_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign) +CREATE_BINEXPR_PARSER(T_PIPEEQUAL, EXPR_BINARY_BITWISE_OR_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign) +CREATE_BINEXPR_PARSER(T_CARETEQUAL, EXPR_BINARY_BITWISE_XOR_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign) +CREATE_BINEXPR_PARSER(',', EXPR_BINARY_COMMA, PREC_ASSIGNMENT, semantic_comma) + + +static expression_t *parse_sub_expression(precedence_t precedence) { if (token.type < 0) { return expected_expression_error(); @@ -8301,7 +8611,7 @@ static expression_t *parse_sub_expression(unsigned precedence) expression_t *left; if (parser->parser != NULL) { - left = parser->parser(parser->precedence); + left = parser->parser(); } else { left = parse_primary_expression(); } @@ -8319,7 +8629,7 @@ static expression_t *parse_sub_expression(unsigned precedence) if (parser->infix_precedence < precedence) break; - left = parser->infix_parser(parser->infix_precedence, left); + left = parser->infix_parser(left); assert(left != NULL); assert(left->kind != EXPR_UNKNOWN); @@ -8334,18 +8644,17 @@ static expression_t *parse_sub_expression(unsigned precedence) */ static expression_t *parse_expression(void) { - return parse_sub_expression(1); + return parse_sub_expression(PREC_EXPRESSION); } /** - * Register a parser for a prefix-like operator with given precedence. + * Register a parser for a prefix-like operator. * * @param parser the parser function * @param token_type the token type of the prefix token - * @param precedence the precedence of the operator */ static void register_expression_parser(parse_expression_function parser, - int token_type, unsigned precedence) + int token_type) { expression_parser_function_t *entry = &expression_parsers[token_type]; @@ -8353,8 +8662,7 @@ static void register_expression_parser(parse_expression_function parser, diagnosticf("for token '%k'\n", (token_type_t)token_type); panic("trying to register multiple expression parsers for a token"); } - entry->parser = parser; - entry->precedence = precedence; + entry->parser = parser; } /** @@ -8385,69 +8693,56 @@ static void init_expression_parsers(void) { memset(&expression_parsers, 0, sizeof(expression_parsers)); - register_infix_parser(parse_array_expression, '[', 30); - register_infix_parser(parse_call_expression, '(', 30); - register_infix_parser(parse_select_expression, '.', 30); - register_infix_parser(parse_select_expression, T_MINUSGREATER, 30); - register_infix_parser(parse_EXPR_UNARY_POSTFIX_INCREMENT, - T_PLUSPLUS, 30); - register_infix_parser(parse_EXPR_UNARY_POSTFIX_DECREMENT, - T_MINUSMINUS, 30); - - register_infix_parser(parse_EXPR_BINARY_MUL, '*', 17); - register_infix_parser(parse_EXPR_BINARY_DIV, '/', 17); - register_infix_parser(parse_EXPR_BINARY_MOD, '%', 17); - register_infix_parser(parse_EXPR_BINARY_ADD, '+', 16); - register_infix_parser(parse_EXPR_BINARY_SUB, '-', 16); - register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT, T_LESSLESS, 15); - register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT, T_GREATERGREATER, 15); - register_infix_parser(parse_EXPR_BINARY_LESS, '<', 14); - register_infix_parser(parse_EXPR_BINARY_GREATER, '>', 14); - register_infix_parser(parse_EXPR_BINARY_LESSEQUAL, T_LESSEQUAL, 14); - register_infix_parser(parse_EXPR_BINARY_GREATEREQUAL, T_GREATEREQUAL, 14); - register_infix_parser(parse_EXPR_BINARY_EQUAL, T_EQUALEQUAL, 13); - register_infix_parser(parse_EXPR_BINARY_NOTEQUAL, - T_EXCLAMATIONMARKEQUAL, 13); - register_infix_parser(parse_EXPR_BINARY_BITWISE_AND, '&', 12); - register_infix_parser(parse_EXPR_BINARY_BITWISE_XOR, '^', 11); - register_infix_parser(parse_EXPR_BINARY_BITWISE_OR, '|', 10); - register_infix_parser(parse_EXPR_BINARY_LOGICAL_AND, T_ANDAND, 9); - register_infix_parser(parse_EXPR_BINARY_LOGICAL_OR, T_PIPEPIPE, 8); - register_infix_parser(parse_conditional_expression, '?', 7); - register_infix_parser(parse_EXPR_BINARY_ASSIGN, '=', 2); - register_infix_parser(parse_EXPR_BINARY_ADD_ASSIGN, T_PLUSEQUAL, 2); - register_infix_parser(parse_EXPR_BINARY_SUB_ASSIGN, T_MINUSEQUAL, 2); - register_infix_parser(parse_EXPR_BINARY_MUL_ASSIGN, T_ASTERISKEQUAL, 2); - register_infix_parser(parse_EXPR_BINARY_DIV_ASSIGN, T_SLASHEQUAL, 2); - register_infix_parser(parse_EXPR_BINARY_MOD_ASSIGN, T_PERCENTEQUAL, 2); - register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT_ASSIGN, - T_LESSLESSEQUAL, 2); - register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT_ASSIGN, - T_GREATERGREATEREQUAL, 2); - register_infix_parser(parse_EXPR_BINARY_BITWISE_AND_ASSIGN, - T_ANDEQUAL, 2); - register_infix_parser(parse_EXPR_BINARY_BITWISE_OR_ASSIGN, - T_PIPEEQUAL, 2); - register_infix_parser(parse_EXPR_BINARY_BITWISE_XOR_ASSIGN, - T_CARETEQUAL, 2); - - register_infix_parser(parse_EXPR_BINARY_COMMA, ',', 1); - - register_expression_parser(parse_EXPR_UNARY_NEGATE, '-', 25); - register_expression_parser(parse_EXPR_UNARY_PLUS, '+', 25); - register_expression_parser(parse_EXPR_UNARY_NOT, '!', 25); - register_expression_parser(parse_EXPR_UNARY_BITWISE_NEGATE, '~', 25); - register_expression_parser(parse_EXPR_UNARY_DEREFERENCE, '*', 25); - register_expression_parser(parse_EXPR_UNARY_TAKE_ADDRESS, '&', 25); - register_expression_parser(parse_EXPR_UNARY_PREFIX_INCREMENT, - T_PLUSPLUS, 25); - register_expression_parser(parse_EXPR_UNARY_PREFIX_DECREMENT, - T_MINUSMINUS, 25); - register_expression_parser(parse_sizeof, T_sizeof, 25); - register_expression_parser(parse_alignof, T___alignof__, 25); - register_expression_parser(parse_extension, T___extension__, 25); - register_expression_parser(parse_builtin_classify_type, - T___builtin_classify_type, 25); + register_infix_parser(parse_array_expression, '[', PREC_POSTFIX); + register_infix_parser(parse_call_expression, '(', PREC_POSTFIX); + register_infix_parser(parse_select_expression, '.', PREC_POSTFIX); + register_infix_parser(parse_select_expression, T_MINUSGREATER, PREC_POSTFIX); + register_infix_parser(parse_EXPR_UNARY_POSTFIX_INCREMENT, T_PLUSPLUS, PREC_POSTFIX); + register_infix_parser(parse_EXPR_UNARY_POSTFIX_DECREMENT, T_MINUSMINUS, PREC_POSTFIX); + register_infix_parser(parse_EXPR_BINARY_MUL, '*', PREC_MULTIPLICATIVE); + register_infix_parser(parse_EXPR_BINARY_DIV, '/', PREC_MULTIPLICATIVE); + register_infix_parser(parse_EXPR_BINARY_MOD, '%', PREC_MULTIPLICATIVE); + register_infix_parser(parse_EXPR_BINARY_ADD, '+', PREC_ADDITIVE); + register_infix_parser(parse_EXPR_BINARY_SUB, '-', PREC_ADDITIVE); + register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT, T_LESSLESS, PREC_SHIFT); + register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT, T_GREATERGREATER, PREC_SHIFT); + register_infix_parser(parse_EXPR_BINARY_LESS, '<', PREC_RELATIONAL); + register_infix_parser(parse_EXPR_BINARY_GREATER, '>', PREC_RELATIONAL); + register_infix_parser(parse_EXPR_BINARY_LESSEQUAL, T_LESSEQUAL, PREC_RELATIONAL); + register_infix_parser(parse_EXPR_BINARY_GREATEREQUAL, T_GREATEREQUAL, PREC_RELATIONAL); + register_infix_parser(parse_EXPR_BINARY_EQUAL, T_EQUALEQUAL, PREC_EQUALITY); + register_infix_parser(parse_EXPR_BINARY_NOTEQUAL, T_EXCLAMATIONMARKEQUAL, PREC_EQUALITY); + register_infix_parser(parse_EXPR_BINARY_BITWISE_AND, '&', PREC_AND); + register_infix_parser(parse_EXPR_BINARY_BITWISE_XOR, '^', PREC_XOR); + register_infix_parser(parse_EXPR_BINARY_BITWISE_OR, '|', PREC_OR); + register_infix_parser(parse_EXPR_BINARY_LOGICAL_AND, T_ANDAND, PREC_LOGICAL_AND); + register_infix_parser(parse_EXPR_BINARY_LOGICAL_OR, T_PIPEPIPE, PREC_LOGICAL_OR); + register_infix_parser(parse_conditional_expression, '?', PREC_CONDITIONAL); + register_infix_parser(parse_EXPR_BINARY_ASSIGN, '=', PREC_ASSIGNMENT); + register_infix_parser(parse_EXPR_BINARY_ADD_ASSIGN, T_PLUSEQUAL, PREC_ASSIGNMENT); + register_infix_parser(parse_EXPR_BINARY_SUB_ASSIGN, T_MINUSEQUAL, PREC_ASSIGNMENT); + register_infix_parser(parse_EXPR_BINARY_MUL_ASSIGN, T_ASTERISKEQUAL, PREC_ASSIGNMENT); + register_infix_parser(parse_EXPR_BINARY_DIV_ASSIGN, T_SLASHEQUAL, PREC_ASSIGNMENT); + register_infix_parser(parse_EXPR_BINARY_MOD_ASSIGN, T_PERCENTEQUAL, PREC_ASSIGNMENT); + register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT_ASSIGN, T_LESSLESSEQUAL, PREC_ASSIGNMENT); + register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT_ASSIGN, T_GREATERGREATEREQUAL, PREC_ASSIGNMENT); + register_infix_parser(parse_EXPR_BINARY_BITWISE_AND_ASSIGN, T_ANDEQUAL, PREC_ASSIGNMENT); + register_infix_parser(parse_EXPR_BINARY_BITWISE_OR_ASSIGN, T_PIPEEQUAL, PREC_ASSIGNMENT); + register_infix_parser(parse_EXPR_BINARY_BITWISE_XOR_ASSIGN, T_CARETEQUAL, PREC_ASSIGNMENT); + register_infix_parser(parse_EXPR_BINARY_COMMA, ',', PREC_EXPRESSION); + + register_expression_parser(parse_EXPR_UNARY_NEGATE, '-'); + register_expression_parser(parse_EXPR_UNARY_PLUS, '+'); + register_expression_parser(parse_EXPR_UNARY_NOT, '!'); + register_expression_parser(parse_EXPR_UNARY_BITWISE_NEGATE, '~'); + register_expression_parser(parse_EXPR_UNARY_DEREFERENCE, '*'); + register_expression_parser(parse_EXPR_UNARY_TAKE_ADDRESS, '&'); + register_expression_parser(parse_EXPR_UNARY_PREFIX_INCREMENT, T_PLUSPLUS); + register_expression_parser(parse_EXPR_UNARY_PREFIX_DECREMENT, T_MINUSMINUS); + register_expression_parser(parse_sizeof, T_sizeof); + register_expression_parser(parse_alignof, T___alignof__); + register_expression_parser(parse_extension, T___extension__); + register_expression_parser(parse_builtin_classify_type, T___builtin_classify_type); } /** @@ -8528,6 +8823,11 @@ static asm_argument_t *parse_asm_arguments(bool is_out) errorf(&expression->base.source_position, "asm output argument is not an lvalue"); } + + if (argument->constraints.begin[0] == '+') + mark_decls_read(expression, NULL); + } else { + mark_decls_read(expression, NULL); } argument->expression = expression; expect(')'); @@ -8583,13 +8883,11 @@ static asm_clobber_t *parse_asm_clobbers(void) */ static statement_t *parse_asm_statement(void) { - eat(T_asm); - - statement_t *statement = allocate_statement_zero(STATEMENT_ASM); - statement->base.source_position = token.source_position; - + statement_t *statement = allocate_statement_zero(STATEMENT_ASM); asm_statement_t *asm_statement = &statement->asms; + eat(T_asm); + if (token.type == T_volatile) { next_token(); asm_statement->is_volatile = true; @@ -8644,19 +8942,18 @@ end_error: */ static statement_t *parse_case_statement(void) { - eat(T_case); - statement_t *const statement = allocate_statement_zero(STATEMENT_CASE_LABEL); source_position_t *const pos = &statement->base.source_position; - *pos = token.source_position; + eat(T_case); + expression_t *const expression = parse_expression(); statement->case_label.expression = expression; if (!is_constant_expression(expression)) { /* This check does not prevent the error message in all cases of an * prior error while parsing the expression. At least it catches the * common case of a mistyped enum entry. */ - if (is_type_valid(expression->base.type)) { + if (is_type_valid(skip_typeref(expression->base.type))) { errorf(pos, "case label does not reduce to an integer constant"); } statement->case_label.is_bad = true; @@ -8666,7 +8963,7 @@ static statement_t *parse_case_statement(void) statement->case_label.last_case = val; } - if (c_mode & _GNUC) { + if (GNU_MODE) { if (token.type == T_DOTDOTDOT) { next_token(); expression_t *const end_range = parse_expression(); @@ -8675,7 +8972,7 @@ static statement_t *parse_case_statement(void) /* This check does not prevent the error message in all cases of an * prior error while parsing the expression. At least it catches the * common case of a mistyped enum entry. */ - if (is_type_valid(end_range->base.type)) { + if (is_type_valid(skip_typeref(end_range->base.type))) { errorf(pos, "case range does not reduce to an integer constant"); } statement->case_label.is_bad = true; @@ -8683,7 +8980,7 @@ static statement_t *parse_case_statement(void) long const val = fold_constant(end_range); statement->case_label.last_case = val; - if (val < statement->case_label.first_case) { + if (warning.other && val < statement->case_label.first_case) { statement->case_label.is_empty_range = true; warningf(pos, "empty range specified"); } @@ -8740,10 +9037,9 @@ end_error: */ static statement_t *parse_default_statement(void) { - eat(T_default); - statement_t *statement = allocate_statement_zero(STATEMENT_CASE_LABEL); - statement->base.source_position = token.source_position; + + eat(T_default); PUSH_PARENT(statement); @@ -8788,14 +9084,13 @@ end_error: static statement_t *parse_label_statement(void) { assert(token.type == T_IDENTIFIER); - symbol_t *symbol = token.v.symbol; - next_token(); - - declaration_t *label = get_label(symbol); + symbol_t *symbol = token.v.symbol; + declaration_t *label = get_label(symbol); statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL); - statement->base.source_position = token.source_position; - statement->label.label = label; + statement->label.label = label; + + next_token(); PUSH_PARENT(statement); @@ -8813,7 +9108,7 @@ static statement_t *parse_label_statement(void) if (token.type == '}') { /* TODO only warn? */ - if (false) { + if (warning.other && false) { warningf(HERE, "label at end of compound statement"); statement->label.statement = create_empty_statement(); } else { @@ -8851,19 +9146,25 @@ static statement_t *parse_label_statement(void) */ static statement_t *parse_if(void) { - eat(T_if); + statement_t *statement = allocate_statement_zero(STATEMENT_IF); - statement_t *statement = allocate_statement_zero(STATEMENT_IF); - statement->base.source_position = token.source_position; + eat(T_if); PUSH_PARENT(statement); + add_anchor_token('{'); + expect('('); add_anchor_token(')'); - statement->ifs.condition = parse_expression(); + expression_t *const expr = parse_expression(); + statement->ifs.condition = expr; + mark_decls_read(expr, NULL); rem_anchor_token(')'); expect(')'); +end_error: + rem_anchor_token('{'); + add_anchor_token(T_else); statement->ifs.true_statement = parse_statement(); rem_anchor_token(T_else); @@ -8875,9 +9176,6 @@ static statement_t *parse_if(void) POP_PARENT; return statement; -end_error: - POP_PARENT; - return create_invalid_statement(); } /** @@ -8925,16 +9223,16 @@ static void check_enum_cases(const switch_statement_t *statement) { */ static statement_t *parse_switch(void) { - eat(T_switch); + statement_t *statement = allocate_statement_zero(STATEMENT_SWITCH); - statement_t *statement = allocate_statement_zero(STATEMENT_SWITCH); - statement->base.source_position = token.source_position; + eat(T_switch); PUSH_PARENT(statement); expect('('); add_anchor_token(')'); expression_t *const expr = parse_expression(); + mark_decls_read(expr, NULL); type_t * type = skip_typeref(expr->base.type); if (is_type_integer(type)) { type = promote_integer(type); @@ -8989,16 +9287,17 @@ static statement_t *parse_loop_body(statement_t *const loop) */ static statement_t *parse_while(void) { - eat(T_while); + statement_t *statement = allocate_statement_zero(STATEMENT_WHILE); - statement_t *statement = allocate_statement_zero(STATEMENT_WHILE); - statement->base.source_position = token.source_position; + eat(T_while); PUSH_PARENT(statement); expect('('); add_anchor_token(')'); - statement->whiles.condition = parse_expression(); + expression_t *const cond = parse_expression(); + statement->whiles.condition = cond; + mark_decls_read(cond, NULL); rem_anchor_token(')'); expect(')'); @@ -9016,12 +9315,11 @@ end_error: */ static statement_t *parse_do(void) { - eat(T_do); - statement_t *statement = allocate_statement_zero(STATEMENT_DO_WHILE); - statement->base.source_position = token.source_position; - PUSH_PARENT(statement) + eat(T_do); + + PUSH_PARENT(statement); add_anchor_token(T_while); statement->do_while.body = parse_loop_body(statement); @@ -9030,7 +9328,9 @@ static statement_t *parse_do(void) expect(T_while); expect('('); add_anchor_token(')'); - statement->do_while.condition = parse_expression(); + expression_t *const cond = parse_expression(); + statement->do_while.condition = cond; + mark_decls_read(cond, NULL); rem_anchor_token(')'); expect(')'); expect(';'); @@ -9047,16 +9347,14 @@ end_error: */ static statement_t *parse_for(void) { - eat(T_for); + statement_t *statement = allocate_statement_zero(STATEMENT_FOR); - statement_t *statement = allocate_statement_zero(STATEMENT_FOR); - statement->base.source_position = token.source_position; + eat(T_for); PUSH_PARENT(statement); - int top = environment_top(); - scope_t *last_scope = scope; - set_scope(&statement->fors.scope); + size_t const top = environment_top(); + scope_push(&statement->fors.scope); expect('('); add_anchor_token(')'); @@ -9068,6 +9366,7 @@ static statement_t *parse_for(void) add_anchor_token(';'); expression_t *const init = parse_expression(); statement->fors.initialisation = init; + mark_decls_read(init, DECL_ANY); if (warning.unused_value && !expression_has_effect(init)) { warningf(&init->base.source_position, "initialisation of 'for'-statement has no effect"); @@ -9081,13 +9380,16 @@ static statement_t *parse_for(void) if (token.type != ';') { add_anchor_token(';'); - statement->fors.condition = parse_expression(); + expression_t *const cond = parse_expression(); + statement->fors.condition = cond; + mark_decls_read(cond, NULL); rem_anchor_token(';'); } expect(';'); if (token.type != ')') { expression_t *const step = parse_expression(); statement->fors.step = step; + mark_decls_read(step, DECL_ANY); if (warning.unused_value && !expression_has_effect(step)) { warningf(&step->base.source_position, "step of 'for'-statement has no effect"); @@ -9098,7 +9400,7 @@ static statement_t *parse_for(void) statement->fors.body = parse_loop_body(statement); assert(scope == &statement->fors.scope); - set_scope(last_scope); + scope_pop(); environment_pop_to(top); POP_PARENT; @@ -9108,7 +9410,7 @@ end_error: POP_PARENT; rem_anchor_token(')'); assert(scope == &statement->fors.scope); - set_scope(last_scope); + scope_pop(); environment_pop_to(top); return create_invalid_statement(); @@ -9119,13 +9421,13 @@ end_error: */ static statement_t *parse_goto(void) { - source_position_t source_position = token.source_position; + statement_t *statement = allocate_statement_zero(STATEMENT_GOTO); eat(T_goto); - statement_t *statement; - if (c_mode & _GNUC && token.type == '*') { + if (GNU_MODE && token.type == '*') { next_token(); expression_t *expression = parse_expression(); + mark_decls_read(expression, NULL); /* Argh: although documentation say the expression must be of type void *, * gcc excepts anything that can be casted into void * without error */ @@ -9133,32 +9435,29 @@ static statement_t *parse_goto(void) if (type != type_error_type) { if (!is_type_pointer(type) && !is_type_integer(type)) { - errorf(&source_position, "cannot convert to a pointer type"); - } else if (type != type_void_ptr) { - warningf(&source_position, + errorf(&expression->base.source_position, + "cannot convert to a pointer type"); + } else if (warning.other && type != type_void_ptr) { + warningf(&expression->base.source_position, "type of computed goto expression should be 'void*' not '%T'", type); } expression = create_implicit_cast(expression, type_void_ptr); } - statement = allocate_statement_zero(STATEMENT_GOTO); - statement->base.source_position = source_position; - statement->gotos.expression = expression; + statement->gotos.expression = expression; } else { if (token.type != T_IDENTIFIER) { - if (c_mode & _GNUC) + if (GNU_MODE) parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL); else parse_error_expected("while parsing goto", T_IDENTIFIER, NULL); - eat_statement(); + eat_until_anchor(); goto end_error; } symbol_t *symbol = token.v.symbol; next_token(); - statement = allocate_statement_zero(STATEMENT_GOTO); - statement->base.source_position = source_position; - statement->gotos.label = get_label(symbol); + statement->gotos.label = get_label(symbol); } /* remember the goto's in a list for later checking */ @@ -9186,7 +9485,6 @@ static statement_t *parse_continue(void) } statement_t *statement = allocate_statement_zero(STATEMENT_CONTINUE); - statement->base.source_position = token.source_position; eat(T_continue); expect(';'); @@ -9205,7 +9503,6 @@ static statement_t *parse_break(void) } statement_t *statement = allocate_statement_zero(STATEMENT_BREAK); - statement->base.source_position = token.source_position; eat(T_break); expect(';'); @@ -9224,7 +9521,6 @@ static statement_t *parse_leave_statement(void) } statement_t *statement = allocate_statement_zero(STATEMENT_LEAVE); - statement->base.source_position = token.source_position; eat(T___leave); expect(';'); @@ -9297,14 +9593,14 @@ declaration_t *expr_is_variable(const expression_t *expression) */ static statement_t *parse_return(void) { - statement_t *statement = allocate_statement_zero(STATEMENT_RETURN); - statement->base.source_position = token.source_position; - eat(T_return); + statement_t *statement = allocate_statement_zero(STATEMENT_RETURN); + expression_t *return_value = NULL; if (token.type != ';') { return_value = parse_expression(); + mark_decls_read(return_value, NULL); } const type_t *const func_type = current_function->type; @@ -9314,10 +9610,12 @@ static statement_t *parse_return(void) if (return_value != NULL) { type_t *return_value_type = skip_typeref(return_value->base.type); - if (is_type_atomic(return_type, ATOMIC_TYPE_VOID) - && !is_type_atomic(return_value_type, ATOMIC_TYPE_VOID)) { - warningf(&statement->base.source_position, - "'return' with a value, in function returning void"); + if (is_type_atomic(return_type, ATOMIC_TYPE_VOID) && + !is_type_atomic(return_value_type, ATOMIC_TYPE_VOID)) { + if (warning.other) { + warningf(&statement->base.source_position, + "'return' with a value, in function returning void"); + } return_value = NULL; } else { assign_error_t error = semantic_assign(return_type, return_value); @@ -9326,7 +9624,8 @@ static statement_t *parse_return(void) return_value = create_implicit_cast(return_value, return_type); } /* check for returning address of a local var */ - if (return_value != NULL && + if (warning.other && + return_value != NULL && return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) { const expression_t *expression = return_value->unary.value; if (is_local_variable(expression)) { @@ -9334,11 +9633,9 @@ static statement_t *parse_return(void) "function returns address of local variable"); } } - } else { - if (!is_type_atomic(return_type, ATOMIC_TYPE_VOID)) { - warningf(&statement->base.source_position, - "'return' without value, in function returning non-void"); - } + } else if (warning.other && !is_type_atomic(return_type, ATOMIC_TYPE_VOID)) { + warningf(&statement->base.source_position, + "'return' without value, in function returning non-void"); } statement->returns.value = return_value; @@ -9355,10 +9652,11 @@ static statement_t *parse_declaration_statement(void) { statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION); - statement->base.source_position = token.source_position; - declaration_t *before = last_declaration; - parse_declaration(record_declaration); + if (GNU_MODE) + parse_external_declaration(); + else + parse_declaration(record_declaration); if (before == NULL) { statement->declaration.declarations_begin = scope->declarations; @@ -9377,9 +9675,9 @@ static statement_t *parse_expression_statement(void) { statement_t *statement = allocate_statement_zero(STATEMENT_EXPRESSION); - statement->base.source_position = token.source_position; expression_t *const expr = parse_expression(); statement->expression.expression = expr; + mark_decls_read(expr, DECL_ANY); expect(';'); @@ -9394,7 +9692,6 @@ end_error: static statement_t *parse_ms_try_statment(void) { statement_t *statement = allocate_statement_zero(STATEMENT_MS_TRY); - statement->base.source_position = token.source_position; eat(T___try); PUSH_PARENT(statement); @@ -9411,6 +9708,7 @@ static statement_t *parse_ms_try_statment(void) expect('('); add_anchor_token(')'); expression_t *const expr = parse_expression(); + mark_decls_read(expr, NULL); type_t * type = skip_typeref(expr->base.type); if (is_type_integer(type)) { type = promote_integer(type); @@ -9447,7 +9745,6 @@ static statement_t *parse_empty_statement(void) static statement_t *parse_local_label_declaration(void) { statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION); - statement->base.source_position = token.source_position; eat(T___label__); @@ -9536,7 +9833,10 @@ expression_statment: do { next_token(); } while (token.type == T___extension__); + bool old_gcc_extension = in_gcc_extension; + in_gcc_extension = true; statement = parse_statement(); + in_gcc_extension = old_gcc_extension; break; DECLARATION_START @@ -9559,7 +9859,7 @@ expression_statment: case T_do: statement = parse_do(); break; case T_for: statement = parse_for(); break; case T_goto: statement = parse_goto(); break; - case T_if: statement = parse_if (); break; + case T_if: statement = parse_if(); break; case T_return: statement = parse_return(); break; case T_switch: statement = parse_switch(); break; case T_while: statement = parse_while(); break; @@ -9595,9 +9895,12 @@ expression_statment: case T___builtin_islessequal: case T___builtin_islessgreater: case T___builtin_isunordered: + case T___builtin_inf: + case T___builtin_inff: + case T___builtin_infl: case T___builtin_nan: - case T___builtin_nand: case T___builtin_nanf: + case T___builtin_nanl: case T___builtin_offsetof: case T___builtin_prefetch: case T___builtin_va_arg: @@ -9651,21 +9954,24 @@ static statement_t *parse_statement(void) static statement_t *parse_compound_statement(bool inside_expression_statement) { statement_t *statement = allocate_statement_zero(STATEMENT_COMPOUND); - statement->base.source_position = token.source_position; PUSH_PARENT(statement); eat('{'); add_anchor_token('}'); - int top = environment_top(); - int top_local = local_label_top(); - scope_t *last_scope = scope; - set_scope(&statement->compound.scope); + size_t const top = environment_top(); + size_t const top_local = local_label_top(); + scope_push(&statement->compound.scope); statement_t **anchor = &statement->compound.statements; bool only_decls_so_far = true; - while (token.type != '}' && token.type != T_EOF) { + while (token.type != '}') { + if (token.type == T_EOF) { + errorf(&statement->base.source_position, + "EOF while parsing compound statement"); + break; + } statement_t *sub_statement = intern_parse_statement(); if (is_invalid_statement(sub_statement)) { /* an error occurred. if we are at an anchor, return */ @@ -9690,13 +9996,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) anchor = &sub_statement->base.next; } - - if (token.type == '}') { - next_token(); - } else { - errorf(&statement->base.source_position, - "end of file while looking for closing '}'"); - } + next_token(); /* look over all statements again to produce no effect warnings */ if (warning.unused_value) { @@ -9720,7 +10020,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) end_error: rem_anchor_token('}'); assert(scope == &statement->compound.scope); - set_scope(last_scope); + scope_pop(); environment_pop_to(top); local_label_pop_to(top_local); @@ -9748,7 +10048,7 @@ static void initialize_builtin_types(void) type_wchar_t_ptr = make_pointer_type(type_wchar_t, TYPE_QUALIFIER_NONE); /* const version of wchar_t */ - type_const_wchar_t = allocate_type_zero(TYPE_TYPEDEF, &builtin_source_position); + type_const_wchar_t = allocate_type_zero(TYPE_TYPEDEF); type_const_wchar_t->typedeft.declaration = type_wchar_t->typedeft.declaration; type_const_wchar_t->base.qualifiers |= TYPE_QUALIFIER_CONST; @@ -9763,7 +10063,7 @@ static void check_unused_globals(void) if (!warning.unused_function && !warning.unused_variable) return; - for (const declaration_t *decl = global_scope->declarations; decl != NULL; decl = decl->next) { + for (const declaration_t *decl = file_scope->declarations; decl != NULL; decl = decl->next) { if (decl->used || decl->modifiers & DM_UNUSED || decl->modifiers & DM_USED || @@ -9791,14 +10091,14 @@ static void check_unused_globals(void) static void parse_global_asm(void) { + statement_t *statement = allocate_statement_zero(STATEMENT_ASM); + eat(T_asm); expect('('); - statement_t *statement = allocate_statement_zero(STATEMENT_ASM); - statement->base.source_position = token.source_position; - statement->asms.asm_text = parse_string_literals(); - statement->base.next = unit->global_asm; - unit->global_asm = statement; + statement->asms.asm_text = parse_string_literals(); + statement->base.next = unit->global_asm; + unit->global_asm = statement; expect(')'); expect(';'); @@ -9811,16 +10111,27 @@ end_error:; */ static void parse_translation_unit(void) { + add_anchor_token(T_EOF); + +#ifndef NDEBUG + unsigned char token_anchor_copy[T_LAST_TOKEN]; + memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy)); +#endif for (;;) { #ifndef NDEBUG bool anchor_leak = false; - for (token_type_t i = 0; i != T_LAST_TOKEN; ++i) { - unsigned char count = token_anchor_set[i]; + for (int i = 0; i != T_LAST_TOKEN; ++i) { + unsigned char count = token_anchor_set[i] - token_anchor_copy[i]; if (count != 0) { errorf(HERE, "Leaked anchor token %k %d times", i, count); anchor_leak = true; } } + if (in_gcc_extension) { + errorf(HERE, "Leaked __extension__"); + anchor_leak = true; + } + if (anchor_leak) abort(); #endif @@ -9837,13 +10148,17 @@ static void parse_translation_unit(void) break; case T_EOF: + rem_anchor_token(T_EOF); return; case ';': - /* TODO error in strict mode */ - warningf(HERE, "stray ';' outside of function"); - next_token(); - break; + if (!strict_mode) { + if (warning.other) + warningf(HERE, "stray ';' outside of function"); + next_token(); + break; + } + /* FALLTHROUGH */ default: errorf(HERE, "stray %K outside of function", &token); @@ -9875,24 +10190,25 @@ void start_parsing(void) assert(unit == NULL); unit = allocate_ast_zero(sizeof(unit[0])); - assert(global_scope == NULL); - global_scope = &unit->scope; + assert(file_scope == NULL); + file_scope = &unit->scope; assert(scope == NULL); - set_scope(&unit->scope); + scope_push(&unit->scope); initialize_builtin_types(); } translation_unit_t *finish_parsing(void) { + /* do NOT use scope_pop() here, this will crash, will it by hand */ assert(scope == &unit->scope); - scope = NULL; + scope = NULL; last_declaration = NULL; - assert(global_scope == &unit->scope); + assert(file_scope == &unit->scope); check_unused_globals(); - global_scope = NULL; + file_scope = NULL; DEL_ARR_F(environment_stack); DEL_ARR_F(label_stack);