X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=e0e250301d6043e25632cfd8de0046564e864d88;hb=92253254f77e5ebb69bc7fb6acddf4b373d3eaad;hp=980d9f2eafaf5aa34deaf6cde7b43251cfeb68dc;hpb=f340c97942290d287f4a8ec2099976f7f744e8b2;p=cparser diff --git a/parser.c b/parser.c index 980d9f2..e0e2503 100644 --- a/parser.c +++ b/parser.c @@ -36,7 +36,7 @@ #include "entity_t.h" #include "attribute_t.h" #include "lang_features.h" -#include "walk_statements.h" +#include "walk.h" #include "warning.h" #include "printer.h" #include "adt/bitfiddle.h" @@ -89,7 +89,6 @@ static scope_t *current_scope = NULL; /** Point to the current function declaration if inside a function. */ static function_t *current_function = NULL; static entity_t *current_entity = NULL; -static entity_t *current_init_decl = NULL; static switch_statement_t *current_switch = NULL; static statement_t *current_loop = NULL; static statement_t *current_parent = NULL; @@ -101,28 +100,44 @@ static label_statement_t *label_first = NULL; static label_statement_t **label_anchor = 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 if we are in an __extension__ context. */ static bool in_gcc_extension = false; static struct obstack temp_obst; static entity_t *anonymous_entity; static declaration_t **incomplete_arrays; - - -#define PUSH_PARENT(stmt) \ - statement_t *const prev_parent = current_parent; \ - ((void)(current_parent = (stmt))) -#define POP_PARENT ((void)(current_parent = prev_parent)) +static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT; + + +#define PUSH_PARENT(stmt) \ + statement_t *const new_parent = (stmt); \ + statement_t *const old_parent = current_parent; \ + ((void)(current_parent = new_parent)) +#define POP_PARENT() (assert(current_parent == new_parent), (void)(current_parent = old_parent)) + +#define PUSH_SCOPE(scope) \ + size_t const top = environment_top(); \ + scope_t *const new_scope = (scope); \ + scope_t *const old_scope = scope_push(new_scope) +#define POP_SCOPE() (assert(current_scope == new_scope), scope_pop(old_scope), environment_pop_to(top)) + +#define PUSH_EXTENSION() \ + (void)0; \ + bool const old_gcc_extension = in_gcc_extension; \ + while (next_if(T___extension__)) { \ + in_gcc_extension = true; \ + } \ + do {} while (0) +#define POP_EXTENSION() \ + ((void)(in_gcc_extension = old_gcc_extension)) /** special symbol used for anonymous entities. */ static symbol_t *sym_anonymous = NULL; /** The token anchor set */ -static unsigned char token_anchor_set[T_LAST_TOKEN]; +static unsigned short token_anchor_set[T_LAST_TOKEN]; /** The current source position. */ -#define HERE (&token.source_position) +#define HERE (&token.base.source_position) /** true if we are in GCC mode. */ #define GNU_MODE ((c_mode & _GNUC) || in_gcc_extension) @@ -214,10 +229,6 @@ static void semantic_comparison(binary_expression_t *expression); TYPE_QUALIFIERS \ TYPE_SPECIFIERS -#define TYPENAME_START \ - TYPE_QUALIFIERS \ - TYPE_SPECIFIERS - #define EXPRESSION_START \ case '!': \ case '&': \ @@ -292,7 +303,7 @@ static size_t get_statement_struct_size(statement_kind_t kind) [STATEMENT_MS_TRY] = sizeof(ms_try_statement_t), [STATEMENT_LEAVE] = sizeof(leave_statement_t) }; - assert(kind < lengthof(sizes)); + assert((size_t)kind < lengthof(sizes)); assert(sizes[kind] != 0); return sizes[kind]; } @@ -308,6 +319,7 @@ static size_t get_expression_struct_size(expression_kind_t kind) [EXPR_INVALID] = sizeof(expression_base_t), [EXPR_REFERENCE] = sizeof(reference_expression_t), [EXPR_REFERENCE_ENUM_VALUE] = sizeof(reference_expression_t), + [EXPR_LITERAL_BOOLEAN] = sizeof(literal_expression_t), [EXPR_LITERAL_INTEGER] = sizeof(literal_expression_t), [EXPR_LITERAL_INTEGER_OCTAL] = sizeof(literal_expression_t), [EXPR_LITERAL_INTEGER_HEXADECIMAL]= sizeof(literal_expression_t), @@ -343,7 +355,7 @@ static size_t get_expression_struct_size(expression_kind_t kind) if (kind >= EXPR_BINARY_FIRST && kind <= EXPR_BINARY_LAST) { return sizes[EXPR_BINARY_FIRST]; } - assert(kind < lengthof(sizes)); + assert((size_t)kind < lengthof(sizes)); assert(sizes[kind] != 0); return sizes[kind]; } @@ -360,7 +372,7 @@ static statement_t *allocate_statement_zero(statement_kind_t kind) res->base.kind = kind; res->base.parent = current_parent; - res->base.source_position = token.source_position; + res->base.source_position = token.base.source_position; return res; } @@ -377,7 +389,7 @@ static expression_t *allocate_expression_zero(expression_kind_t kind) res->base.kind = kind; res->base.type = type_error_type; - res->base.source_position = token.source_position; + res->base.source_position = token.base.source_position; return res; } @@ -406,15 +418,6 @@ static statement_t *create_empty_statement(void) return allocate_statement_zero(STATEMENT_EMPTY); } -static function_parameter_t *allocate_parameter(type_t *const type) -{ - function_parameter_t *const param - = obstack_alloc(type_obst, sizeof(*param)); - memset(param, 0, sizeof(*param)); - param->type = type; - return param; -} - /** * Returns the size of an initializer node. * @@ -429,7 +432,7 @@ static size_t get_initializer_size(initializer_kind_t kind) [INITIALIZER_LIST] = sizeof(initializer_list_t), [INITIALIZER_DESIGNATOR] = sizeof(initializer_designator_t) }; - assert(kind < lengthof(sizes)); + assert((size_t)kind < lengthof(sizes)); assert(sizes[kind] != 0); return sizes[kind]; } @@ -481,7 +484,7 @@ static inline void next_token(void) static inline bool next_if(int const type) { - if (token.type == type) { + if (token.kind == type) { next_token(); return true; } else { @@ -502,41 +505,41 @@ static inline const token_t *look_ahead(size_t num) /** * Adds a token type to the token type anchor set (a multi-set). */ -static void add_anchor_token(int token_type) +static void add_anchor_token(int token_kind) { - assert(0 <= token_type && token_type < T_LAST_TOKEN); - ++token_anchor_set[token_type]; + assert(0 <= token_kind && token_kind < T_LAST_TOKEN); + ++token_anchor_set[token_kind]; } /** * Set the number of tokens types of the given type * to zero and return the old count. */ -static int save_and_reset_anchor_state(int token_type) +static int save_and_reset_anchor_state(int token_kind) { - assert(0 <= token_type && token_type < T_LAST_TOKEN); - int count = token_anchor_set[token_type]; - token_anchor_set[token_type] = 0; + assert(0 <= token_kind && token_kind < T_LAST_TOKEN); + int count = token_anchor_set[token_kind]; + token_anchor_set[token_kind] = 0; return count; } /** * Restore the number of token types to the given count. */ -static void restore_anchor_state(int token_type, int count) +static void restore_anchor_state(int token_kind, int count) { - assert(0 <= token_type && token_type < T_LAST_TOKEN); - token_anchor_set[token_type] = count; + assert(0 <= token_kind && token_kind < T_LAST_TOKEN); + token_anchor_set[token_kind] = count; } /** * Remove a token type from the token type anchor set (a multi-set). */ -static void rem_anchor_token(int token_type) +static void rem_anchor_token(int token_kind) { - assert(0 <= token_type && token_type < T_LAST_TOKEN); - assert(token_anchor_set[token_type] != 0); - --token_anchor_set[token_type]; + assert(0 <= token_kind && token_kind < T_LAST_TOKEN); + assert(token_anchor_set[token_kind] != 0); + --token_anchor_set[token_kind]; } /** @@ -545,9 +548,9 @@ static void rem_anchor_token(int token_type) */ static bool at_anchor(void) { - if (token.type < 0) + if (token.kind < 0) return false; - return token_anchor_set[token.type]; + return token_anchor_set[token.kind]; } /** @@ -566,11 +569,11 @@ static void eat_until_matching_token(int type) unsigned parenthesis_count = 0; unsigned brace_count = 0; unsigned bracket_count = 0; - while (token.type != end_token || + while (token.kind != end_token || parenthesis_count != 0 || brace_count != 0 || bracket_count != 0) { - switch (token.type) { + switch (token.kind) { case T_EOF: return; case '(': ++parenthesis_count; break; case '{': ++brace_count; break; @@ -590,7 +593,7 @@ static void eat_until_matching_token(int type) if (bracket_count > 0) --bracket_count; check_stop: - if (token.type == end_token && + if (token.kind == end_token && parenthesis_count == 0 && brace_count == 0 && bracket_count == 0) @@ -609,9 +612,9 @@ check_stop: */ static void eat_until_anchor(void) { - while (token_anchor_set[token.type] == 0) { - if (token.type == '(' || token.type == '{' || token.type == '[') - eat_until_matching_token(token.type); + while (token_anchor_set[token.kind] == 0) { + if (token.kind == '(' || token.kind == '{' || token.kind == '[') + eat_until_matching_token(token.kind); next_token(); } } @@ -625,7 +628,7 @@ static void eat_block(void) next_if('}'); } -#define eat(token_type) (assert(token.type == (token_type)), next_token()) +#define eat(token_kind) (assert(token.kind == (token_kind)), next_token()) /** * Report a parse error because an expected token was not found. @@ -662,13 +665,13 @@ static void type_error_incompatible(const char *msg, */ #define expect(expected, error_label) \ do { \ - if (UNLIKELY(token.type != (expected))) { \ + if (UNLIKELY(token.kind != (expected))) { \ parse_error_expected(NULL, (expected), NULL); \ add_anchor_token(expected); \ eat_until_anchor(); \ - next_if((expected)); \ rem_anchor_token(expected); \ - goto error_label; \ + if (token.kind != (expected)) \ + goto error_label; \ } \ next_token(); \ } while (0) @@ -705,7 +708,7 @@ static entity_t *get_entity(const symbol_t *const symbol, assert(namespc != NAMESPACE_INVALID); entity_t *entity = symbol->entity; for (; entity != NULL; entity = entity->base.symbol_next) { - if (entity->base.namespc == namespc) + if ((namespace_tag_t)entity->base.namespc == namespc) return entity; } @@ -718,7 +721,7 @@ static entity_t *get_tag(symbol_t const *const symbol, entity_kind_tag_t const kind) { entity_t *entity = get_entity(symbol, NAMESPACE_TAG); - if (entity != NULL && entity->kind != kind) { + if (entity != NULL && (entity_kind_tag_t)entity->kind != kind) { errorf(HERE, "'%Y' defined as wrong kind of tag (previous definition %P)", symbol, &entity->base.source_position); @@ -875,32 +878,12 @@ static int get_rank(const type_t *type) */ static type_t *promote_integer(type_t *type) { - if (type->kind == TYPE_BITFIELD) - type = type->bitfield.base_type; - if (get_rank(type) < get_akind_rank(ATOMIC_TYPE_INT)) type = type_int; return type; } -/** - * Create a cast expression. - * - * @param expression the expression to cast - * @param dest_type the destination type - */ -static expression_t *create_cast_expression(expression_t *expression, - type_t *dest_type) -{ - expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST_IMPLICIT); - - cast->unary.value = expression; - cast->base.type = dest_type; - - return cast; -} - /** * Check if a given expression represents a null pointer constant. * @@ -909,8 +892,7 @@ static expression_t *create_cast_expression(expression_t *expression, static bool is_null_pointer_constant(const expression_t *expression) { /* skip void* cast */ - if (expression->kind == EXPR_UNARY_CAST || - expression->kind == EXPR_UNARY_CAST_IMPLICIT) { + if (expression->kind == EXPR_UNARY_CAST) { type_t *const type = skip_typeref(expression->base.type); if (types_compatible(type, type_void_ptr)) expression = expression->unary.value; @@ -940,7 +922,12 @@ static expression_t *create_implicit_cast(expression_t *expression, if (source_type == dest_type) return expression; - return create_cast_expression(expression, dest_type); + expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST); + cast->unary.value = expression; + cast->base.type = dest_type; + cast->base.implicit = true; + + return cast; } typedef enum assign_error_t { @@ -952,10 +939,7 @@ typedef enum assign_error_t { ASSIGN_WARNING_INT_FROM_POINTER } assign_error_t; -static void report_assign_error(assign_error_t error, type_t *orig_type_left, - const expression_t *const right, - const char *context, - const source_position_t *source_position) +static void report_assign_error(assign_error_t error, type_t *orig_type_left, expression_t const *const right, char const *const context, source_position_t const *const pos) { type_t *const orig_type_right = right->base.type; type_t *const type_left = skip_typeref(orig_type_left); @@ -965,48 +949,29 @@ static void report_assign_error(assign_error_t error, type_t *orig_type_left, case ASSIGN_SUCCESS: return; case ASSIGN_ERROR_INCOMPATIBLE: - errorf(source_position, - "destination type '%T' in %s is incompatible with type '%T'", - orig_type_left, context, orig_type_right); + errorf(pos, "destination type '%T' in %s is incompatible with type '%T'", orig_type_left, context, orig_type_right); return; case ASSIGN_ERROR_POINTER_QUALIFIER_MISSING: { - 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); + 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); - } + /* the left type has all qualifiers from the right type */ + unsigned missing_qualifiers = points_to_right->base.qualifiers & ~points_to_left->base.qualifiers; + warningf(WARN_OTHER, pos, "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: - 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); - } + warningf(WARN_OTHER, pos, "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: - if (warning.other) { - warningf(source_position, - "%s makes pointer '%T' from integer '%T' without a cast", - context, orig_type_left, orig_type_right); - } + warningf(WARN_OTHER, pos, "%s makes pointer '%T' from integer '%T' without a cast", context, orig_type_left, orig_type_right); return; case ASSIGN_WARNING_INT_FROM_POINTER: - if (warning.other) { - warningf(source_position, - "%s makes integer '%T' from pointer '%T' without a cast", - context, orig_type_left, orig_type_right); - } + warningf(WARN_OTHER, pos, "%s makes integer '%T' from pointer '%T' without a cast", context, orig_type_left, orig_type_right); return; default: @@ -1062,8 +1027,7 @@ static assign_error_t semantic_assign(type_t *orig_type_left, (is_type_atomic(type_left, ATOMIC_TYPE_BOOL) && is_type_pointer(type_right))) { return ASSIGN_SUCCESS; - } else if ((is_type_compound(type_left) && is_type_compound(type_right)) - || (is_type_builtin(type_left) && is_type_builtin(type_right))) { + } else if (is_type_compound(type_left) && is_type_compound(type_right)) { type_t *const unqual_type_left = get_unqualified_type(type_left); type_t *const unqual_type_right = get_unqualified_type(type_right); if (types_compatible(unqual_type_left, unqual_type_right)) { @@ -1098,21 +1062,19 @@ static expression_t *parse_assignment_expression(void) static void warn_string_concat(const source_position_t *pos) { - if (warning.traditional) { - warningf(pos, "traditional C rejects string constant concatenation"); - } + warningf(WARN_TRADITIONAL, pos, "traditional C rejects string constant concatenation"); } static string_t parse_string_literals(void) { - assert(token.type == T_STRING_LITERAL); - string_t result = token.literal; + assert(token.kind == T_STRING_LITERAL); + string_t result = token.string.string; next_token(); - while (token.type == T_STRING_LITERAL) { - warn_string_concat(&token.source_position); - result = concat_strings(&result, &token.literal); + while (token.kind == T_STRING_LITERAL) { + warn_string_concat(&token.base.source_position); + result = concat_strings(&result, &token.string.string); next_token(); } @@ -1138,7 +1100,8 @@ static int strcmp_underscore(const char *s1, const char *s2) static attribute_t *allocate_attribute_zero(attribute_kind_t kind) { attribute_t *attribute = allocate_ast_zero(sizeof(*attribute)); - attribute->kind = kind; + attribute->kind = kind; + attribute->source_position = *HERE; return attribute; } @@ -1174,13 +1137,13 @@ static attribute_argument_t *parse_attribute_arguments(void) { attribute_argument_t *first = NULL; attribute_argument_t **anchor = &first; - if (token.type != ')') do { + if (token.kind != ')') do { attribute_argument_t *argument = allocate_ast_zero(sizeof(*argument)); /* is it an identifier */ - if (token.type == T_IDENTIFIER - && (look_ahead(1)->type == ',' || look_ahead(1)->type == ')')) { - symbol_t *symbol = token.symbol; + if (token.kind == T_IDENTIFIER + && (look_ahead(1)->kind == ',' || look_ahead(1)->kind == ')')) { + symbol_t *symbol = token.identifier.symbol; argument->kind = ATTRIBUTE_ARGUMENT_SYMBOL; argument->v.symbol = symbol; next_token(); @@ -1207,9 +1170,8 @@ end_error: static attribute_t *parse_attribute_asm(void) { - eat(T_asm); - attribute_t *attribute = allocate_attribute_zero(ATTRIBUTE_GNU_ASM); + eat(T_asm); expect('(', end_error); attribute->a.arguments = parse_attribute_arguments(); @@ -1221,9 +1183,9 @@ end_error: static symbol_t *get_symbol_from_token(void) { - switch(token.type) { + switch(token.kind) { case T_IDENTIFIER: - return token.symbol; + return token.identifier.symbol; case T_auto: case T_char: case T_double: @@ -1253,7 +1215,7 @@ static symbol_t *get_symbol_from_token(void) case T_volatile: case T_inline: /* maybe we need more tokens ... add them on demand */ - return get_token_symbol(&token); + return get_token_kind_symbol(token.kind); default: return NULL; } @@ -1268,26 +1230,24 @@ static attribute_t *parse_attribute_gnu_single(void) return NULL; } - const char *name = symbol->string; - next_token(); + attribute_kind_t kind; + char const *const name = symbol->string; + for (kind = ATTRIBUTE_GNU_FIRST;; ++kind) { + if (kind > ATTRIBUTE_GNU_LAST) { + warningf(WARN_ATTRIBUTE, HERE, "unknown attribute '%s' ignored", name); + /* TODO: we should still save the attribute in the list... */ + kind = ATTRIBUTE_UNKNOWN; + break; + } - attribute_kind_t kind; - for (kind = ATTRIBUTE_GNU_FIRST; kind <= ATTRIBUTE_GNU_LAST; ++kind) { const char *attribute_name = get_attribute_name(kind); if (attribute_name != NULL && strcmp_underscore(attribute_name, name) == 0) break; } - if (kind >= ATTRIBUTE_GNU_LAST) { - if (warning.attribute) { - warningf(HERE, "unknown attribute '%s' ignored", name); - } - /* TODO: we should still save the attribute in the list... */ - kind = ATTRIBUTE_UNKNOWN; - } - attribute_t *attribute = allocate_attribute_zero(kind); + next_token(); /* parse arguments */ if (next_if('(')) @@ -1305,7 +1265,7 @@ static attribute_t *parse_attribute_gnu(void) expect('(', end_error); expect('(', end_error); - if (token.type != ')') do { + if (token.kind != ')') do { attribute_t *attribute = parse_attribute_gnu_single(); if (attribute == NULL) goto end_error; @@ -1329,9 +1289,11 @@ static attribute_t *parse_attributes(attribute_t *first) anchor = &(*anchor)->next; attribute_t *attribute; - switch (token.type) { + switch (token.kind) { case T___attribute__: attribute = parse_attribute_gnu(); + if (attribute == NULL) + continue; break; case T_asm: @@ -1339,31 +1301,30 @@ static attribute_t *parse_attributes(attribute_t *first) break; case T_cdecl: - next_token(); attribute = allocate_attribute_zero(ATTRIBUTE_MS_CDECL); + eat(T_cdecl); break; case T__fastcall: - next_token(); attribute = allocate_attribute_zero(ATTRIBUTE_MS_FASTCALL); + eat(T__fastcall); break; case T__forceinline: - next_token(); attribute = allocate_attribute_zero(ATTRIBUTE_MS_FORCEINLINE); + eat(T__forceinline); break; case T__stdcall: - next_token(); attribute = allocate_attribute_zero(ATTRIBUTE_MS_STDCALL); + eat(T__stdcall); break; case T___thiscall: - next_token(); /* TODO record modifier */ - if (warning.other) - warningf(HERE, "Ignoring declaration modifier %K", &token); + warningf(WARN_OTHER, HERE, "Ignoring declaration modifier %K", &token); attribute = allocate_attribute_zero(ATTRIBUTE_MS_THISCALL); + eat(T___thiscall); break; default: @@ -1529,7 +1490,6 @@ static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent) 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_vars_read(expr->unary.value, lhs_ent); @@ -1587,7 +1547,6 @@ unary: return; EXPR_LITERAL_CASES - case EXPR_UNKNOWN: case EXPR_INVALID: case EXPR_STRING_LITERAL: case EXPR_WIDE_STRING_LITERAL: @@ -1615,10 +1574,10 @@ static designator_t *parse_designation(void) for (;;) { designator_t *designator; - switch (token.type) { + switch (token.kind) { case '[': designator = allocate_ast_zero(sizeof(designator[0])); - designator->source_position = token.source_position; + designator->source_position = token.base.source_position; next_token(); add_anchor_token(']'); designator->array_index = parse_constant_expression(); @@ -1627,14 +1586,14 @@ static designator_t *parse_designation(void) break; case '.': designator = allocate_ast_zero(sizeof(designator[0])); - designator->source_position = token.source_position; + designator->source_position = token.base.source_position; next_token(); - if (token.type != T_IDENTIFIER) { + if (token.kind != T_IDENTIFIER) { parse_error_expected("while parsing designator", T_IDENTIFIER, NULL); return NULL; } - designator->symbol = token.symbol; + designator->symbol = token.identifier.symbol; next_token(); break; default: @@ -1732,13 +1691,12 @@ static initializer_t *initializer_from_expression(type_t *orig_type, } /** - * Checks if a given expression can be used as an constant initializer. + * Checks if a given expression can be used as a constant initializer. */ static bool is_initializer_constant(const expression_t *expression) { - return - is_constant_expression(expression) != EXPR_CLASS_VARIABLE || - is_address_constant(expression) != EXPR_CLASS_VARIABLE; + return is_constant_expression(expression) != EXPR_CLASS_VARIABLE || + is_linker_constant(expression) != EXPR_CLASS_VARIABLE; } /** @@ -1751,12 +1709,12 @@ static initializer_t *parse_scalar_initializer(type_t *type, { /* there might be extra {} hierarchies */ int braces = 0; - if (next_if('{')) { - if (warning.other) - warningf(HERE, "extra curly braces around scalar initializer"); + if (token.kind == '{') { + warningf(WARN_OTHER, HERE, "extra curly braces around scalar initializer"); do { + eat('{'); ++braces; - } while (next_if('{')); + } while (token.kind == '{'); } expression_t *expression = parse_assignment_expression(); @@ -1780,9 +1738,9 @@ static initializer_t *parse_scalar_initializer(type_t *type, bool additional_warning_displayed = false; while (braces > 0) { next_if(','); - if (token.type != '}') { - if (!additional_warning_displayed && warning.other) { - warningf(HERE, "additional elements in scalar initializer"); + if (token.kind != '}') { + if (!additional_warning_displayed) { + warningf(WARN_OTHER, HERE, "additional elements in scalar initializer"); additional_warning_displayed = true; } } @@ -1962,17 +1920,14 @@ static bool walk_designator(type_path_t *path, const designator_t *designator, if (iter == NULL) { errorf(&designator->source_position, "'%T' has no member named '%Y'", orig_type, symbol); - goto failed; + return false; } assert(iter->kind == ENTITY_COMPOUND_MEMBER); - if (used_in_offsetof) { - type_t *real_type = skip_typeref(iter->declaration.type); - if (real_type->kind == TYPE_BITFIELD) { - errorf(&designator->source_position, - "offsetof designator '%Y' must not specify bitfield", - symbol); - goto failed; - } + if (used_in_offsetof && iter->compound_member.bitfield) { + errorf(&designator->source_position, + "offsetof designator '%Y' must not specify bitfield", + symbol); + return false; } top->type = orig_type; @@ -1989,7 +1944,7 @@ static bool walk_designator(type_path_t *path, const designator_t *designator, "[%E] designator used for non-array type '%T'", array_index, orig_type); } - goto failed; + return false; } long index = fold_constant_to_int(array_index); @@ -2018,9 +1973,6 @@ static bool walk_designator(type_path_t *path, const designator_t *designator, } } return true; - -failed: - return false; } static void advance_current_object(type_path_t *path, size_t top_path_level) @@ -2079,10 +2031,10 @@ static void skip_initializers(void) { next_if('{'); - while (token.type != '}') { - if (token.type == T_EOF) + while (token.kind != '}') { + if (token.kind == T_EOF) return; - if (token.type == '{') { + if (token.kind == '{') { eat_block(); continue; } @@ -2104,7 +2056,7 @@ static initializer_t *parse_sub_initializer(type_path_t *path, type_t *outer_type, size_t top_path_level, parse_initializer_env_t *env) { - if (token.type == '}') { + if (token.kind == '}') { /* empty initializer */ return create_empty_initializer(); } @@ -2122,14 +2074,14 @@ static initializer_t *parse_sub_initializer(type_path_t *path, while (true) { designator_t *designator = NULL; - if (token.type == '.' || token.type == '[') { + if (token.kind == '.' || token.kind == '[') { designator = parse_designation(); goto finish_designator; - } else if (token.type == T_IDENTIFIER && look_ahead(1)->type == ':') { + } else if (token.kind == T_IDENTIFIER && look_ahead(1)->kind == ':') { /* GNU-style designator ("identifier: value") */ designator = allocate_ast_zero(sizeof(designator[0])); - designator->source_position = token.source_position; - designator->symbol = token.symbol; + designator->source_position = token.base.source_position; + designator->symbol = token.identifier.symbol; eat(T_IDENTIFIER); eat(':'); @@ -2152,11 +2104,10 @@ finish_designator: initializer_t *sub; - if (token.type == '{') { + if (token.kind == '{') { if (type != NULL && is_type_scalar(type)) { sub = parse_scalar_initializer(type, env->must_be_constant); } else { - eat('{'); if (type == NULL) { if (env->entity != NULL) { errorf(HERE, @@ -2165,8 +2116,11 @@ finish_designator: } else { errorf(HERE, "extra brace group at end of initializer"); } - } else + eat('{'); + } else { + eat('{'); descend_into_subtype(path); + } add_anchor_token('}'); sub = parse_sub_initializer(path, orig_type, top_path_level+1, @@ -2198,10 +2152,17 @@ finish_designator: goto error_parse_next; type_t *const outer_type_skip = skip_typeref(outer_type); if (is_type_compound(outer_type_skip) && - !outer_type_skip->compound.compound->complete) { + !outer_type_skip->compound.compound->complete) { goto error_parse_next; } - goto error_excess; + + source_position_t const* const pos = &expression->base.source_position; + if (env->entity != NULL) { + warningf(WARN_OTHER, pos, "excess elements in initializer for '%Y'", env->entity->base.symbol); + } else { + warningf(WARN_OTHER, pos, "excess elements in initializer"); + } + goto error_parse_next; } /* handle { "string" } special case */ @@ -2211,9 +2172,8 @@ finish_designator: sub = initializer_from_expression(outer_type, expression); if (sub != NULL) { next_if(','); - if (token.type != '}' && warning.other) { - warningf(HERE, "excessive elements in initializer for type '%T'", - orig_type); + if (token.kind != '}') { + warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", orig_type); } /* TODO: eat , ... */ return sub; @@ -2253,27 +2213,15 @@ finish_designator: path->max_index = index; } - if (type != NULL) { - /* append to initializers list */ - ARR_APP1(initializer_t*, initializers, sub); - } else { -error_excess: - if (warning.other) { - if (env->entity != NULL) { - warningf(HERE, "excess elements in initializer for '%Y'", - env->entity->base.symbol); - } else { - warningf(HERE, "excess elements in initializer"); - } - } - } + /* append to initializers list */ + ARR_APP1(initializer_t*, initializers, sub); error_parse_next: - if (token.type == '}') { + if (token.kind == '}') { break; } expect(',', end_error); - if (token.type == '}') { + if (token.kind == '}') { break; } @@ -2332,7 +2280,7 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env) if (is_type_scalar(type)) { result = parse_scalar_initializer(type, env->must_be_constant); - } else if (token.type == '{') { + } else if (token.kind == '{') { eat('{'); type_path_t path; @@ -2350,6 +2298,7 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env) DEL_ARR_F(path.path); expect('}', end_error); +end_error:; } else { /* parse_scalar_initializer() also works in this case: we simply * have an expression without {} around it */ @@ -2395,8 +2344,6 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env) } return result; -end_error: - return NULL; } static void append_entity(scope_t *scope, entity_t *entity) @@ -2413,88 +2360,79 @@ static void append_entity(scope_t *scope, entity_t *entity) static compound_t *parse_compound_type_specifier(bool is_struct) { + source_position_t const pos = *HERE; eat(is_struct ? T_struct : T_union); - symbol_t *symbol = NULL; - compound_t *compound = NULL; + symbol_t *symbol = NULL; + entity_t *entity = NULL; attribute_t *attributes = NULL; - if (token.type == T___attribute__) { + if (token.kind == T___attribute__) { attributes = parse_attributes(NULL); } entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION; - if (token.type == T_IDENTIFIER) { + if (token.kind == T_IDENTIFIER) { /* the compound has a name, check if we have seen it already */ - symbol = token.symbol; + symbol = token.identifier.symbol; + entity = get_tag(symbol, kind); next_token(); - entity_t *entity = get_tag(symbol, kind); if (entity != NULL) { - compound = &entity->compound; - if (compound->base.parent_scope != current_scope && - (token.type == '{' || token.type == ';')) { + if (entity->base.parent_scope != current_scope && + (token.kind == '{' || token.kind == ';')) { /* we're in an inner scope and have a definition. Shadow * existing definition in outer scope */ - compound = NULL; - } else if (compound->complete && token.type == '{') { - assert(symbol != NULL); - errorf(HERE, "multiple definitions of '%s %Y' (previous definition %P)", - is_struct ? "struct" : "union", symbol, - &compound->base.source_position); + entity = NULL; + } else if (entity->compound.complete && token.kind == '{') { + source_position_t const *const ppos = &entity->base.source_position; + errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos); /* clear members in the hope to avoid further errors */ - compound->members.entities = NULL; + entity->compound.members.entities = NULL; } } - } else if (token.type != '{') { - if (is_struct) { - parse_error_expected("while parsing struct type specifier", - T_IDENTIFIER, '{', NULL); - } else { - parse_error_expected("while parsing union type specifier", - T_IDENTIFIER, '{', NULL); - } + } else if (token.kind != '{') { + char const *const msg = + is_struct ? "while parsing struct type specifier" : + "while parsing union type specifier"; + parse_error_expected(msg, T_IDENTIFIER, '{', NULL); return NULL; } - if (compound == NULL) { - entity_t *entity = allocate_entity_zero(kind); - compound = &entity->compound; - - compound->alignment = 1; - compound->base.namespc = NAMESPACE_TAG; - compound->base.source_position = token.source_position; - compound->base.symbol = symbol; - compound->base.parent_scope = current_scope; + if (entity == NULL) { + entity = allocate_entity_zero(kind, NAMESPACE_TAG, symbol); + entity->compound.alignment = 1; + entity->base.source_position = pos; + entity->base.parent_scope = current_scope; if (symbol != NULL) { environment_push(entity); } append_entity(current_scope, entity); } - if (token.type == '{') { - parse_compound_type_entries(compound); + if (token.kind == '{') { + parse_compound_type_entries(&entity->compound); /* ISO/IEC 14882:1998(E) §7.1.3:5 */ if (symbol == NULL) { assert(anonymous_entity == NULL); - anonymous_entity = (entity_t*)compound; + anonymous_entity = entity; } } if (attributes != NULL) { - handle_entity_attributes(attributes, (entity_t*) compound); + handle_entity_attributes(attributes, entity); } - return compound; + return &entity->compound; } static void parse_enum_entries(type_t *const enum_type) { eat('{'); - if (token.type == '}') { + if (token.kind == '}') { errorf(HERE, "empty enum not allowed"); next_token(); return; @@ -2502,18 +2440,18 @@ static void parse_enum_entries(type_t *const enum_type) add_anchor_token('}'); do { - if (token.type != T_IDENTIFIER) { + if (token.kind != T_IDENTIFIER) { parse_error_expected("while parsing enum entry", T_IDENTIFIER, NULL); eat_block(); rem_anchor_token('}'); return; } - entity_t *entity = allocate_entity_zero(ENTITY_ENUM_VALUE); + symbol_t *symbol = token.identifier.symbol; + entity_t *const entity + = allocate_entity_zero(ENTITY_ENUM_VALUE, NAMESPACE_NORMAL, symbol); entity->enum_value.enum_type = enum_type; - entity->base.namespc = NAMESPACE_NORMAL; - entity->base.symbol = token.symbol; - entity->base.source_position = token.source_position; + entity->base.source_position = token.base.source_position; next_token(); if (next_if('=')) { @@ -2526,7 +2464,7 @@ static void parse_enum_entries(type_t *const enum_type) } record_entity(entity, false); - } while (next_if(',') && token.type != '}'); + } while (next_if(',') && token.kind != '}'); rem_anchor_token('}'); expect('}', end_error); @@ -2537,25 +2475,26 @@ end_error: static type_t *parse_enum_specifier(void) { - entity_t *entity; - symbol_t *symbol; + source_position_t const pos = *HERE; + entity_t *entity; + symbol_t *symbol; eat(T_enum); - switch (token.type) { + switch (token.kind) { case T_IDENTIFIER: - symbol = token.symbol; + symbol = token.identifier.symbol; + entity = get_tag(symbol, ENTITY_ENUM); next_token(); - entity = get_tag(symbol, ENTITY_ENUM); if (entity != NULL) { if (entity->base.parent_scope != current_scope && - (token.type == '{' || token.type == ';')) { + (token.kind == '{' || token.kind == ';')) { /* we're in an inner scope and have a definition. Shadow * existing definition in outer scope */ entity = NULL; - } else if (entity->enume.complete && token.type == '{') { - errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)", - symbol, &entity->base.source_position); + } else if (entity->enume.complete && token.kind == '{') { + source_position_t const *const ppos = &entity->base.source_position; + errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos); } } break; @@ -2572,10 +2511,8 @@ static type_t *parse_enum_specifier(void) } if (entity == NULL) { - entity = allocate_entity_zero(ENTITY_ENUM); - entity->base.namespc = NAMESPACE_TAG; - entity->base.source_position = token.source_position; - entity->base.symbol = symbol; + entity = allocate_entity_zero(ENTITY_ENUM, NAMESPACE_TAG, symbol); + entity->base.source_position = pos; entity->base.parent_scope = current_scope; } @@ -2583,7 +2520,7 @@ static type_t *parse_enum_specifier(void) type->enumt.enume = &entity->enume; type->enumt.akind = ATOMIC_TYPE_INT; - if (token.type == '{') { + if (token.kind == '{') { if (symbol != NULL) { environment_push(entity); } @@ -2599,8 +2536,7 @@ static type_t *parse_enum_specifier(void) anonymous_entity = entity; } } else if (!entity->enume.complete && !(c_mode & _GNUC)) { - errorf(HERE, "'enum %Y' used before definition (incomplete enums are a GNU extension)", - symbol); + errorf(HERE, "'%T' used before definition (incomplete enums are a GNU extension)", type); } return type; @@ -2626,18 +2562,10 @@ static type_t *parse_typeof(void) expression_t *expression = NULL; - bool old_type_prop = in_type_prop; - bool old_gcc_extension = in_gcc_extension; - in_type_prop = true; - - while (next_if(T___extension__)) { - /* This can be a prefix to a typename or an expression. */ - in_gcc_extension = true; - } - switch (token.type) { + switch (token.kind) { case T_IDENTIFIER: - if (is_typedef_symbol(token.symbol)) { - TYPENAME_START + if (is_typedef_symbol(token.identifier.symbol)) { + DECLARATION_START type = parse_typename(); } else { default: @@ -2646,8 +2574,6 @@ static type_t *parse_typeof(void) } break; } - in_type_prop = old_type_prop; - in_gcc_extension = old_gcc_extension; rem_anchor_token(')'); expect(')', end_error); @@ -2683,15 +2609,6 @@ typedef enum specifiers_t { SPECIFIER_IMAGINARY = 1 << 18, } 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); - type->builtin.symbol = symbol; - type->builtin.real_type = real_type; - return identify_new_type(type); -} - static type_t *get_typedef_type(symbol_t *symbol) { entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL); @@ -2712,34 +2629,31 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute) = allocate_ast_zero(sizeof(*property)); do { - if (token.type != T_IDENTIFIER) { + if (token.kind != T_IDENTIFIER) { parse_error_expected("while parsing property declspec", T_IDENTIFIER, NULL); goto end_error; } - bool is_put; - symbol_t *symbol = token.symbol; - next_token(); + symbol_t **prop; + symbol_t *symbol = token.identifier.symbol; if (strcmp(symbol->string, "put") == 0) { - is_put = true; + prop = &property->put_symbol; } else if (strcmp(symbol->string, "get") == 0) { - is_put = false; + prop = &property->get_symbol; } else { errorf(HERE, "expected put or get in property declspec"); - goto end_error; + prop = NULL; } + eat(T_IDENTIFIER); expect('=', end_error); - if (token.type != T_IDENTIFIER) { + if (token.kind != T_IDENTIFIER) { parse_error_expected("while parsing property declspec", T_IDENTIFIER, NULL); goto end_error; } - if (is_put) { - property->put_symbol = token.symbol; - } else { - property->get_symbol = token.symbol; - } + if (prop != NULL) + *prop = token.identifier.symbol; next_token(); } while (next_if(',')); @@ -2756,9 +2670,8 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void) attribute_kind_t kind = ATTRIBUTE_UNKNOWN; if (next_if(T_restrict)) { kind = ATTRIBUTE_MS_RESTRICT; - } else if (token.type == T_IDENTIFIER) { - const char *name = token.symbol->string; - next_token(); + } else if (token.kind == T_IDENTIFIER) { + const char *name = token.identifier.symbol->string; for (attribute_kind_t k = ATTRIBUTE_MS_FIRST; k <= ATTRIBUTE_MS_LAST; ++k) { const char *attribute_name = get_attribute_name(k); @@ -2768,8 +2681,8 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void) } } - if (kind == ATTRIBUTE_UNKNOWN && warning.attribute) { - warningf(HERE, "unknown __declspec '%s' ignored", name); + if (kind == ATTRIBUTE_UNKNOWN) { + warningf(WARN_ATTRIBUTE, HERE, "unknown __declspec '%s' ignored", name); } } else { parse_error_expected("while parsing __declspec", T_IDENTIFIER, NULL); @@ -2777,6 +2690,7 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void) } attribute_t *attribute = allocate_attribute_zero(kind); + eat(T_IDENTIFIER); if (kind == ATTRIBUTE_MS_PROPERTY) { return parse_attribute_ms_property(attribute); @@ -2825,10 +2739,8 @@ end_error: static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind) { - entity_t *entity = allocate_entity_zero(kind); - entity->base.namespc = NAMESPACE_NORMAL; + entity_t *const entity = allocate_entity_zero(kind, NAMESPACE_NORMAL, symbol); entity->base.source_position = *HERE; - entity->base.symbol = symbol; if (is_declaration(entity)) { entity->declaration.type = type_error_type; entity->declaration.implicit = true; @@ -2843,19 +2755,19 @@ static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind) static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) { - type_t *type = NULL; - type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE; - unsigned type_specifiers = 0; - bool newtype = false; - bool saw_error = false; - bool old_gcc_extension = in_gcc_extension; + type_t *type = NULL; + type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE; + unsigned type_specifiers = 0; + bool newtype = false; + bool saw_error = false; - specifiers->source_position = token.source_position; + memset(specifiers, 0, sizeof(*specifiers)); + specifiers->source_position = token.base.source_position; while (true) { specifiers->attributes = parse_attributes(specifiers->attributes); - switch (token.type) { + switch (token.kind) { /* storage class */ #define MATCH_STORAGE_CLASS(token, class) \ case token: \ @@ -2919,11 +2831,6 @@ wrong_thread_storage_class: MATCH_TYPE_QUALIFIER(T___uptr, TYPE_QUALIFIER_UPTR); MATCH_TYPE_QUALIFIER(T___sptr, TYPE_QUALIFIER_SPTR); - case T___extension__: - next_token(); - in_gcc_extension = true; - break; - /* type specifiers */ #define MATCH_SPECIFIER(token, specifier, name) \ case token: \ @@ -2968,7 +2875,7 @@ wrong_thread_storage_class: case T_long: if (type_specifiers & SPECIFIER_LONG_LONG) { - errorf(HERE, "multiple type specifiers given"); + errorf(HERE, "too many long type specifiers given"); } else if (type_specifiers & SPECIFIER_LONG) { type_specifiers |= SPECIFIER_LONG_LONG; } else { @@ -2977,9 +2884,8 @@ wrong_thread_storage_class: next_token(); break; -#define CHECK_DOUBLE_TYPE() \ - if ( type != NULL) \ - errorf(HERE, "multiple data types in declaration specifiers"); +#define CHECK_DOUBLE_TYPE() \ + (type != NULL ? errorf(HERE, "multiple types in declaration specifiers") : (void)0) case T_struct: CHECK_DOUBLE_TYPE(); @@ -3012,7 +2918,7 @@ wrong_thread_storage_class: /* Be somewhat resilient to typos like 'unsigned lng* f()' in a * declaration, so it doesn't generate errors about expecting '(' or * '{' later on. */ - switch (look_ahead(1)->type) { + switch (look_ahead(1)->kind) { STORAGE_CLASSES TYPE_SPECIFIERS case T_const: @@ -3032,12 +2938,12 @@ wrong_thread_storage_class: } } - type_t *const typedef_type = get_typedef_type(token.symbol); + type_t *const typedef_type = get_typedef_type(token.identifier.symbol); if (typedef_type == NULL) { /* Be somewhat resilient to typos like 'vodi f()' at the beginning of a * declaration, so it doesn't generate 'implicit int' followed by more * errors later on. */ - token_type_t const la1_type = (token_type_t)look_ahead(1)->type; + token_kind_t const la1_type = (token_kind_t)look_ahead(1)->kind; switch (la1_type) { DECLARATION_START case T_IDENTIFIER: @@ -3045,16 +2951,15 @@ wrong_thread_storage_class: case '*': { errorf(HERE, "%K does not name a type", &token); - entity_t *entity = - create_error_entity(token.symbol, ENTITY_TYPEDEF); + symbol_t *symbol = token.identifier.symbol; + entity_t *entity + = create_error_entity(symbol, ENTITY_TYPEDEF); type = allocate_type_zero(TYPE_TYPEDEF); type->typedeft.typedefe = &entity->typedefe; next_token(); saw_error = true; - if (la1_type == '&' || la1_type == '*') - goto finish_specifiers; continue; } @@ -3077,8 +2982,6 @@ wrong_thread_storage_class: finish_specifiers: specifiers->attributes = parse_attributes(specifiers->attributes); - in_gcc_extension = old_gcc_extension; - if (type == NULL || (saw_error && type_specifiers != 0)) { atomic_type_kind_t atomic_type; @@ -3142,10 +3045,7 @@ finish_specifiers: | SPECIFIER_INT: atomic_type = ATOMIC_TYPE_ULONGLONG; warn_about_long_long: - if (warning.long_long) { - warningf(&specifiers->source_position, - "ISO C90 does not support 'long long'"); - } + warningf(WARN_LONG_LONG, &specifiers->source_position, "ISO C90 does not support 'long long'"); break; case SPECIFIER_UNSIGNED | SPECIFIER_INT8: @@ -3217,32 +3117,31 @@ warn_about_long_long: case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY: atomic_type = ATOMIC_TYPE_LONG_DOUBLE; break; - default: + default: { /* invalid specifier combination, give an error message */ + source_position_t const* const pos = &specifiers->source_position; if (type_specifiers == 0) { - if (saw_error) - goto end_error; - - /* ISO/IEC 14882:1998(E) §C.1.5:4 */ - if (!(c_mode & _CXX) && !strict_mode) { - if (warning.implicit_int) { - warningf(HERE, "no type specifiers in declaration, using 'int'"); + if (!saw_error) { + /* ISO/IEC 14882:1998(E) §C.1.5:4 */ + if (!(c_mode & _CXX) && !strict_mode) { + warningf(WARN_IMPLICIT_INT, pos, "no type specifiers in declaration, using 'int'"); + atomic_type = ATOMIC_TYPE_INT; + break; + } else { + errorf(pos, "no type specifiers given in declaration"); } - atomic_type = ATOMIC_TYPE_INT; - break; - } else { - errorf(HERE, "no type specifiers given in declaration"); } } else if ((type_specifiers & SPECIFIER_SIGNED) && (type_specifiers & SPECIFIER_UNSIGNED)) { - errorf(HERE, "signed and unsigned specifiers given"); + errorf(pos, "signed and unsigned specifiers given"); } else if (type_specifiers & (SPECIFIER_SIGNED | SPECIFIER_UNSIGNED)) { - errorf(HERE, "only integer types can be signed or unsigned"); + errorf(pos, "only integer types can be signed or unsigned"); } else { - errorf(HERE, "multiple datatypes in declaration"); + errorf(pos, "multiple datatypes in declaration"); } goto end_error; } + } if (type_specifiers & SPECIFIER_COMPLEX) { type = allocate_type_zero(TYPE_COMPLEX); @@ -3256,7 +3155,7 @@ warn_about_long_long: } newtype = true; } else if (type_specifiers != 0) { - errorf(HERE, "multiple datatypes in declaration"); + errorf(&specifiers->source_position, "multiple datatypes in declaration"); } /* FIXME: check type qualifiers here */ @@ -3282,7 +3181,7 @@ static type_qualifiers_t parse_type_qualifiers(void) type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE; while (true) { - switch (token.type) { + switch (token.kind) { /* type qualifiers */ MATCH_TYPE_QUALIFIER(T_const, TYPE_QUALIFIER_CONST); MATCH_TYPE_QUALIFIER(T_restrict, TYPE_QUALIFIER_RESTRICT); @@ -3305,24 +3204,21 @@ static type_qualifiers_t parse_type_qualifiers(void) */ static void parse_identifier_list(scope_t *scope) { + assert(token.kind == T_IDENTIFIER); do { - entity_t *entity = allocate_entity_zero(ENTITY_PARAMETER); - entity->base.source_position = token.source_position; - entity->base.namespc = NAMESPACE_NORMAL; - entity->base.symbol = token.symbol; + entity_t *const entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, token.identifier.symbol); + entity->base.source_position = token.base.source_position; /* a K&R parameter has no type, yet */ next_token(); if (scope != NULL) append_entity(scope, entity); - } while (next_if(',') && token.type == T_IDENTIFIER); + } while (next_if(',') && token.kind == T_IDENTIFIER); } static entity_t *parse_parameter(void) { declaration_specifiers_t specifiers; - memset(&specifiers, 0, sizeof(specifiers)); - parse_declaration_specifiers(&specifiers); entity_t *entity = parse_declarator(&specifiers, @@ -3341,27 +3237,26 @@ static void semantic_parameter_incomplete(const entity_t *entity) * incomplete type. */ type_t *type = skip_typeref(entity->declaration.type); if (is_type_incomplete(type)) { - errorf(&entity->base.source_position, - "parameter '%#T' has incomplete type", - entity->declaration.type, entity->base.symbol); + errorf(&entity->base.source_position, "'%N' has incomplete type", entity); } } static bool has_parameters(void) { /* func(void) is not a parameter */ - if (token.type == T_IDENTIFIER) { - entity_t const *const entity = get_entity(token.symbol, NAMESPACE_NORMAL); + if (token.kind == T_IDENTIFIER) { + entity_t const *const entity + = get_entity(token.identifier.symbol, NAMESPACE_NORMAL); if (entity == NULL) return true; if (entity->kind != ENTITY_TYPEDEF) return true; if (skip_typeref(entity->typedefe.type) != type_void) return true; - } else if (token.type != T_void) { + } else if (token.kind != T_void) { return true; } - if (look_ahead(1)->type != ')') + if (look_ahead(1)->kind != ')') return true; next_token(); return false; @@ -3377,9 +3272,9 @@ static void parse_parameters(function_type_t *type, scope_t *scope) add_anchor_token(')'); int saved_comma_state = save_and_reset_anchor_state(','); - if (token.type == T_IDENTIFIER && - !is_typedef_symbol(token.symbol)) { - token_type_t la1_type = (token_type_t)look_ahead(1)->type; + if (token.kind == T_IDENTIFIER + && !is_typedef_symbol(token.identifier.symbol)) { + token_kind_t la1_type = (token_kind_t)look_ahead(1)->kind; if (la1_type == ',' || la1_type == ')') { type->kr_style_parameters = true; parse_identifier_list(scope); @@ -3387,24 +3282,20 @@ static void parse_parameters(function_type_t *type, scope_t *scope) } } - if (token.type == ')') { + if (token.kind == ')') { /* ISO/IEC 14882:1998(E) §C.1.6:1 */ if (!(c_mode & _CXX)) type->unspecified_parameters = true; - goto parameters_finished; - } - - if (has_parameters()) { + } else if (has_parameters()) { function_parameter_t **anchor = &type->parameters; do { - switch (token.type) { + switch (token.kind) { case T_DOTDOTDOT: next_token(); type->variadic = true; goto parameters_finished; case T_IDENTIFIER: - case T___extension__: DECLARATION_START { entity_t *entity = parse_parameter(); @@ -3435,7 +3326,6 @@ static void parse_parameters(function_type_t *type, scope_t *scope) } while (next_if(',')); } - parameters_finished: rem_anchor_token(')'); expect(')', end_error); @@ -3456,6 +3346,7 @@ typedef union construct_type_t construct_type_t; typedef struct construct_type_base_t { construct_type_kind_t kind; + source_position_t pos; construct_type_t *next; } construct_type_base_t; @@ -3495,16 +3386,16 @@ static construct_type_t *allocate_declarator_zero(construct_type_kind_t const ki { construct_type_t *const cons = obstack_alloc(&temp_obst, size); memset(cons, 0, size); - cons->kind = kind; + cons->kind = kind; + cons->base.pos = *HERE; return cons; } /* §6.7.5.1 */ static construct_type_t *parse_pointer_declarator(void) { - eat('*'); - construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_POINTER, sizeof(parsed_pointer_t)); + eat('*'); cons->pointer.type_qualifiers = parse_type_qualifiers(); //cons->pointer.base_variable = base_variable; @@ -3514,12 +3405,11 @@ static construct_type_t *parse_pointer_declarator(void) /* ISO/IEC 14882:1998(E) §8.3.2 */ static construct_type_t *parse_reference_declarator(void) { - eat('&'); - if (!(c_mode & _CXX)) errorf(HERE, "references are only available for C++"); construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_REFERENCE, sizeof(parsed_reference_t)); + eat('&'); return cons; } @@ -3527,12 +3417,12 @@ static construct_type_t *parse_reference_declarator(void) /* §6.7.5.2 */ static construct_type_t *parse_array_declarator(void) { - eat('['); - add_anchor_token(']'); - construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_ARRAY, sizeof(parsed_array_t)); parsed_array_t *const array = &cons->array; + eat('['); + add_anchor_token(']'); + bool is_static = next_if(T_static); type_qualifiers_t type_qualifiers = parse_type_qualifiers(); @@ -3544,10 +3434,10 @@ static construct_type_t *parse_array_declarator(void) array->is_static = is_static; expression_t *size = NULL; - if (token.type == '*' && look_ahead(1)->type == ']') { + if (token.kind == '*' && look_ahead(1)->kind == ']') { array->is_variable = true; next_token(); - } else if (token.type != ']') { + } else if (token.kind != ']') { size = parse_assignment_expression(); /* §6.7.5.2:1 Array size must have integer type */ @@ -3564,7 +3454,7 @@ static construct_type_t *parse_array_declarator(void) } if (is_static && size == NULL) - errorf(HERE, "static array parameters require a size"); + errorf(&array->base.pos, "static array parameters require a size"); rem_anchor_token(']'); expect(']', end_error); @@ -3576,6 +3466,8 @@ end_error: /* §6.7.5.3 */ static construct_type_t *parse_function_declarator(scope_t *scope) { + construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_FUNCTION, sizeof(construct_function_type_t)); + type_t *type = allocate_type_zero(TYPE_FUNCTION); function_type_t *ftype = &type->function; @@ -3584,7 +3476,6 @@ static construct_type_t *parse_function_declarator(scope_t *scope) parse_parameters(ftype, scope); - construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_FUNCTION, sizeof(construct_function_type_t)); cons->function.function_type = type; return cons; @@ -3613,7 +3504,7 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env) for (;;) { construct_type_t *type; //variable_t *based = NULL; /* MS __based extension */ - switch (token.type) { + switch (token.kind) { case '&': type = parse_reference_declarator(); break; @@ -3641,40 +3532,58 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env) ptr_operator_end: ; construct_type_t *inner_types = NULL; - switch (token.type) { + switch (token.kind) { case T_IDENTIFIER: if (env->must_be_abstract) { errorf(HERE, "no identifier expected in typename"); } else { - env->symbol = token.symbol; - env->source_position = token.source_position; + env->symbol = token.identifier.symbol; + env->source_position = token.base.source_position; } next_token(); break; - case '(': - /* §6.7.6:2 footnote 126: Empty parentheses in a type name are - * interpreted as ``function with no parameter specification'', rather - * than redundant parentheses around the omitted identifier. */ - if (look_ahead(1)->type != ')') { - next_token(); - add_anchor_token(')'); - inner_types = parse_inner_declarator(env); - if (inner_types != NULL) { - /* All later declarators only modify the return type */ - env->must_be_abstract = true; - } - rem_anchor_token(')'); - expect(')', end_error); - } else if (!env->may_be_abstract) { - errorf(HERE, "declarator must have a name"); - goto error_out; + + case '(': { + /* Parenthesized declarator or function declarator? */ + token_t const *const la1 = look_ahead(1); + switch (la1->kind) { + case T_IDENTIFIER: + if (is_typedef_symbol(la1->identifier.symbol)) { + case ')': + /* §6.7.6:2 footnote 126: Empty parentheses in a type name are + * interpreted as ``function with no parameter specification'', rather + * than redundant parentheses around the omitted identifier. */ + default: + /* Function declarator. */ + if (!env->may_be_abstract) { + errorf(HERE, "function declarator must have a name"); + } + } else { + case '&': + case '(': + case '*': + case '[': + case T___attribute__: /* FIXME __attribute__ might also introduce a parameter of a function declarator. */ + /* Paranthesized declarator. */ + next_token(); + add_anchor_token(')'); + inner_types = parse_inner_declarator(env); + if (inner_types != NULL) { + /* All later declarators only modify the return type */ + env->must_be_abstract = true; + } + rem_anchor_token(')'); + expect(')', end_error); + } + break; } break; + } + default: if (env->may_be_abstract) break; parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL); -error_out: eat_until_anchor(); return NULL; } @@ -3683,7 +3592,7 @@ error_out: for (;;) { construct_type_t *type; - switch (token.type) { + switch (token.kind) { case '(': { scope_t *scope = NULL; if (!env->must_be_abstract) { @@ -3722,6 +3631,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, { construct_type_t *iter = construct_list; for (; iter != NULL; iter = iter->base.next) { + source_position_t const* const pos = &iter->base.pos; switch (iter->kind) { case CONSTRUCT_INVALID: break; @@ -3734,13 +3644,12 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, 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"); + errorf(pos, "function returning function is not allowed"); } else if (is_type_array(skipped_return_type)) { - errorf(HERE, "function returning array is not allowed"); + errorf(pos, "function returning array is not allowed"); } else { - if (skipped_return_type->base.qualifiers != 0 && warning.other) { - warningf(HERE, - "type qualifiers in return type of function type are meaningless"); + if (skipped_return_type->base.qualifiers != 0) { + warningf(WARN_IGNORED_QUALIFIERS, pos, "type qualifiers in return type of function type are meaningless"); } } @@ -3752,7 +3661,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, case CONSTRUCT_POINTER: { if (is_type_reference(skip_typeref(type))) - errorf(HERE, "cannot declare a pointer to reference"); + errorf(pos, "cannot declare a pointer to reference"); parsed_pointer_t *pointer = &iter->pointer; type = make_based_pointer_type(type, pointer->type_qualifiers, pointer->base_variable); @@ -3761,14 +3670,14 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, case CONSTRUCT_REFERENCE: if (is_type_reference(skip_typeref(type))) - errorf(HERE, "cannot declare a reference to reference"); + errorf(pos, "cannot declare a reference to reference"); type = make_reference_type(type); continue; case CONSTRUCT_ARRAY: { if (is_type_reference(skip_typeref(type))) - errorf(HERE, "cannot declare an array of references"); + errorf(pos, "cannot declare an array of references"); parsed_array_t *array = &iter->array; type_t *array_type = allocate_type_zero(TYPE_ARRAY); @@ -3787,45 +3696,43 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, if (size_expression != NULL) { switch (is_constant_expression(size_expression)) { - case EXPR_CLASS_CONSTANT: { - long const size = fold_constant_to_int(size_expression); - array_type->array.size = size; - array_type->array.size_constant = true; - /* §6.7.5.2:1 If the expression is a constant expression, it shall - * have a value greater than zero. */ - if (size <= 0) { - if (size < 0 || !GNU_MODE) { - errorf(&size_expression->base.source_position, - "size of array must be greater than zero"); - } else if (warning.other) { - warningf(&size_expression->base.source_position, - "zero length arrays are a GCC extension"); - } - } - break; + case EXPR_CLASS_CONSTANT: { + long const size = fold_constant_to_int(size_expression); + array_type->array.size = size; + array_type->array.size_constant = true; + /* §6.7.5.2:1 If the expression is a constant expression, + * it shall have a value greater than zero. */ + if (size < 0) { + errorf(&size_expression->base.source_position, + "size of array must be greater than zero"); + } else if (size == 0 && !GNU_MODE) { + errorf(&size_expression->base.source_position, + "size of array must be greater than zero (zero length arrays are a GCC extension)"); } + break; + } - case EXPR_CLASS_VARIABLE: - array_type->array.is_vla = true; - break; + case EXPR_CLASS_VARIABLE: + array_type->array.is_vla = true; + break; - case EXPR_CLASS_ERROR: - break; + case EXPR_CLASS_ERROR: + break; } } type_t *skipped_type = skip_typeref(type); /* §6.7.5.2:1 */ if (is_type_incomplete(skipped_type)) { - errorf(HERE, "array of incomplete type '%T' is not allowed", type); + errorf(pos, "array of incomplete type '%T' is not allowed", type); } else if (is_type_function(skipped_type)) { - errorf(HERE, "array of functions is not allowed"); + errorf(pos, "array of functions is not allowed"); } type = identify_new_type(array_type); continue; } } - internal_errorf(HERE, "invalid type construction found"); + internal_errorf(pos, "invalid type construction found"); } return type; @@ -3836,7 +3743,7 @@ static type_t *automatic_type_conversion(type_t *orig_type); static type_t *semantic_parameter(const source_position_t *pos, type_t *type, const declaration_specifiers_t *specifiers, - symbol_t *symbol) + entity_t const *const param) { /* §6.7.5.3:7 A declaration of a parameter as ``array of type'' * shall be adjusted to ``qualified pointer to type'', @@ -3847,7 +3754,7 @@ static type_t *semantic_parameter(const source_position_t *pos, type = automatic_type_conversion(type); if (specifiers->is_inline && is_type_valid(type)) { - errorf(pos, "parameter '%#T' declared 'inline'", type, symbol); + errorf(pos, "'%N' declared 'inline'", param); } /* §6.9.1:6 The declarations in the declaration list shall contain @@ -3857,7 +3764,7 @@ static type_t *semantic_parameter(const source_position_t *pos, specifiers->storage_class != STORAGE_CLASS_NONE && specifiers->storage_class != STORAGE_CLASS_REGISTER) ) { - errorf(pos, "invalid storage class for parameter '%#T'", type, symbol); + errorf(pos, "invalid storage class for '%N'", param); } /* delay test for incomplete type, because we might have (void) @@ -3892,9 +3799,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, entity_t *entity; if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) { - entity = allocate_entity_zero(ENTITY_TYPEDEF); - entity->base.namespc = NAMESPACE_NORMAL; - entity->base.symbol = env.symbol; + entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol); entity->base.source_position = env.source_position; entity->typedefe.type = orig_type; @@ -3915,7 +3820,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, } else { /* create a declaration type entity */ if (flags & DECL_CREATE_COMPOUND_MEMBER) { - entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER); + entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, env.symbol); if (env.symbol != NULL) { if (specifiers->is_inline && is_type_valid(type)) { @@ -3931,15 +3836,13 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, } } } else if (flags & DECL_IS_PARAMETER) { - orig_type = semantic_parameter(&env.source_position, orig_type, - specifiers, env.symbol); - - entity = allocate_entity_zero(ENTITY_PARAMETER); + entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, env.symbol); + orig_type = semantic_parameter(&env.source_position, orig_type, specifiers, entity); } else if (is_type_function(type)) { - entity = allocate_entity_zero(ENTITY_FUNCTION); - - entity->function.is_inline = specifiers->is_inline; - entity->function.parameters = env.parameters; + entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, env.symbol); + entity->function.is_inline = specifiers->is_inline; + entity->function.elf_visibility = default_visibility; + entity->function.parameters = env.parameters; if (env.symbol != NULL) { /* this needs fixes for C++ */ @@ -3950,19 +3853,17 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, specifiers->storage_class != STORAGE_CLASS_NONE && (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC) )) { - errorf(&env.source_position, - "invalid storage class for function '%Y'", env.symbol); + errorf(&env.source_position, "invalid storage class for '%N'", entity); } } } else { - entity = allocate_entity_zero(ENTITY_VARIABLE); - - entity->variable.thread_local = specifiers->thread_local; + entity = allocate_entity_zero(ENTITY_VARIABLE, NAMESPACE_NORMAL, env.symbol); + entity->variable.elf_visibility = default_visibility; + entity->variable.thread_local = specifiers->thread_local; if (env.symbol != NULL) { if (specifiers->is_inline && is_type_valid(type)) { - errorf(&env.source_position, - "variable '%Y' declared 'inline'", env.symbol); + errorf(&env.source_position, "'%N' declared 'inline'", entity); } bool invalid_storage_class = false; @@ -3979,19 +3880,12 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, } } if (invalid_storage_class) { - errorf(&env.source_position, - "invalid storage class for variable '%Y'", env.symbol); + errorf(&env.source_position, "invalid storage class for variable '%N'", entity); } } } - if (env.symbol != NULL) { - entity->base.symbol = env.symbol; - entity->base.source_position = env.source_position; - } else { - entity->base.source_position = specifiers->source_position; - } - entity->base.namespc = NAMESPACE_NORMAL; + entity->base.source_position = env.symbol != NULL ? env.source_position : specifiers->source_position; entity->declaration.type = orig_type; entity->declaration.alignment = get_type_alignment(orig_type); entity->declaration.modifiers = env.modifiers; @@ -4000,7 +3894,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, storage_class_t storage_class = specifiers->storage_class; entity->declaration.declared_storage_class = storage_class; - if (storage_class == STORAGE_CLASS_NONE && current_function != NULL) + if (storage_class == STORAGE_CLASS_NONE && current_function != NULL) storage_class = STORAGE_CLASS_AUTO; entity->declaration.storage_class = storage_class; } @@ -4044,41 +3938,44 @@ static void check_main(const entity_t *entity) { const source_position_t *pos = &entity->base.source_position; if (entity->kind != ENTITY_FUNCTION) { - warningf(pos, "'main' is not a function"); + warningf(WARN_MAIN, pos, "'main' is not a function"); return; } if (entity->declaration.storage_class == STORAGE_CLASS_STATIC) { - warningf(pos, "'main' is normally a non-static function"); + warningf(WARN_MAIN, pos, "'main' is normally a non-static function"); } type_t *type = skip_typeref(entity->declaration.type); assert(is_type_function(type)); - function_type_t *func_type = &type->function; - if (!types_compatible(skip_typeref(func_type->return_type), type_int)) { - warningf(pos, "return type of 'main' should be 'int', but is '%T'", - func_type->return_type); + function_type_t const *const func_type = &type->function; + type_t *const ret_type = func_type->return_type; + if (!types_compatible(skip_typeref(ret_type), type_int)) { + warningf(WARN_MAIN, pos, "return type of 'main' should be 'int', but is '%T'", ret_type); } const function_parameter_t *parm = func_type->parameters; if (parm != NULL) { - type_t *const first_type = parm->type; - if (!types_compatible(skip_typeref(first_type), type_int)) { - warningf(pos, - "first argument of 'main' should be 'int', but is '%T'", - first_type); + type_t *const first_type = skip_typeref(parm->type); + type_t *const first_type_unqual = get_unqualified_type(first_type); + if (!types_compatible(first_type_unqual, type_int)) { + warningf(WARN_MAIN, pos, "first argument of 'main' should be 'int', but is '%T'", parm->type); } parm = parm->next; if (parm != NULL) { - type_t *const second_type = parm->type; - if (!types_compatible(skip_typeref(second_type), type_char_ptr_ptr)) { - warningf(pos, "second argument of 'main' should be 'char**', but is '%T'", second_type); + type_t *const second_type = skip_typeref(parm->type); + type_t *const second_type_unqual + = get_unqualified_type(second_type); + if (!types_compatible(second_type_unqual, type_char_ptr_ptr)) { + warningf(WARN_MAIN, pos, "second argument of 'main' should be 'char**', but is '%T'", parm->type); } parm = parm->next; if (parm != NULL) { - type_t *const third_type = parm->type; - if (!types_compatible(skip_typeref(third_type), type_char_ptr_ptr)) { - warningf(pos, "third argument of 'main' should be 'char**', but is '%T'", third_type); + type_t *const third_type = skip_typeref(parm->type); + type_t *const third_type_unqual + = get_unqualified_type(third_type); + if (!types_compatible(third_type_unqual, type_char_ptr_ptr)) { + warningf(WARN_MAIN, pos, "third argument of 'main' should be 'char**', but is '%T'", parm->type); } parm = parm->next; if (parm != NULL) @@ -4086,7 +3983,7 @@ static void check_main(const entity_t *entity) } } else { warn_arg_count: - warningf(pos, "'main' takes only zero, two or three arguments"); + warningf(WARN_MAIN, pos, "'main' takes only zero, two or three arguments"); } } } @@ -4102,9 +3999,9 @@ static bool is_sym_main(const symbol_t *const sym) static void error_redefined_as_different_kind(const source_position_t *pos, const entity_t *old, entity_kind_t new_kind) { - errorf(pos, "redeclaration of %s '%Y' as %s (declared %P)", - get_entity_kind_name(old->kind), old->base.symbol, - get_entity_kind_name(new_kind), &old->base.source_position); + char const *const what = get_entity_kind_name(new_kind); + source_position_t const *const ppos = &old->base.source_position; + errorf(pos, "redeclaration of '%N' as %s (declared %P)", old, what, ppos); } static bool is_entity_valid(entity_t *const ent) @@ -4182,35 +4079,30 @@ entity_t *record_entity(entity_t *entity, const bool is_definition) assert(is_type_function(type)); if (type->function.unspecified_parameters && - warning.strict_prototypes && - previous_entity == NULL) { - warningf(pos, "function declaration '%#T' is not a prototype", - orig_type, symbol); + previous_entity == NULL && + !entity->declaration.implicit) { + warningf(WARN_STRICT_PROTOTYPES, pos, "function declaration '%#N' is not a prototype", entity); } - if (warning.main && current_scope == file_scope - && is_sym_main(symbol)) { + if (current_scope == file_scope && is_sym_main(symbol)) { check_main(entity); } } - if (is_declaration(entity) && - warning.nested_externs && - entity->declaration.storage_class == STORAGE_CLASS_EXTERN && - current_scope != file_scope) { - warningf(pos, "nested extern declaration of '%#T'", - entity->declaration.type, symbol); + if (is_declaration(entity) && + entity->declaration.storage_class == STORAGE_CLASS_EXTERN && + current_scope != file_scope && + !entity->declaration.implicit) { + warningf(WARN_NESTED_EXTERNS, pos, "nested extern declaration of '%#N'", entity); } if (previous_entity != NULL) { + source_position_t const *const ppos = &previous_entity->base.source_position; + if (previous_entity->base.parent_scope == ¤t_function->parameters && previous_entity->base.parent_scope->depth + 1 == current_scope->depth) { assert(previous_entity->kind == ENTITY_PARAMETER); - errorf(pos, - "declaration '%#T' redeclares the parameter '%#T' (declared %P)", - entity->declaration.type, symbol, - previous_entity->declaration.type, symbol, - &previous_entity->base.source_position); + errorf(pos, "declaration of '%N' redeclares the '%N' (declared %P)", entity, previous_entity, ppos); goto finish; } @@ -4223,14 +4115,12 @@ entity_t *record_entity(entity_t *entity, const bool is_definition) goto finish; } if (previous_entity->kind == ENTITY_ENUM_VALUE) { - errorf(pos, "redeclaration of enum entry '%Y' (declared %P)", - symbol, &previous_entity->base.source_position); + errorf(pos, "redeclaration of '%N' (declared %P)", entity, ppos); goto finish; } if (previous_entity->kind == ENTITY_TYPEDEF) { /* TODO: C++ allows this for exactly the same type */ - errorf(pos, "redefinition of typedef '%Y' (declared %P)", - symbol, &previous_entity->base.source_position); + errorf(pos, "redefinition of '%N' (declared %P)", entity, ppos); goto finish; } @@ -4251,27 +4141,19 @@ entity_t *record_entity(entity_t *entity, const bool is_definition) return previous_entity; } - type_t *const orig_type = decl->type; - assert(orig_type != NULL); - type_t *const type = skip_typeref(orig_type); + type_t *const type = skip_typeref(decl->type); type_t *const prev_type = skip_typeref(prev_decl->type); if (!types_compatible(type, prev_type)) { - errorf(pos, - "declaration '%#T' is incompatible with '%#T' (declared %P)", - orig_type, symbol, prev_decl->type, symbol, - &previous_entity->base.source_position); + errorf(pos, "declaration '%#N' is incompatible with '%#N' (declared %P)", entity, previous_entity, ppos); } else { unsigned old_storage_class = prev_decl->storage_class; - if (warning.redundant_decls && - is_definition && + if (is_definition && !prev_decl->used && !(prev_decl->modifiers & DM_USED) && prev_decl->storage_class == STORAGE_CLASS_STATIC) { - warningf(&previous_entity->base.source_position, - "unnecessary static forward declaration for '%#T'", - prev_decl->type, symbol); + warningf(WARN_REDUNDANT_DECLS, ppos, "unnecessary static forward declaration for '%#N'", previous_entity); } storage_class_t new_storage_class = decl->storage_class; @@ -4292,11 +4174,8 @@ entity_t *record_entity(entity_t *entity, const bool is_definition) case STORAGE_CLASS_EXTERN: if (is_definition) { - if (warning.missing_prototypes && - prev_type->function.unspecified_parameters && - !is_sym_main(symbol)) { - warningf(pos, "no previous prototype for '%#T'", - orig_type, symbol); + if (prev_type->function.unspecified_parameters && !is_sym_main(symbol)) { + warningf(WARN_MISSING_PROTOTYPES, pos, "no previous prototype for '%#N'", entity); } } else if (new_storage_class == STORAGE_CLASS_NONE) { new_storage_class = STORAGE_CLASS_EXTERN; @@ -4320,20 +4199,14 @@ warn_redundant_declaration: ; if (has_new_attrs) { merge_in_attributes(decl, prev_decl->attributes); } else if (!is_definition && - warning.redundant_decls && is_type_valid(prev_type) && - strcmp(previous_entity->base.source_position.input_name, - "") != 0) { - warningf(pos, - "redundant declaration for '%Y' (declared %P)", - symbol, &previous_entity->base.source_position); + strcmp(ppos->input_name, "") != 0) { + warningf(WARN_REDUNDANT_DECLS, pos, "redundant declaration for '%Y' (declared %P)", symbol, ppos); } } else if (current_function == NULL) { if (old_storage_class != STORAGE_CLASS_STATIC && new_storage_class == STORAGE_CLASS_STATIC) { - errorf(pos, - "static declaration of '%Y' follows non-static declaration (declared %P)", - symbol, &previous_entity->base.source_position); + errorf(pos, "static declaration of '%Y' follows non-static declaration (declared %P)", symbol, ppos); } else if (old_storage_class == STORAGE_CLASS_EXTERN) { prev_decl->storage_class = STORAGE_CLASS_NONE; prev_decl->declared_storage_class = STORAGE_CLASS_NONE; @@ -4346,12 +4219,9 @@ warn_redundant_declaration: ; } else if (is_type_valid(prev_type)) { if (old_storage_class == new_storage_class) { error_redeclaration: - errorf(pos, "redeclaration of '%Y' (declared %P)", - symbol, &previous_entity->base.source_position); + errorf(pos, "redeclaration of '%Y' (declared %P)", symbol, ppos); } else { - errorf(pos, - "redeclaration of '%Y' with different linkage (declared %P)", - symbol, &previous_entity->base.source_position); + errorf(pos, "redeclaration of '%Y' with different linkage (declared %P)", symbol, ppos); } } } @@ -4363,32 +4233,30 @@ error_redeclaration: return previous_entity; } - if (warning.shadow) { - warningf(pos, "%s '%Y' shadows %s (declared %P)", - get_entity_kind_name(entity->kind), symbol, - get_entity_kind_name(previous_entity->kind), - &previous_entity->base.source_position); + warning_t why; + if (is_warn_on(why = WARN_SHADOW) || + (is_warn_on(why = WARN_SHADOW_LOCAL) && previous_entity->base.parent_scope != file_scope)) { + char const *const what = get_entity_kind_name(previous_entity->kind); + warningf(why, pos, "'%N' shadows %s (declared %P)", entity, what, ppos); } } if (entity->kind == ENTITY_FUNCTION) { if (is_definition && - entity->declaration.storage_class != STORAGE_CLASS_STATIC) { - if (warning.missing_prototypes && !is_sym_main(symbol)) { - warningf(pos, "no previous prototype for '%#T'", - entity->declaration.type, symbol); - } else if (warning.missing_declarations && !is_sym_main(symbol)) { - warningf(pos, "no previous declaration for '%#T'", - entity->declaration.type, symbol); + entity->declaration.storage_class != STORAGE_CLASS_STATIC && + !is_sym_main(symbol)) { + if (is_warn_on(WARN_MISSING_PROTOTYPES)) { + warningf(WARN_MISSING_PROTOTYPES, pos, "no previous prototype for '%#N'", entity); + } else { + goto warn_missing_declaration; } } - } else if (warning.missing_declarations && - entity->kind == ENTITY_VARIABLE && - current_scope == file_scope) { - declaration_t *declaration = &entity->declaration; - if (declaration->storage_class == STORAGE_CLASS_NONE) { - warningf(pos, "no previous declaration for '%#T'", - declaration->type, symbol); + } else if (entity->kind == ENTITY_VARIABLE) { + if (current_scope == file_scope && + entity->declaration.storage_class == STORAGE_CLASS_NONE && + !entity->declaration.implicit) { +warn_missing_declaration: + warningf(WARN_MISSING_DECLARATIONS, pos, "no previous declaration for '%#N'", entity); } } @@ -4397,7 +4265,6 @@ finish: assert(current_scope != NULL); entity->base.parent_scope = current_scope; - entity->base.namespc = NAMESPACE_NORMAL; environment_push(entity); append_entity(current_scope, entity); @@ -4411,19 +4278,13 @@ static void parser_error_multiple_definition(entity_t *entity, entity->base.symbol, &entity->base.source_position); } -static bool is_declaration_specifier(const token_t *token, - bool only_specifiers_qualifiers) +static bool is_declaration_specifier(const token_t *token) { - switch (token->type) { - TYPE_SPECIFIERS - TYPE_QUALIFIERS + switch (token->kind) { + DECLARATION_START return true; case T_IDENTIFIER: - return is_typedef_symbol(token->symbol); - - case T___extension__: - STORAGE_CLASSES - return !only_specifiers_qualifiers; + return is_typedef_symbol(token->identifier.symbol); default: return false; @@ -4435,14 +4296,12 @@ static void parse_init_declarator_rest(entity_t *entity) type_t *orig_type = type_error_type; if (entity->base.kind == ENTITY_TYPEDEF) { - errorf(&entity->base.source_position, - "typedef '%Y' is initialized (use __typeof__ instead)", - entity->base.symbol); + source_position_t const *const pos = &entity->base.source_position; + errorf(pos, "'%N' is initialized (use __typeof__ instead)", entity); } else { assert(is_declaration(entity)); orig_type = entity->declaration.type; } - eat('='); type_t *type = skip_typeref(orig_type); @@ -4450,6 +4309,7 @@ static void parse_init_declarator_rest(entity_t *entity) && entity->variable.initializer != NULL) { parser_error_multiple_definition(entity, HERE); } + eat('='); declaration_t *const declaration = &entity->declaration; bool must_be_constant = false; @@ -4459,9 +4319,8 @@ static void parse_init_declarator_rest(entity_t *entity) } if (is_type_function(type)) { - errorf(&entity->base.source_position, - "function '%#T' is initialized like a variable", - orig_type, entity->base.symbol); + source_position_t const *const pos = &entity->base.source_position; + errorf(pos, "'%N' is initialized like a variable", entity); orig_type = type_error_type; } @@ -4469,10 +4328,8 @@ static void parse_init_declarator_rest(entity_t *entity) env.type = orig_type; env.must_be_constant = must_be_constant; env.entity = entity; - current_init_decl = entity; initializer_t *initializer = parse_initializer(&env); - current_init_decl = NULL; if (entity->kind == ENTITY_VARIABLE) { /* §6.7.5:22 array initializers for arrays with unknown size @@ -4489,31 +4346,28 @@ static void parse_anonymous_declaration_rest( eat(';'); anonymous_entity = NULL; - if (warning.other) { - if (specifiers->storage_class != STORAGE_CLASS_NONE || - specifiers->thread_local) { - warningf(&specifiers->source_position, - "useless storage class in empty declaration"); - } + source_position_t const *const pos = &specifiers->source_position; + if (specifiers->storage_class != STORAGE_CLASS_NONE || + specifiers->thread_local) { + warningf(WARN_OTHER, pos, "useless storage class in empty declaration"); + } - type_t *type = specifiers->type; - switch (type->kind) { - case TYPE_COMPOUND_STRUCT: - case TYPE_COMPOUND_UNION: { - if (type->compound.compound->base.symbol == NULL) { - warningf(&specifiers->source_position, - "unnamed struct/union that defines no instances"); - } - break; + type_t *type = specifiers->type; + switch (type->kind) { + case TYPE_COMPOUND_STRUCT: + case TYPE_COMPOUND_UNION: { + if (type->compound.compound->base.symbol == NULL) { + warningf(WARN_OTHER, pos, "unnamed struct/union that defines no instances"); } + break; + } - case TYPE_ENUM: - break; + case TYPE_ENUM: + break; - default: - warningf(&specifiers->source_position, "empty declaration"); - break; - } + default: + warningf(WARN_OTHER, pos, "empty declaration"); + break; } } @@ -4529,8 +4383,7 @@ static void check_variable_type_complete(entity_t *ent) decl->storage_class == STORAGE_CLASS_STATIC) return; - type_t *const orig_type = decl->type; - type_t *const type = skip_typeref(orig_type); + type_t *const type = skip_typeref(decl->type); if (!is_type_incomplete(type)) return; @@ -4541,8 +4394,7 @@ static void check_variable_type_complete(entity_t *ent) return; } - errorf(&ent->base.source_position, "variable '%#T' has incomplete type", - orig_type, ent->base.symbol); + errorf(&ent->base.source_position, "variable '%#N' has incomplete type", ent); } @@ -4554,9 +4406,9 @@ static void parse_declaration_rest(entity_t *ndeclaration, add_anchor_token(';'); add_anchor_token(','); while (true) { - entity_t *entity = finished_declaration(ndeclaration, token.type == '='); + entity_t *entity = finished_declaration(ndeclaration, token.kind == '='); - if (token.type == '=') { + if (token.kind == '=') { parse_init_declarator_rest(entity); } else if (entity->kind == ENTITY_VARIABLE) { /* ISO/IEC 14882:1998(E) §8.5.3:3 The initializer can be omitted @@ -4565,9 +4417,8 @@ static void parse_declaration_rest(entity_t *ndeclaration, if (decl->storage_class != STORAGE_CLASS_EXTERN) { type_t *type = decl->type; if (is_type_reference(skip_typeref(type))) { - errorf(&entity->base.source_position, - "reference '%#T' must be initialized", - type, entity->base.symbol); + source_position_t const *const pos = &entity->base.source_position; + errorf(pos, "reference '%#N' must be initialized", entity); } } } @@ -4592,22 +4443,20 @@ end_error: static entity_t *finished_kr_declaration(entity_t *entity, bool is_definition) { symbol_t *symbol = entity->base.symbol; - if (symbol == NULL) { - errorf(HERE, "anonymous declaration not valid as function parameter"); + if (symbol == NULL) return entity; - } assert(entity->base.namespc == NAMESPACE_NORMAL); entity_t *previous_entity = get_entity(symbol, NAMESPACE_NORMAL); if (previous_entity == NULL || previous_entity->base.parent_scope != current_scope) { - errorf(HERE, "expected declaration of a function parameter, found '%Y'", + errorf(&entity->base.source_position, "expected declaration of a function parameter, found '%Y'", symbol); return entity; } if (is_definition) { - errorf(HERE, "parameter '%Y' is initialised", entity->base.symbol); + errorf(HERE, "'%N' is initialised", entity); } return record_entity(entity, false); @@ -4616,14 +4465,12 @@ static entity_t *finished_kr_declaration(entity_t *entity, bool is_definition) static void parse_declaration(parsed_declaration_func finished_declaration, declarator_flags_t flags) { - declaration_specifiers_t specifiers; - memset(&specifiers, 0, sizeof(specifiers)); - add_anchor_token(';'); + declaration_specifiers_t specifiers; parse_declaration_specifiers(&specifiers); rem_anchor_token(';'); - if (token.type == ';') { + if (token.kind == ';') { parse_anonymous_declaration_rest(&specifiers); } else { entity_t *entity = parse_declarator(&specifiers, flags); @@ -4658,9 +4505,7 @@ static void parse_kr_declaration_list(entity_t *entity) add_anchor_token('{'); - /* push function parameters */ - size_t const top = environment_top(); - scope_t *old_scope = scope_push(&entity->function.parameters); + PUSH_SCOPE(&entity->function.parameters); entity_t *parameter = entity->function.parameters.entities; for ( ; parameter != NULL; parameter = parameter->base.next) { @@ -4671,9 +4516,8 @@ static void parse_kr_declaration_list(entity_t *entity) /* parse declaration list */ for (;;) { - switch (token.type) { + switch (token.kind) { DECLARATION_START - case T___extension__: /* This covers symbols, which are no type, too, and results in * better error messages. The typical cases are misspelled type * names and missing includes. */ @@ -4686,10 +4530,7 @@ static void parse_kr_declaration_list(entity_t *entity) } decl_list_end: - /* pop function parameters */ - assert(current_scope == &entity->function.parameters); - scope_pop(old_scope); - environment_pop_to(top); + POP_SCOPE(); /* update function type */ type_t *new_type = duplicate_type(type); @@ -4726,15 +4567,12 @@ decl_list_end: type_t *parameter_type = parameter->declaration.type; if (parameter_type == NULL) { + source_position_t const* const pos = ¶meter->base.source_position; if (strict_mode) { - errorf(HERE, "no type specified for function parameter '%Y'", - parameter->base.symbol); + errorf(pos, "no type specified for function '%N'", parameter); parameter_type = type_error_type; } else { - if (warning.implicit_int) { - warningf(HERE, "no type specified for function parameter '%Y', using 'int'", - parameter->base.symbol); - } + warningf(WARN_IMPLICIT_INT, pos, "no type specified for function parameter '%N', using 'int'", parameter); parameter_type = type_int; } parameter->declaration.type = parameter_type; @@ -4759,25 +4597,22 @@ decl_list_end: parameter_type = not_promoted; } } - function_parameter_t *const parameter + function_parameter_t *const function_parameter = allocate_parameter(parameter_type); - *anchor = parameter; - anchor = ¶meter->next; + *anchor = function_parameter; + anchor = &function_parameter->next; } new_type->function.parameters = parameters; new_type = identify_new_type(new_type); - if (warning.other && need_incompatible_warning) { - type_t *proto_type_type = proto_type->declaration.type; - warningf(HERE, - "declaration '%#T' is incompatible with '%#T' (declared %P)", - proto_type_type, proto_type->base.symbol, - new_type, entity->base.symbol, - &proto_type->base.source_position); + if (need_incompatible_warning) { + symbol_t const *const sym = entity->base.symbol; + source_position_t const *const pos = &entity->base.source_position; + source_position_t const *const ppos = &proto_type->base.source_position; + warningf(WARN_OTHER, pos, "declaration '%#N' is incompatible with '%#T' (declared %P)", proto_type, new_type, sym, ppos); } - entity->declaration.type = new_type; rem_anchor_token('{'); @@ -4793,9 +4628,8 @@ static void print_in_function(void) { if (first_err) { first_err = false; - diagnosticf("%s: In function '%Y':\n", - current_function->base.base.source_position.input_name, - current_function->base.base.symbol); + char const *const file = current_function->base.base.source_position.input_name; + diagnosticf("%s: In '%N':\n", file, (entity_t const*)current_function); } } @@ -4813,16 +4647,14 @@ static void check_labels(void) continue; label_t *label = goto_statement->label; - - label->used = true; if (label->base.source_position.input_name == NULL) { print_in_function(); - errorf(&goto_statement->base.source_position, - "label '%Y' used but not defined", label->base.symbol); + source_position_t const *const pos = &goto_statement->base.source_position; + errorf(pos, "'%N' used but not defined", (entity_t const*)label); } } - if (warning.unused_label) { + if (is_warn_on(WARN_UNUSED_LABEL)) { for (const label_statement_t *label_statement = label_first; label_statement != NULL; label_statement = label_statement->next) { @@ -4830,14 +4662,14 @@ static void check_labels(void) if (! label->used) { print_in_function(); - warningf(&label_statement->base.source_position, - "label '%Y' defined but not used", label->base.symbol); + source_position_t const *const pos = &label_statement->base.source_position; + warningf(WARN_UNUSED_LABEL, pos, "'%N' defined but not used", (entity_t const*)label); } } } } -static void warn_unused_entity(entity_t *entity, entity_t *last) +static void warn_unused_entity(warning_t const why, entity_t *entity, entity_t *const last) { entity_t const *const end = last != NULL ? last->base.next : NULL; for (; entity != end; entity = entity->base.next) { @@ -4850,14 +4682,10 @@ static void warn_unused_entity(entity_t *entity, entity_t *last) if (!declaration->used) { print_in_function(); - const char *what = get_entity_kind_name(entity->kind); - warningf(&entity->base.source_position, "%s '%Y' is unused", - what, entity->base.symbol); + warningf(why, &entity->base.source_position, "'%N' is unused", entity); } else if (entity->kind == ENTITY_VARIABLE && !entity->variable.read) { print_in_function(); - const char *what = get_entity_kind_name(entity->kind); - warningf(&entity->base.source_position, "%s '%Y' is never read", - what, entity->base.symbol); + warningf(why, &entity->base.source_position, "'%N' is never read", entity); } } } @@ -4869,13 +4697,12 @@ static void check_unused_variables(statement_t *const stmt, void *const env) switch (stmt->kind) { case STATEMENT_DECLARATION: { declaration_statement_t const *const decls = &stmt->declaration; - warn_unused_entity(decls->declarations_begin, - decls->declarations_end); + warn_unused_entity(WARN_UNUSED_VARIABLE, decls->declarations_begin, decls->declarations_end); return; } case STATEMENT_FOR: - warn_unused_entity(stmt->fors.scope.entities, NULL); + warn_unused_entity(WARN_UNUSED_VARIABLE, stmt->fors.scope.entities, NULL); return; default: @@ -4888,15 +4715,15 @@ static void check_unused_variables(statement_t *const stmt, void *const env) */ static void check_declarations(void) { - if (warning.unused_parameter) { + if (is_warn_on(WARN_UNUSED_PARAMETER)) { const scope_t *scope = ¤t_function->parameters; /* do not issue unused warnings for main */ if (!is_sym_main(current_function->base.base.symbol)) { - warn_unused_entity(scope->entities, NULL); + warn_unused_entity(WARN_UNUSED_PARAMETER, scope->entities, NULL); } } - if (warning.unused_variable) { + if (is_warn_on(WARN_UNUSED_VARIABLE)) { walk_statements(current_function->statement, check_unused_variables, NULL); } @@ -5002,9 +4829,6 @@ static bool expression_returns(expression_t const *const expr) return expression_returns(expr->binary.left) && expression_returns(expr->binary.right); - - case EXPR_UNKNOWN: - break; } panic("unhandled expression"); @@ -5056,15 +4880,15 @@ static void check_reachable(statement_t *const stmt) case STATEMENT_DECLARATION: { declaration_statement_t const *const decl = &stmt->declaration; entity_t const * ent = decl->declarations_begin; - entity_t const *const last = decl->declarations_end; + entity_t const *const last_decl = decl->declarations_end; if (ent != NULL) { for (;; ent = ent->base.next) { if (ent->kind == ENTITY_VARIABLE && - ent->variable.initializer != NULL && - !initializer_returns(ent->variable.initializer)) { + ent->variable.initializer != NULL && + !initializer_returns(ent->variable.initializer)) { return; } - if (ent == last) + if (ent == last_decl) break; } } @@ -5309,12 +5133,11 @@ found_break_parent: type_t *const type = skip_typeref(current_function->base.type); assert(is_type_function(type)); type_t *const ret = skip_typeref(type->function.return_type); - if (warning.return_type && - !is_type_atomic(ret, ATOMIC_TYPE_VOID) && + if (!is_type_atomic(ret, ATOMIC_TYPE_VOID) && is_type_valid(ret) && !is_sym_main(current_function->base.base.symbol)) { - warningf(&stmt->base.source_position, - "control reaches end of non-void function"); + source_position_t const *const pos = &stmt->base.source_position; + warningf(WARN_RETURN_TYPE, pos, "control reaches end of non-void function"); } return; } @@ -5447,8 +5270,8 @@ static void check_unreachable(statement_t* const stmt, void *const env) if (!stmt->base.reachable) { expression_t const *const cond = stmt->do_while.condition; if (determine_truth(cond) >= 0) { - warningf(&cond->base.source_position, - "condition of do-while-loop is unreachable"); + source_position_t const *const pos = &cond->base.source_position; + warningf(WARN_UNREACHABLE_CODE, pos, "condition of do-while-loop is unreachable"); } } return; @@ -5458,21 +5281,21 @@ static void check_unreachable(statement_t* const stmt, void *const env) // if init and step are unreachable, cond is unreachable, too if (!stmt->base.reachable && !fors->step_reachable) { - warningf(&stmt->base.source_position, "statement is unreachable"); + goto warn_unreachable; } else { if (!stmt->base.reachable && fors->initialisation != NULL) { - warningf(&fors->initialisation->base.source_position, - "initialisation of for-statement is unreachable"); + source_position_t const *const pos = &fors->initialisation->base.source_position; + warningf(WARN_UNREACHABLE_CODE, pos, "initialisation of for-statement is unreachable"); } if (!fors->condition_reachable && fors->condition != NULL) { - warningf(&fors->condition->base.source_position, - "condition of for-statement is unreachable"); + source_position_t const *const pos = &fors->condition->base.source_position; + warningf(WARN_UNREACHABLE_CODE, pos, "condition of for-statement is unreachable"); } if (!fors->step_reachable && fors->step != NULL) { - warningf(&fors->step->base.source_position, - "step of for-statement is unreachable"); + source_position_t const *const pos = &fors->step->base.source_position; + warningf(WARN_UNREACHABLE_CODE, pos, "step of for-statement is unreachable"); } } return; @@ -5503,8 +5326,10 @@ static void check_unreachable(statement_t* const stmt, void *const env) default: warn_unreachable: - if (!stmt->base.reachable) - warningf(&stmt->base.source_position, "statement is unreachable"); + if (!stmt->base.reachable) { + source_position_t const *const pos = &stmt->base.source_position; + warningf(WARN_UNREACHABLE_CODE, pos, "statement is unreachable"); + } return; } } @@ -5513,15 +5338,13 @@ static void parse_external_declaration(void) { /* function-definitions and declarations both start with declaration * specifiers */ - declaration_specifiers_t specifiers; - memset(&specifiers, 0, sizeof(specifiers)); - add_anchor_token(';'); + declaration_specifiers_t specifiers; parse_declaration_specifiers(&specifiers); rem_anchor_token(';'); /* must be a declaration */ - if (token.type == ';') { + if (token.kind == ';') { parse_anonymous_declaration_rest(&specifiers); return; } @@ -5540,7 +5363,7 @@ static void parse_external_declaration(void) rem_anchor_token(','); /* must be a declaration */ - switch (token.type) { + switch (token.kind) { case ',': case ';': case '=': @@ -5552,7 +5375,7 @@ static void parse_external_declaration(void) /* must be a function definition */ parse_kr_declaration_list(ndeclaration); - if (token.type != '{') { + if (token.kind != '{') { parse_error_expected("while parsing function definition", '{', NULL); eat_until_matching_token(';'); return; @@ -5564,30 +5387,25 @@ static void parse_external_declaration(void) if (!is_type_function(type)) { if (is_type_valid(type)) { - errorf(HERE, "declarator '%#T' has a body but is not a function type", - type, ndeclaration->base.symbol); + errorf(HERE, "declarator '%#N' has a body but is not a function type", ndeclaration); } eat_block(); return; - } else if (is_typeref(orig_type)) { - /* §6.9.1:2 */ - errorf(&ndeclaration->base.source_position, - "type of function definition '%#T' is a typedef", - orig_type, ndeclaration->base.symbol); } - if (warning.aggregate_return && - is_type_compound(skip_typeref(type->function.return_type))) { - warningf(HERE, "function '%Y' returns an aggregate", - ndeclaration->base.symbol); + source_position_t const *const pos = &ndeclaration->base.source_position; + if (is_typeref(orig_type)) { + /* §6.9.1:2 */ + errorf(pos, "type of function definition '%#N' is a typedef", ndeclaration); } - if (warning.traditional && !type->function.unspecified_parameters) { - warningf(HERE, "traditional C rejects ISO C style function definition of function '%Y'", - ndeclaration->base.symbol); + + if (is_type_compound(skip_typeref(type->function.return_type))) { + warningf(WARN_AGGREGATE_RETURN, pos, "'%N' returns an aggregate", ndeclaration); } - if (warning.old_style_definition && type->function.unspecified_parameters) { - warningf(HERE, "old-style function definition '%Y'", - ndeclaration->base.symbol); + if (type->function.unspecified_parameters) { + warningf(WARN_OLD_STYLE_DEFINITION, pos, "old-style definition of '%N'", ndeclaration); + } else { + warningf(WARN_TRADITIONAL, pos, "traditional C rejects ISO C style definition of '%N'", ndeclaration); } /* §6.7.5.3:14 a function definition with () means no @@ -5605,16 +5423,14 @@ static void parse_external_declaration(void) assert(entity->kind == ENTITY_FUNCTION); assert(ndeclaration->kind == ENTITY_FUNCTION); - function_t *function = &entity->function; + function_t *const function = &entity->function; if (ndeclaration != entity) { function->parameters = ndeclaration->function.parameters; } assert(is_declaration(entity)); type = skip_typeref(entity->declaration.type); - /* push function parameters and switch scope */ - size_t const top = environment_top(); - scope_t *old_scope = scope_push(&function->parameters); + PUSH_SCOPE(&function->parameters); entity_t *parameter = function->parameters.entities; for (; parameter != NULL; parameter = parameter->base.next) { @@ -5640,8 +5456,8 @@ static void parse_external_declaration(void) function_t *old_current_function = current_function; entity_t *old_current_entity = current_entity; current_function = function; - current_entity = (entity_t*) function; - current_parent = NULL; + current_entity = entity; + PUSH_PARENT(NULL); goto_first = NULL; goto_anchor = &goto_first; @@ -5653,74 +5469,29 @@ static void parse_external_declaration(void) first_err = true; check_labels(); check_declarations(); - if (warning.return_type || - warning.unreachable_code || - (warning.missing_noreturn - && !(function->base.modifiers & DM_NORETURN))) { + if (is_warn_on(WARN_RETURN_TYPE) || + is_warn_on(WARN_UNREACHABLE_CODE) || + (is_warn_on(WARN_MISSING_NORETURN) && !(function->base.modifiers & DM_NORETURN))) { noreturn_candidate = true; check_reachable(body); - if (warning.unreachable_code) + if (is_warn_on(WARN_UNREACHABLE_CODE)) walk_statements(body, check_unreachable, NULL); - if (warning.missing_noreturn && - noreturn_candidate && + if (noreturn_candidate && !(function->base.modifiers & DM_NORETURN)) { - warningf(&body->base.source_position, - "function '%#T' is candidate for attribute 'noreturn'", - type, entity->base.symbol); + source_position_t const *const pos = &body->base.source_position; + warningf(WARN_MISSING_NORETURN, pos, "function '%#N' is candidate for attribute 'noreturn'", entity); } } - assert(current_parent == NULL); + POP_PARENT(); assert(current_function == function); - assert(current_entity == (entity_t*) function); + assert(current_entity == entity); current_entity = old_current_entity; current_function = old_current_function; label_pop_to(label_stack_top); } - assert(current_scope == &function->parameters); - scope_pop(old_scope); - environment_pop_to(top); -} - -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); - - type->bitfield.base_type = base_type; - type->bitfield.size_expression = size; - - il_size_t bit_size; - type_t *skipped_type = skip_typeref(base_type); - if (!is_type_integer(skipped_type)) { - errorf(HERE, "bitfield base type '%T' is not an integer type", - base_type); - bit_size = 0; - } else { - bit_size = get_type_size(base_type) * 8; - } - - if (is_constant_expression(size) == EXPR_CLASS_CONSTANT) { - long v = fold_constant_to_int(size); - const symbol_t *user_symbol = symbol == NULL ? sym_anonymous : symbol; - - if (v < 0) { - errorf(source_position, "negative width in bit-field '%Y'", - user_symbol); - } else if (v == 0 && symbol != NULL) { - errorf(source_position, "zero width for bit-field '%Y'", - user_symbol); - } else if (bit_size > 0 && (il_size_t)v > bit_size) { - errorf(source_position, "width of '%Y' exceeds its type", - user_symbol); - } else { - type->bitfield.bit_size = v; - } - } - - return type; + POP_SCOPE(); } static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol) @@ -5750,23 +5521,17 @@ static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol) static void check_deprecated(const source_position_t *source_position, const entity_t *entity) { - if (!warning.deprecated_declarations) - return; if (!is_declaration(entity)) return; if ((entity->declaration.modifiers & DM_DEPRECATED) == 0) return; - char const *const prefix = get_entity_kind_name(entity->kind); - const char *deprecated_string - = get_deprecated_string(entity->declaration.attributes); - if (deprecated_string != NULL) { - warningf(source_position, "%s '%Y' is deprecated (declared %P): \"%s\"", - prefix, entity->base.symbol, &entity->base.source_position, - deprecated_string); + source_position_t const *const epos = &entity->base.source_position; + char const *const msg = get_deprecated_string(entity->declaration.attributes); + if (msg != NULL) { + warningf(WARN_DEPRECATED_DECLARATIONS, source_position, "'%N' is deprecated (declared %P): \"%s\"", entity, epos, msg); } else { - warningf(source_position, "%s '%Y' is deprecated (declared %P)", prefix, - entity->base.symbol, &entity->base.source_position); + warningf(WARN_DEPRECATED_DECLARATIONS, source_position, "'%N' is deprecated (declared %P)", entity, epos); } } @@ -5787,12 +5552,19 @@ static expression_t *create_select(const source_position_t *pos, type_t *entry_type = entry->declaration.type; type_t *res_type = get_qualified_type(entry_type, qualifiers); + /* bitfields need special treatment */ + if (entry->compound_member.bitfield) { + unsigned bit_size = entry->compound_member.bit_size; + /* if fewer bits than an int, convert to int (see §6.3.1.1) */ + if (bit_size < get_atomic_type_size(ATOMIC_TYPE_INT) * BITS_PER_BYTE) { + res_type = type_int; + } + } + /* we always do the auto-type conversions; the & and sizeof parser contains * code to revert this! */ select->base.type = automatic_type_conversion(res_type); - if (res_type->kind == TYPE_BITFIELD) { - select->base.type = res_type->bitfield.base_type; - } + return select; } @@ -5826,7 +5598,7 @@ static expression_t *find_create_select(const source_position_t *pos, expression_t *sub_addr = create_select(pos, addr, qualifiers, iter); sub_addr->base.source_position = *pos; - sub_addr->select.implicit = true; + sub_addr->base.implicit = true; return find_create_select(pos, sub_addr, qualifiers, sub_compound, symbol); } @@ -5839,46 +5611,84 @@ static expression_t *find_create_select(const source_position_t *pos, return NULL; } +static void parse_bitfield_member(entity_t *entity) +{ + eat(':'); + + expression_t *size = parse_constant_expression(); + long size_long; + + assert(entity->kind == ENTITY_COMPOUND_MEMBER); + type_t *type = entity->declaration.type; + if (!is_type_integer(skip_typeref(type))) { + errorf(HERE, "bitfield base type '%T' is not an integer type", + type); + } + + if (is_constant_expression(size) != EXPR_CLASS_CONSTANT) { + /* error already reported by parse_constant_expression */ + size_long = get_type_size(type) * 8; + } else { + size_long = fold_constant_to_int(size); + + const symbol_t *symbol = entity->base.symbol; + const symbol_t *user_symbol + = symbol == NULL ? sym_anonymous : symbol; + unsigned bit_size = get_type_size(type) * 8; + if (size_long < 0) { + errorf(HERE, "negative width in bit-field '%Y'", user_symbol); + } else if (size_long == 0 && symbol != NULL) { + errorf(HERE, "zero width for bit-field '%Y'", user_symbol); + } else if (bit_size > 0 && (unsigned)size_long > bit_size) { + errorf(HERE, "width of bitfield '%Y' exceeds its type", + user_symbol); + } else { + /* hope that people don't invent crazy types with more bits + * than our struct can hold */ + assert(size_long < + (1 << sizeof(entity->compound_member.bit_size)*8)); + } + } + + entity->compound_member.bitfield = true; + entity->compound_member.bit_size = (unsigned char)size_long; +} + static void parse_compound_declarators(compound_t *compound, const declaration_specifiers_t *specifiers) { do { entity_t *entity; - if (token.type == ':') { - source_position_t source_position = *HERE; - next_token(); - - type_t *base_type = specifiers->type; - expression_t *size = parse_constant_expression(); + if (token.kind == ':') { + /* anonymous bitfield */ + type_t *type = specifiers->type; + entity_t *entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, + NAMESPACE_NORMAL, NULL); + entity->base.source_position = *HERE; + entity->declaration.declared_storage_class = STORAGE_CLASS_NONE; + entity->declaration.storage_class = STORAGE_CLASS_NONE; + entity->declaration.type = type; - type_t *type = make_bitfield_type(base_type, size, - &source_position, NULL); + parse_bitfield_member(entity); attribute_t *attributes = parse_attributes(NULL); attribute_t **anchor = &attributes; while (*anchor != NULL) anchor = &(*anchor)->next; *anchor = specifiers->attributes; - - entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER); - entity->base.namespc = NAMESPACE_NORMAL; - entity->base.source_position = source_position; - entity->declaration.declared_storage_class = STORAGE_CLASS_NONE; - entity->declaration.storage_class = STORAGE_CLASS_NONE; - entity->declaration.type = type; - entity->declaration.attributes = attributes; - if (attributes != NULL) { handle_entity_attributes(attributes, entity); } + entity->declaration.attributes = attributes; + append_entity(&compound->members, entity); } else { entity = parse_declarator(specifiers, DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER); + source_position_t const *const pos = &entity->base.source_position; if (entity->kind == ENTITY_TYPEDEF) { - errorf(&entity->base.source_position, - "typedef not allowed as compound member"); + errorf(pos, "typedef not allowed as compound member"); } else { assert(entity->kind == ENTITY_COMPOUND_MEMBER); @@ -5887,39 +5697,27 @@ static void parse_compound_declarators(compound_t *compound, if (symbol != NULL) { entity_t *prev = find_compound_entry(compound, symbol); if (prev != NULL) { - errorf(&entity->base.source_position, - "multiple declarations of symbol '%Y' (declared %P)", - symbol, &prev->base.source_position); + source_position_t const *const ppos = &prev->base.source_position; + errorf(pos, "multiple declarations of symbol '%Y' (declared %P)", symbol, ppos); } } - if (token.type == ':') { - source_position_t source_position = *HERE; - next_token(); - expression_t *size = parse_constant_expression(); - - type_t *type = entity->declaration.type; - type_t *bitfield_type = make_bitfield_type(type, size, - &source_position, entity->base.symbol); + if (token.kind == ':') { + parse_bitfield_member(entity); attribute_t *attributes = parse_attributes(NULL); - entity->declaration.type = bitfield_type; handle_entity_attributes(attributes, entity); } else { type_t *orig_type = entity->declaration.type; type_t *type = skip_typeref(orig_type); if (is_type_function(type)) { - errorf(&entity->base.source_position, - "compound member '%Y' must not have function type '%T'", - entity->base.symbol, orig_type); + errorf(pos, "'%N' must not have function type '%T'", entity, orig_type); } else if (is_type_incomplete(type)) { /* §6.7.2.1:16 flexible array member */ if (!is_type_array(type) || - token.type != ';' || - look_ahead(1)->type != '}') { - errorf(&entity->base.source_position, - "compound member '%Y' has incomplete type '%T'", - entity->base.symbol, orig_type); + token.kind != ';' || + look_ahead(1)->kind != '}') { + errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type); } } } @@ -5939,35 +5737,40 @@ static void parse_compound_type_entries(compound_t *compound) eat('{'); add_anchor_token('}'); - 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); + for (;;) { + switch (token.kind) { + DECLARATION_START + case T___extension__: + case T_IDENTIFIER: { + PUSH_EXTENSION(); + declaration_specifiers_t specifiers; + parse_declaration_specifiers(&specifiers); + parse_compound_declarators(compound, &specifiers); + POP_EXTENSION(); + break; + } - parse_compound_declarators(compound, &specifiers); + default: + rem_anchor_token('}'); + expect('}', end_error); +end_error: + /* §6.7.2.1:7 */ + compound->complete = true; + return; + } } - rem_anchor_token('}'); - next_token(); - - /* §6.7.2.1:7 */ - compound->complete = true; } static type_t *parse_typename(void) { declaration_specifiers_t specifiers; - memset(&specifiers, 0, sizeof(specifiers)); parse_declaration_specifiers(&specifiers); if (specifiers.storage_class != STORAGE_CLASS_NONE || specifiers.thread_local) { /* TODO: improve error message, user does probably not know what a * storage class is... */ - errorf(HERE, "typename must not have a storage class"); + errorf(&specifiers.source_position, "typename must not have a storage class"); } type_t *result = parse_abstract_declarator(specifiers.type); @@ -5988,7 +5791,7 @@ struct expression_parser_function_t { parse_expression_infix_function infix_parser; }; -expression_parser_function_t expression_parsers[T_LAST_TOKEN]; +static expression_parser_function_t expression_parsers[T_LAST_TOKEN]; /** * Prints an error message if an expression was expected but not read @@ -5996,7 +5799,7 @@ expression_parser_function_t expression_parsers[T_LAST_TOKEN]; static expression_t *expected_expression_error(void) { /* skip the error message if the error token was read */ - if (token.type != T_ERROR) { + if (token.kind != T_ERROR) { errorf(HERE, "expected expression, got token %K", &token); } next_token(); @@ -6006,12 +5809,12 @@ static expression_t *expected_expression_error(void) static type_t *get_string_type(void) { - return warning.write_strings ? type_const_char_ptr : type_char_ptr; + return is_warn_on(WARN_WRITE_STRINGS) ? type_const_char_ptr : type_char_ptr; } static type_t *get_wide_string_type(void) { - return warning.write_strings ? type_const_wchar_t_ptr : type_wchar_t_ptr; + return is_warn_on(WARN_WRITE_STRINGS) ? type_const_wchar_t_ptr : type_wchar_t_ptr; } /** @@ -6019,17 +5822,17 @@ static type_t *get_wide_string_type(void) */ static expression_t *parse_string_literal(void) { - source_position_t begin = token.source_position; - string_t res = token.literal; - bool is_wide = (token.type == T_WIDE_STRING_LITERAL); + source_position_t begin = token.base.source_position; + string_t res = token.string.string; + bool is_wide = (token.kind == T_WIDE_STRING_LITERAL); next_token(); - while (token.type == T_STRING_LITERAL - || token.type == T_WIDE_STRING_LITERAL) { - warn_string_concat(&token.source_position); - res = concat_strings(&res, &token.literal); + while (token.kind == T_STRING_LITERAL + || token.kind == T_WIDE_STRING_LITERAL) { + warn_string_concat(&token.base.source_position); + res = concat_strings(&res, &token.string.string); next_token(); - is_wide |= token.type == T_WIDE_STRING_LITERAL; + is_wide |= token.kind == T_WIDE_STRING_LITERAL; } expression_t *literal; @@ -6052,10 +5855,9 @@ static expression_t *parse_string_literal(void) static expression_t *parse_boolean_literal(bool value) { expression_t *literal = allocate_expression_zero(EXPR_LITERAL_BOOLEAN); - literal->base.source_position = token.source_position; - literal->base.type = type_bool; - literal->literal.value.begin = value ? "true" : "false"; - literal->literal.value.size = value ? 4 : 5; + literal->base.type = type_bool; + literal->literal.value.begin = value ? "true" : "false"; + literal->literal.value.size = value ? 4 : 5; next_token(); return literal; @@ -6063,20 +5865,18 @@ static expression_t *parse_boolean_literal(bool value) static void warn_traditional_suffix(void) { - if (!warning.traditional) - return; - warningf(&token.source_position, "traditional C rejects the '%Y' suffix", - token.symbol); + warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%S' suffix", + &token.number.suffix); } static void check_integer_suffix(void) { - symbol_t *suffix = token.symbol; - if (suffix == NULL) + const string_t *suffix = &token.number.suffix; + if (suffix->size == 0) return; bool not_traditional = false; - const char *c = suffix->string; + const char *c = suffix->begin; if (*c == 'l' || *c == 'L') { ++c; if (*c == *(c-1)) { @@ -6100,8 +5900,8 @@ static void check_integer_suffix(void) } } if (*c != '\0') { - errorf(&token.source_position, - "invalid suffix '%s' on integer constant", suffix->string); + errorf(&token.base.source_position, + "invalid suffix '%S' on integer constant", suffix); } else if (not_traditional) { warn_traditional_suffix(); } @@ -6109,13 +5909,13 @@ static void check_integer_suffix(void) static type_t *check_floatingpoint_suffix(void) { - symbol_t *suffix = token.symbol; - type_t *type = type_double; - if (suffix == NULL) + const string_t *suffix = &token.number.suffix; + type_t *type = type_double; + if (suffix->size == 0) return type; bool not_traditional = false; - const char *c = suffix->string; + const char *c = suffix->begin; if (*c == 'f' || *c == 'F') { ++c; type = type_float; @@ -6124,8 +5924,8 @@ static type_t *check_floatingpoint_suffix(void) type = type_long_double; } if (*c != '\0') { - errorf(&token.source_position, - "invalid suffix '%s' on floatingpoint constant", suffix->string); + errorf(&token.base.source_position, + "invalid suffix '%S' on floatingpoint constant", suffix); } else if (not_traditional) { warn_traditional_suffix(); } @@ -6141,7 +5941,7 @@ static expression_t *parse_number_literal(void) expression_kind_t kind; type_t *type; - switch (token.type) { + switch (token.kind) { case T_INTEGER: kind = EXPR_LITERAL_INTEGER; check_integer_suffix(); @@ -6170,10 +5970,9 @@ static expression_t *parse_number_literal(void) } expression_t *literal = allocate_expression_zero(kind); - literal->base.source_position = token.source_position; - literal->base.type = type; - literal->literal.value = token.literal; - literal->literal.suffix = token.symbol; + literal->base.type = type; + literal->literal.value = token.number.number; + literal->literal.suffix = token.number.suffix; next_token(); /* integer type depends on the size of the number and the size @@ -6190,17 +5989,16 @@ static expression_t *parse_number_literal(void) static expression_t *parse_character_constant(void) { expression_t *literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER); - literal->base.source_position = token.source_position; - literal->base.type = c_mode & _CXX ? type_char : type_int; - literal->literal.value = token.literal; + literal->base.type = c_mode & _CXX ? type_char : type_int; + literal->literal.value = token.string.string; size_t len = literal->literal.value.size; - if (len != 1) { + if (len > 1) { if (!GNU_MODE && !(c_mode & _C99)) { errorf(HERE, "more than 1 character in character constant"); - } else if (warning.multichar) { + } else { literal->base.type = type_int; - warningf(HERE, "multi-character character constant"); + warningf(WARN_MULTICHAR, HERE, "multi-character character constant"); } } @@ -6214,13 +6012,12 @@ static expression_t *parse_character_constant(void) static expression_t *parse_wide_character_constant(void) { expression_t *literal = allocate_expression_zero(EXPR_LITERAL_WIDE_CHARACTER); - literal->base.source_position = token.source_position; - literal->base.type = type_int; - literal->literal.value = token.literal; + literal->base.type = type_int; + literal->literal.value = token.string.string; size_t len = wstrlen(&literal->literal.value); - if (len != 1) { - warningf(HERE, "multi-character character constant"); + if (len > 1) { + warningf(WARN_MULTICHAR, HERE, "multi-character character constant"); } next_token(); @@ -6236,21 +6033,15 @@ static entity_t *create_implicit_function(symbol_t *symbol, ntype->function.linkage = LINKAGE_C; type_t *type = identify_new_type(ntype); - entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION); + entity_t *const entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, symbol); entity->declaration.storage_class = STORAGE_CLASS_EXTERN; entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN; entity->declaration.type = type; entity->declaration.implicit = true; - entity->base.namespc = NAMESPACE_NORMAL; - entity->base.symbol = symbol; entity->base.source_position = *source_position; - if (current_scope != NULL) { - bool strict_prototypes_old = warning.strict_prototypes; - warning.strict_prototypes = false; + if (current_scope != NULL) record_entity(entity, false); - warning.strict_prototypes = strict_prototypes_old; - } return entity; } @@ -6300,8 +6091,7 @@ type_t *revert_automatic_type_conversion(const expression_t *expression) entity_t *entity = expression->select.compound_entry; assert(is_declaration(entity)); type_t *type = entity->declaration.type; - return get_qualified_type(type, - expression->base.type->base.qualifiers); + return get_qualified_type(type, expression->base.type->base.qualifiers); } case EXPR_UNARY_DEREFERENCE: { @@ -6354,7 +6144,8 @@ static entity_t *lookup_entity(const scope_t *scope, symbol_t *symbol, construct a hashmap here... */ entity_t *entity = scope->entities; for ( ; entity != NULL; entity = entity->base.next) { - if (entity->base.symbol == symbol && entity->base.namespc == namespc) + if (entity->base.symbol == symbol + && (namespace_tag_t)entity->base.namespc == namespc) break; } @@ -6373,11 +6164,11 @@ static entity_t *parse_qualified_identifier(void) entity_t *entity; while (true) { - if (token.type != T_IDENTIFIER) { + if (token.kind != T_IDENTIFIER) { parse_error_expected("while parsing identifier", T_IDENTIFIER, NULL); return create_error_entity(sym_anonymous, ENTITY_VARIABLE); } - symbol = token.symbol; + symbol = token.identifier.symbol; pos = *HERE; next_token(); @@ -6399,19 +6190,18 @@ static entity_t *parse_qualified_identifier(void) default: errorf(&pos, "'%Y' must be a namespace, class, struct or union (but is a %s)", symbol, get_entity_kind_name(entity->kind)); - goto end_error; + + /* skip further qualifications */ + while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {} + + return create_error_entity(sym_anonymous, ENTITY_VARIABLE); } } if (entity == NULL) { - if (!strict_mode && token.type == '(') { + if (!strict_mode && token.kind == '(') { /* an implicitly declared function */ - if (warning.error_implicit_function_declaration) { - errorf(&pos, "implicit declaration of function '%Y'", symbol); - } else if (warning.implicit_function_declaration) { - warningf(&pos, "implicit declaration of function '%Y'", symbol); - } - + warningf(WARN_IMPLICIT_FUNCTION_DECLARATION, &pos, "implicit declaration of function '%Y'", symbol); entity = create_implicit_function(symbol, &pos); } else { errorf(&pos, "unknown identifier '%Y' found.", symbol); @@ -6420,17 +6210,12 @@ static entity_t *parse_qualified_identifier(void) } return entity; - -end_error: - /* skip further qualifications */ - while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {} - - return create_error_entity(sym_anonymous, ENTITY_VARIABLE); } static expression_t *parse_reference(void) { - entity_t *entity = parse_qualified_identifier(); + source_position_t const pos = token.base.source_position; + entity_t *const entity = parse_qualified_identifier(); type_t *orig_type; if (is_declaration(entity)) { @@ -6449,9 +6234,10 @@ static expression_t *parse_reference(void) if (entity->kind == ENTITY_ENUM_VALUE) kind = EXPR_REFERENCE_ENUM_VALUE; - expression_t *expression = allocate_expression_zero(kind); - expression->reference.entity = entity; - expression->base.type = type; + expression_t *expression = allocate_expression_zero(kind); + expression->base.source_position = pos; + expression->base.type = type; + expression->reference.entity = entity; /* this declaration is used */ if (is_declaration(entity)) { @@ -6471,14 +6257,7 @@ static expression_t *parse_reference(void) current_function->need_closure = true; } - check_deprecated(HERE, entity); - - if (warning.init_self && entity == current_init_decl && !in_type_prop - && entity->kind == ENTITY_VARIABLE) { - current_init_decl = NULL; - warningf(HERE, "variable '%#T' is initialized by itself", - entity->declaration.type, entity->base.symbol); - } + check_deprecated(&pos, entity); return expression; } @@ -6515,25 +6294,22 @@ static bool semantic_cast(expression_t *cast) return false; } - if (warning.cast_qual && - is_type_pointer(src_type) && - is_type_pointer(dst_type)) { + if (is_type_pointer(src_type) && is_type_pointer(dst_type)) { type_t *src = skip_typeref(src_type->pointer.points_to); type_t *dst = skip_typeref(dst_type->pointer.points_to); unsigned missing_qualifiers = src->base.qualifiers & ~dst->base.qualifiers; if (missing_qualifiers != 0) { - warningf(pos, - "cast discards qualifiers '%Q' in pointer target type of '%T'", - missing_qualifiers, orig_type_right); + warningf(WARN_CAST_QUAL, pos, "cast discards qualifiers '%Q' in pointer target type of '%T'", missing_qualifiers, orig_type_right); } } return true; } -static expression_t *parse_compound_literal(type_t *type) +static expression_t *parse_compound_literal(source_position_t const *const pos, type_t *type) { expression_t *expression = allocate_expression_zero(EXPR_COMPOUND_LITERAL); + expression->base.source_position = *pos; parse_initializer_env_t env; env.type = type; @@ -6554,21 +6330,22 @@ static expression_t *parse_compound_literal(type_t *type) */ static expression_t *parse_cast(void) { - add_anchor_token(')'); + source_position_t const pos = *HERE; - source_position_t source_position = token.source_position; + eat('('); + add_anchor_token(')'); type_t *type = parse_typename(); rem_anchor_token(')'); expect(')', end_error); - if (token.type == '{') { - return parse_compound_literal(type); + if (token.kind == '{') { + return parse_compound_literal(&pos, type); } expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST); - cast->base.source_position = source_position; + cast->base.source_position = pos; expression_t *value = parse_subexpression(PREC_CAST); cast->base.type = type; @@ -6588,10 +6365,11 @@ end_error: */ static expression_t *parse_statement_expression(void) { - add_anchor_token(')'); - expression_t *expression = allocate_expression_zero(EXPR_STATEMENT); + eat('('); + add_anchor_token(')'); + statement_t *statement = parse_compound_statement(true); statement->compound.stmt_expr = true; expression->statement.statement = statement; @@ -6606,8 +6384,9 @@ static expression_t *parse_statement_expression(void) if (stmt->kind == STATEMENT_EXPRESSION) { type = stmt->expression.expression->base.type; } - } else if (warning.other) { - warningf(&expression->base.source_position, "empty statement expression ({})"); + } else { + source_position_t const *const pos = &expression->base.source_position; + warningf(WARN_OTHER, pos, "empty statement expression ({})"); } expression->base.type = type; @@ -6623,22 +6402,20 @@ end_error: */ static expression_t *parse_parenthesized_expression(void) { - eat('('); - - switch (token.type) { + token_t const* const la1 = look_ahead(1); + switch (la1->kind) { case '{': /* gcc extension: a statement expression */ return parse_statement_expression(); - TYPE_QUALIFIERS - TYPE_SPECIFIERS - return parse_cast(); case T_IDENTIFIER: - if (is_typedef_symbol(token.symbol)) { + if (is_typedef_symbol(la1->identifier.symbol)) { + DECLARATION_START return parse_cast(); } } + eat('('); add_anchor_token(')'); expression_t *result = parse_expression(); result->base.parenthesized = true; @@ -6716,25 +6493,25 @@ static designator_t *parse_designator(void) designator_t *result = allocate_ast_zero(sizeof(result[0])); result->source_position = *HERE; - if (token.type != T_IDENTIFIER) { + if (token.kind != T_IDENTIFIER) { parse_error_expected("while parsing member designator", T_IDENTIFIER, NULL); return NULL; } - result->symbol = token.symbol; + result->symbol = token.identifier.symbol; next_token(); designator_t *last_designator = result; while (true) { if (next_if('.')) { - if (token.type != T_IDENTIFIER) { + if (token.kind != T_IDENTIFIER) { parse_error_expected("while parsing member designator", T_IDENTIFIER, NULL); return NULL; } designator_t *designator = allocate_ast_zero(sizeof(result[0])); designator->source_position = *HERE; - designator->symbol = token.symbol; + designator->symbol = token.identifier.symbol; next_token(); last_designator->next = designator; @@ -6947,7 +6724,7 @@ static expression_t *parse_compare_builtin(void) { expression_t *expression; - switch (token.type) { + switch (token.kind) { case T___builtin_isgreater: expression = allocate_expression_zero(EXPR_BINARY_ISGREATER); break; @@ -7019,40 +6796,27 @@ end_error: } /** - * Return the declaration for a given label symbol or create a new one. - * - * @param symbol the symbol of the label + * Return the label for the current symbol or create a new one. */ -static label_t *get_label(symbol_t *symbol) +static label_t *get_label(void) { - entity_t *label; + assert(token.kind == T_IDENTIFIER); assert(current_function != NULL); - label = get_entity(symbol, NAMESPACE_LABEL); - /* if we found a local label, we already created the declaration */ + entity_t *label = get_entity(token.identifier.symbol, NAMESPACE_LABEL); + /* If we find a local label, we already created the declaration. */ if (label != NULL && label->kind == ENTITY_LOCAL_LABEL) { if (label->base.parent_scope != current_scope) { assert(label->base.parent_scope->depth < current_scope->depth); current_function->goto_to_outer = true; } - return &label->label; + } else if (label == NULL || label->base.parent_scope != ¤t_function->parameters) { + /* There is no matching label in the same function, so create a new one. */ + label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, token.identifier.symbol); + label_push(label); } - label = get_entity(symbol, NAMESPACE_LABEL); - /* if we found a label in the same function, then we already created the - * declaration */ - if (label != NULL - && label->base.parent_scope == ¤t_function->parameters) { - return &label->label; - } - - /* otherwise we need to create a new one */ - label = allocate_entity_zero(ENTITY_LABEL); - label->base.namespc = NAMESPACE_LABEL; - label->base.symbol = symbol; - - label_push(label); - + eat(T_IDENTIFIER); return &label->label; } @@ -7061,28 +6825,24 @@ static label_t *get_label(symbol_t *symbol) */ static expression_t *parse_label_address(void) { - source_position_t source_position = token.source_position; + source_position_t source_position = token.base.source_position; eat(T_ANDAND); - if (token.type != T_IDENTIFIER) { + if (token.kind != T_IDENTIFIER) { parse_error_expected("while parsing label address", T_IDENTIFIER, NULL); - goto end_error; + return create_invalid_expression(); } - symbol_t *symbol = token.symbol; - next_token(); - label_t *label = get_label(symbol); + label_t *const label = get_label(); label->used = true; label->address_taken = true; expression_t *expression = allocate_expression_zero(EXPR_LABEL_ADDRESS); expression->base.source_position = source_position; - /* label address is threaten as a void pointer */ + /* label address is treated as a void pointer */ expression->base.type = type_void_ptr; expression->label_address.label = label; return expression; -end_error: - return create_invalid_expression(); } /** @@ -7092,20 +6852,19 @@ static expression_t *parse_noop_expression(void) { /* the result is a (int)0 */ expression_t *literal = allocate_expression_zero(EXPR_LITERAL_MS_NOOP); - literal->base.type = type_int; - literal->base.source_position = token.source_position; - literal->literal.value.begin = "__noop"; - literal->literal.value.size = 6; + literal->base.type = type_int; + literal->literal.value.begin = "__noop"; + literal->literal.value.size = 6; eat(T___noop); - if (token.type == '(') { + if (token.kind == '(') { /* parse arguments */ eat('('); add_anchor_token(')'); add_anchor_token(','); - if (token.type != ')') do { + if (token.kind != ')') do { (void)parse_assignment_expression(); } while (next_if(',')); } @@ -7122,7 +6881,7 @@ end_error: */ static expression_t *parse_primary_expression(void) { - switch (token.type) { + switch (token.kind) { case T_false: return parse_boolean_literal(false); case T_true: return parse_boolean_literal(true); case T_INTEGER: @@ -7164,13 +6923,15 @@ static expression_t *parse_primary_expression(void) case T_COLONCOLON: return parse_reference(); case T_IDENTIFIER: - if (!is_typedef_symbol(token.symbol)) { + if (!is_typedef_symbol(token.identifier.symbol)) { return parse_reference(); } /* FALLTHROUGH */ - TYPENAME_START { - source_position_t const pos = *HERE; - type_t const *const type = parse_typename(); + DECLARATION_START { + source_position_t const pos = *HERE; + declaration_specifiers_t specifiers; + parse_declaration_specifiers(&specifiers); + type_t const *const type = parse_abstract_declarator(specifiers.type); errorf(&pos, "encountered type '%T' while parsing expression", type); return create_invalid_expression(); } @@ -7181,29 +6942,15 @@ static expression_t *parse_primary_expression(void) return create_invalid_expression(); } -/** - * Check if the expression has the character type and issue a warning then. - */ -static void check_for_char_index_type(const expression_t *expression) -{ - type_t *const type = expression->base.type; - const type_t *const base_type = skip_typeref(type); - - if (is_type_atomic(base_type, ATOMIC_TYPE_CHAR) && - warning.char_subscripts) { - warningf(&expression->base.source_position, - "array subscript has type '%T'", type); - } -} - static expression_t *parse_array_expression(expression_t *left) { - expression_t *expression = allocate_expression_zero(EXPR_ARRAY_ACCESS); + expression_t *const expr = allocate_expression_zero(EXPR_ARRAY_ACCESS); + array_access_expression_t *const arr = &expr->array_access; eat('['); add_anchor_token(']'); - expression_t *inside = parse_expression(); + expression_t *const inside = parse_expression(); type_t *const orig_type_left = left->base.type; type_t *const orig_type_inside = inside->base.type; @@ -7211,36 +6958,53 @@ static expression_t *parse_array_expression(expression_t *left) type_t *const type_left = skip_typeref(orig_type_left); type_t *const type_inside = skip_typeref(orig_type_inside); - type_t *return_type; - array_access_expression_t *array_access = &expression->array_access; + expression_t *ref; + expression_t *idx; + type_t *idx_type; + type_t *res_type; if (is_type_pointer(type_left)) { - return_type = type_left->pointer.points_to; - array_access->array_ref = left; - array_access->index = inside; - check_for_char_index_type(inside); + ref = left; + idx = inside; + idx_type = type_inside; + res_type = type_left->pointer.points_to; + goto check_idx; } else if (is_type_pointer(type_inside)) { - return_type = type_inside->pointer.points_to; - array_access->array_ref = inside; - array_access->index = left; - array_access->flipped = true; - check_for_char_index_type(left); + arr->flipped = true; + ref = inside; + idx = left; + idx_type = type_left; + res_type = type_inside->pointer.points_to; +check_idx: + res_type = automatic_type_conversion(res_type); + if (!is_type_integer(idx_type)) { + errorf(&idx->base.source_position, "array subscript must have integer type"); + } else if (is_type_atomic(idx_type, ATOMIC_TYPE_CHAR)) { + source_position_t const *const pos = &idx->base.source_position; + warningf(WARN_CHAR_SUBSCRIPTS, pos, "array subscript has char type"); + } } else { if (is_type_valid(type_left) && is_type_valid(type_inside)) { - errorf(HERE, - "array access on object with non-pointer types '%T', '%T'", - orig_type_left, orig_type_inside); + errorf(&expr->base.source_position, "invalid types '%T[%T]' for array access", orig_type_left, orig_type_inside); } - return_type = type_error_type; - array_access->array_ref = left; - array_access->index = inside; + res_type = type_error_type; + ref = left; + idx = inside; } - expression->base.type = automatic_type_conversion(return_type); + arr->array_ref = ref; + arr->index = idx; + arr->base.type = res_type; rem_anchor_token(']'); expect(']', end_error); end_error: - return expression; + return expr; +} + +static bool is_bitfield(const expression_t *expression) +{ + return expression->kind == EXPR_SELECT + && expression->select.compound_entry->compound_member.bitfield; } static expression_t *parse_typeprop(expression_kind_t const kind) @@ -7250,29 +7014,32 @@ static expression_t *parse_typeprop(expression_kind_t const kind) eat(kind == EXPR_SIZEOF ? T_sizeof : T___alignof__); - /* we only refer to a type property, mark this case */ - bool old = in_type_prop; - in_type_prop = true; - type_t *orig_type; expression_t *expression; - if (token.type == '(' && is_declaration_specifier(look_ahead(1), true)) { + if (token.kind == '(' && is_declaration_specifier(look_ahead(1))) { + source_position_t const pos = *HERE; next_token(); add_anchor_token(')'); orig_type = parse_typename(); rem_anchor_token(')'); expect(')', end_error); - if (token.type == '{') { + if (token.kind == '{') { /* It was not sizeof(type) after all. It is sizeof of an expression * starting with a compound literal */ - expression = parse_compound_literal(orig_type); + expression = parse_compound_literal(&pos, orig_type); goto typeprop_expression; } } else { expression = parse_subexpression(PREC_UNARY); typeprop_expression: + if (is_bitfield(expression)) { + char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; + errorf(&tp_expression->base.source_position, + "operand of %s expression must not be a bitfield", what); + } + tp_expression->typeprop.tp_expression = expression; orig_type = revert_automatic_type_conversion(expression); @@ -7288,20 +7055,13 @@ typeprop_expression: } else if (type->kind == TYPE_FUNCTION) { if (GNU_MODE) { /* function types are allowed (and return 1) */ - if (warning.other) { - char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; - warningf(&tp_expression->base.source_position, - "%s expression with function argument returns invalid result", what); - } + source_position_t const *const pos = &tp_expression->base.source_position; + char const *const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; + warningf(WARN_OTHER, pos, "%s expression with function argument returns invalid result", what); } else { wrong_type = "function"; } - } else { - if (is_type_incomplete(type)) - wrong_type = "incomplete"; } - if (type->kind == TYPE_BITFIELD) - wrong_type = "bitfield"; if (wrong_type != NULL) { char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; @@ -7311,7 +7071,6 @@ typeprop_expression: } end_error: - in_type_prop = old; return tp_expression; } @@ -7327,16 +7086,16 @@ static expression_t *parse_alignof(void) static expression_t *parse_select_expression(expression_t *addr) { - assert(token.type == '.' || token.type == T_MINUSGREATER); - bool select_left_arrow = (token.type == T_MINUSGREATER); + assert(token.kind == '.' || token.kind == T_MINUSGREATER); + bool select_left_arrow = (token.kind == T_MINUSGREATER); source_position_t const pos = *HERE; next_token(); - if (token.type != T_IDENTIFIER) { + if (token.kind != T_IDENTIFIER) { parse_error_expected("while parsing select", T_IDENTIFIER, NULL); return create_invalid_expression(); } - symbol_t *symbol = token.symbol; + symbol_t *symbol = token.identifier.symbol; next_token(); type_t *const orig_type = addr->base.type; @@ -7431,17 +7190,16 @@ static void check_call_argument(type_t *expected_type, /* report exact scope in error messages (like "in argument 3") */ char buf[64]; snprintf(buf, sizeof(buf), "call argument %u", pos); - report_assign_error(error, expected_type, arg_expr, buf, - &arg_expr->base.source_position); - } else if (warning.traditional || warning.conversion) { + report_assign_error(error, expected_type, arg_expr, buf, + &arg_expr->base.source_position); + } else { type_t *const promoted_type = get_default_promoted_type(arg_type); if (!types_compatible(expected_type_skip, promoted_type) && !types_compatible(expected_type_skip, type_void_ptr) && !types_compatible(type_void_ptr, promoted_type)) { /* Deliberately show the skipped types in this warning */ - warningf(&arg_expr->base.source_position, - "passing call argument %u as '%T' rather than '%T' due to prototype", - pos, expected_type_skip, promoted_type); + source_position_t const *const apos = &arg_expr->base.source_position; + warningf(WARN_TRADITIONAL, apos, "passing call argument %u as '%T' rather than '%T' due to prototype", pos, expected_type_skip, promoted_type); } } } @@ -7538,7 +7296,7 @@ static expression_t *parse_call_expression(expression_t *expression) add_anchor_token(')'); add_anchor_token(','); - if (token.type != ')') { + if (token.kind != ')') { call_argument_t **anchor = &call->arguments; do { call_argument_t *argument = allocate_ast_zero(sizeof(*argument)); @@ -7565,36 +7323,35 @@ static expression_t *parse_call_expression(expression_t *expression) } if (parameter != NULL) { - errorf(HERE, "too few arguments to function '%E'", expression); + errorf(&expression->base.source_position, "too few arguments to function '%E'", expression); } else if (argument != NULL && !function_type->variadic) { - errorf(HERE, "too many arguments to function '%E'", expression); + errorf(&argument->expression->base.source_position, "too many arguments to function '%E'", expression); } } /* do default promotion for other arguments */ for (; argument != NULL; argument = argument->next) { - type_t *type = argument->expression->base.type; - if (!is_type_object(skip_typeref(type))) { + type_t *argument_type = argument->expression->base.type; + if (!is_type_object(skip_typeref(argument_type))) { errorf(&argument->expression->base.source_position, "call argument '%E' must not be void", argument->expression); } - type = get_default_promoted_type(type); + argument_type = get_default_promoted_type(argument_type); argument->expression - = create_implicit_cast(argument->expression, type); + = create_implicit_cast(argument->expression, argument_type); } - check_format(&result->call); + check_format(call); - if (warning.aggregate_return && - is_type_compound(skip_typeref(function_type->return_type))) { - warningf(&result->base.source_position, - "function call has aggregate value"); + if (is_type_compound(skip_typeref(function_type->return_type))) { + source_position_t const *const pos = &expression->base.source_position; + warningf(WARN_AGGREGATE_RETURN, pos, "function call has aggregate value"); } - if (call->function->kind == EXPR_REFERENCE) { - reference_expression_t *reference = &call->function->reference; + if (expression->kind == EXPR_REFERENCE) { + reference_expression_t *reference = &expression->reference; if (reference->entity->kind == ENTITY_FUNCTION && reference->entity->function.btk != bk_none) handle_builtin_argument_restrictions(call); @@ -7645,27 +7402,22 @@ static expression_t const *get_reference_address(expression_t const *expr) static void warn_reference_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.entity->base.symbol); + source_position_t const *const pos = &expr->base.source_position; + entity_t const *const ent = expr->reference.entity; + warningf(WARN_ADDRESS, pos, "the address of '%N' will always evaluate as 'true'", ent); } } static void warn_assignment_in_condition(const expression_t *const expr) { - if (!warning.parentheses) - return; if (expr->base.kind != EXPR_BINARY_ASSIGN) return; if (expr->base.parenthesized) return; - warningf(&expr->base.source_position, - "suggest parentheses around assignment used as truth value"); + source_position_t const *const pos = &expr->base.source_position; + warningf(WARN_PARENTHESES, pos, "suggest parentheses around assignment used as truth value"); } static void semantic_condition(expression_t const *const expr, @@ -7701,7 +7453,7 @@ static expression_t *parse_conditional_expression(expression_t *expression) expression_t *true_expression = expression; bool gnu_cond = false; - if (GNU_MODE && token.type == ':') { + if (GNU_MODE && token.kind == ':') { gnu_cond = true; } else { true_expression = parse_expression(); @@ -7718,7 +7470,8 @@ end_error:; type_t *const false_type = skip_typeref(orig_false_type); /* 6.5.15.3 */ - type_t *result_type; + source_position_t const *const pos = &conditional->base.source_position; + type_t *result_type; if (is_type_atomic(true_type, ATOMIC_TYPE_VOID) || is_type_atomic(false_type, ATOMIC_TYPE_VOID)) { /* ISO/IEC 14882:1998(E) §5.16:2 */ @@ -7727,12 +7480,9 @@ end_error:; } else if (false_expression->kind == EXPR_UNARY_THROW) { result_type = true_type; } else { - 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"); + if (!is_type_atomic(true_type, ATOMIC_TYPE_VOID) || + !is_type_atomic(false_type, ATOMIC_TYPE_VOID)) { + warningf(WARN_OTHER, pos, "ISO C forbids conditional expression with only one void side"); } result_type = type_void; } @@ -7771,11 +7521,7 @@ end_error:; get_unqualified_type(to2))) { to = to1; } else { - if (warning.other) { - warningf(&conditional->base.source_position, - "pointer types '%T' and '%T' in conditional expression are incompatible", - true_type, false_type); - } + warningf(WARN_OTHER, pos, "pointer types '%T' and '%T' in conditional expression are incompatible", true_type, false_type); to = type_void; } @@ -7783,23 +7529,15 @@ end_error:; 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)) { - if (warning.other) { - warningf(&conditional->base.source_position, - "pointer/integer type mismatch in conditional expression ('%T' and '%T')", true_type, false_type); - } + warningf(WARN_OTHER, pos, "pointer/integer type mismatch in conditional expression ('%T' and '%T')", true_type, false_type); result_type = pointer_type; } else { - 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; + goto types_incompatible; } } else { +types_incompatible: if (is_type_valid(true_type) && is_type_valid(false_type)) { - type_error_incompatible("while parsing conditional", - &conditional->base.source_position, true_type, - false_type); + type_error_incompatible("while parsing conditional", pos, true_type, false_type); } result_type = type_error_type; } @@ -7817,12 +7555,9 @@ end_error:; */ static expression_t *parse_extension(void) { - eat(T___extension__); - - bool old_gcc_extension = in_gcc_extension; - in_gcc_extension = true; + PUSH_EXTENSION(); expression_t *expression = parse_subexpression(PREC_UNARY); - in_gcc_extension = old_gcc_extension; + POP_EXTENSION(); return expression; } @@ -7874,10 +7609,9 @@ end_error:; errorf(&value->base.source_position, "operand of delete must have pointer type"); } - } else if (warning.other && - is_type_atomic(skip_typeref(type->pointer.points_to), ATOMIC_TYPE_VOID)) { - warningf(&value->base.source_position, - "deleting 'void*' is undefined"); + } else if (is_type_atomic(skip_typeref(type->pointer.points_to), ATOMIC_TYPE_VOID)) { + source_position_t const *const pos = &value->base.source_position; + warningf(WARN_OTHER, pos, "deleting 'void*' is undefined"); } return result; @@ -7895,7 +7629,7 @@ static expression_t *parse_throw(void) eat(T_throw); expression_t *value = NULL; - switch (token.type) { + switch (token.kind) { EXPRESSION_START { value = parse_assignment_expression(); /* ISO/IEC 14882:1998(E) §15.1:3 */ @@ -7935,10 +7669,8 @@ static bool check_pointer_arithmetic(const source_position_t *source_position, "arithmetic with pointer to incomplete type '%T' not allowed", orig_pointer_type); return false; - } else if (warning.pointer_arith) { - warningf(source_position, - "pointer of type '%T' used in arithmetic", - orig_pointer_type); + } else { + warningf(WARN_POINTER_ARITH, source_position, "pointer of type '%T' used in arithmetic", orig_pointer_type); } } else if (is_type_function(points_to)) { if (!GNU_MODE) { @@ -7946,10 +7678,8 @@ static bool check_pointer_arithmetic(const source_position_t *source_position, "arithmetic with pointer to function type '%T' not allowed", orig_pointer_type); return false; - } else if (warning.pointer_arith) { - warningf(source_position, - "pointer to a function '%T' used in arithmetic", - orig_pointer_type); + } else { + warningf(WARN_POINTER_ARITH, source_position, "pointer to a function '%T' used in arithmetic", orig_pointer_type); } } return true; @@ -8020,9 +7750,8 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression) static void semantic_unexpr_plus(unary_expression_t *expression) { semantic_unexpr_arithmetic(expression); - if (warning.traditional) - warningf(&expression->base.source_position, - "traditional C rejects the unary plus operator"); + source_position_t const *const pos = &expression->base.source_position; + warningf(WARN_TRADITIONAL, pos, "traditional C rejects the unary plus operator"); } static void semantic_not(unary_expression_t *expression) @@ -8082,9 +7811,8 @@ static void set_address_taken(expression_t *expression, bool may_be_register) if (entity->declaration.storage_class == STORAGE_CLASS_REGISTER && !may_be_register) { - errorf(&expression->base.source_position, - "address of register %s '%Y' requested", - get_entity_kind_name(entity->kind), entity->base.symbol); + source_position_t const *const pos = &expression->base.source_position; + errorf(pos, "address of register '%N' requested", entity); } if (entity->kind == ENTITY_VARIABLE) { @@ -8112,10 +7840,9 @@ static void semantic_take_addr(unary_expression_t *expression) if (!is_lvalue(value)) { errorf(&expression->base.source_position, "'&' requires an lvalue"); } - if (type->kind == TYPE_BITFIELD) { + if (is_bitfield(value)) { errorf(&expression->base.source_position, - "'&' not allowed on object with bitfield type '%T'", - type); + "'&' not allowed on bitfield"); } set_address_taken(value, false); @@ -8123,12 +7850,12 @@ 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) \ +#define CREATE_UNARY_EXPRESSION_PARSER(token_kind, unexpression_type, sfunc) \ static expression_t *parse_##unexpression_type(void) \ { \ expression_t *unary_expression \ = allocate_expression_zero(unexpression_type); \ - eat(token_type); \ + eat(token_kind); \ unary_expression->unary.value = parse_subexpression(PREC_UNARY); \ \ sfunc(&unary_expression->unary); \ @@ -8153,13 +7880,13 @@ CREATE_UNARY_EXPRESSION_PARSER(T_PLUSPLUS, EXPR_UNARY_PREFIX_INCREMENT, CREATE_UNARY_EXPRESSION_PARSER(T_MINUSMINUS, EXPR_UNARY_PREFIX_DECREMENT, semantic_incdec) -#define CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(token_type, unexpression_type, \ +#define CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(token_kind, unexpression_type, \ sfunc) \ static expression_t *parse_##unexpression_type(expression_t *left) \ { \ expression_t *unary_expression \ = allocate_expression_zero(unexpression_type); \ - eat(token_type); \ + eat(token_kind); \ unary_expression->unary.value = left; \ \ sfunc(&unary_expression->unary); \ @@ -8265,10 +7992,33 @@ static void semantic_binexpr_arithmetic(binary_expression_t *expression) expression->base.type = arithmetic_type; } +static void semantic_binexpr_integer(binary_expression_t *const expression) +{ + expression_t *const left = expression->left; + expression_t *const right = expression->right; + type_t *const orig_type_left = left->base.type; + type_t *const orig_type_right = right->base.type; + type_t *const type_left = skip_typeref(orig_type_left); + type_t *const type_right = skip_typeref(orig_type_right); + + if (!is_type_integer(type_left) || !is_type_integer(type_right)) { + /* TODO: improve error message */ + if (is_type_valid(type_left) && is_type_valid(type_right)) { + errorf(&expression->base.source_position, + "operation needs integer types"); + } + return; + } + + type_t *const result_type = semantic_arithmetic(type_left, type_right); + expression->left = create_implicit_cast(left, result_type); + expression->right = create_implicit_cast(right, result_type); + expression->base.type = result_type; +} + static void warn_div_by_zero(binary_expression_t const *const expression) { - if (!warning.div_by_zero || - !is_type_integer(expression->base.type)) + if (!is_type_integer(expression->base.type)) return; expression_t const *const right = expression->right; @@ -8276,7 +8026,8 @@ static void warn_div_by_zero(binary_expression_t const *const expression) if (is_type_integer(right->base.type) && is_constant_expression(right) == EXPR_CLASS_CONSTANT && !fold_constant_to_bool(right)) { - warningf(&expression->base.source_position, "division by zero"); + source_position_t const *const pos = &expression->base.source_position; + warningf(WARN_DIV_BY_ZERO, pos, "division by zero"); } } @@ -8301,8 +8052,8 @@ static void warn_addsub_in_shift(const expression_t *const expr) default: return; } - warningf(&expr->base.source_position, - "suggest parentheses around '%c' inside shift", op); + source_position_t const *const pos = &expr->base.source_position; + warningf(WARN_PARENTHESES, pos, "suggest parentheses around '%c' inside shift", op); } static bool semantic_shift(binary_expression_t *expression) @@ -8326,14 +8077,13 @@ static bool semantic_shift(binary_expression_t *expression) type_left = promote_integer(type_left); if (is_constant_expression(right) == EXPR_CLASS_CONSTANT) { - long count = fold_constant_to_int(right); + source_position_t const *const pos = &right->base.source_position; + long const count = fold_constant_to_int(right); if (count < 0) { - warningf(&right->base.source_position, - "shift count must be non-negative"); + warningf(WARN_OTHER, pos, "shift count must be non-negative"); } else if ((unsigned long)count >= get_atomic_type_size(type_left->atomic.akind) * 8) { - warningf(&right->base.source_position, - "shift count must be less than type width"); + warningf(WARN_OTHER, pos, "shift count must be less than type width"); } } @@ -8351,10 +8101,8 @@ static void semantic_shift_op(binary_expression_t *expression) if (!semantic_shift(expression)) return; - if (warning.parentheses) { - warn_addsub_in_shift(left); - warn_addsub_in_shift(right); - } + warn_addsub_in_shift(left); + warn_addsub_in_shift(right); type_t *const orig_type_left = left->base.type; type_t * type_left = skip_typeref(orig_type_left); @@ -8425,8 +8173,8 @@ static void semantic_sub(binary_expression_t *expression) 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"); + } else { + warningf(WARN_OTHER, pos, "subtracting pointers to void"); } } expression->base.type = type_ptrdiff_t; @@ -8447,27 +8195,8 @@ static void warn_string_literal_address(expression_t const* expr) 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"); - } -} - -static void warn_comparison_in_comparison(const expression_t *const expr) -{ - if (expr->base.parenthesized) - return; - switch (expr->base.kind) { - case EXPR_BINARY_LESS: - case EXPR_BINARY_GREATER: - case EXPR_BINARY_LESSEQUAL: - case EXPR_BINARY_GREATEREQUAL: - case EXPR_BINARY_NOTEQUAL: - case EXPR_BINARY_EQUAL: - warningf(&expr->base.source_position, - "comparisons like 'x <= y < z' do not have their mathematical meaning"); - break; - default: - break; + source_position_t const *const pos = &expr->base.source_position; + warningf(WARN_ADDRESS, pos, "comparison with string literal results in unspecified behaviour"); } } @@ -8475,11 +8204,37 @@ static bool maybe_negative(expression_t const *const expr) { switch (is_constant_expression(expr)) { case EXPR_CLASS_ERROR: return false; - case EXPR_CLASS_CONSTANT: return fold_constant_to_int(expr) < 0; + case EXPR_CLASS_CONSTANT: return constant_is_negative(expr); default: return true; } } +static void warn_comparison(source_position_t const *const pos, expression_t const *const expr, expression_t const *const other) +{ + warn_string_literal_address(expr); + + expression_t const* const ref = get_reference_address(expr); + if (ref != NULL && is_null_pointer_constant(other)) { + entity_t const *const ent = ref->reference.entity; + warningf(WARN_ADDRESS, pos, "the address of '%N' will never be NULL", ent); + } + + if (!expr->base.parenthesized) { + switch (expr->base.kind) { + case EXPR_BINARY_LESS: + case EXPR_BINARY_GREATER: + case EXPR_BINARY_LESSEQUAL: + case EXPR_BINARY_GREATEREQUAL: + case EXPR_BINARY_NOTEQUAL: + case EXPR_BINARY_EQUAL: + warningf(WARN_PARENTHESES, pos, "comparisons like 'x <= y < z' do not have their mathematical meaning"); + break; + default: + break; + } + } +} + /** * Check the semantics of comparison expressions. * @@ -8487,32 +8242,12 @@ static bool maybe_negative(expression_t const *const expr) */ static void semantic_comparison(binary_expression_t *expression) { - expression_t *left = expression->left; - expression_t *right = expression->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.entity->base.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.entity->base.symbol); - } - } + source_position_t const *const pos = &expression->base.source_position; + expression_t *const left = expression->left; + expression_t *const right = expression->right; - if (warning.parentheses) { - warn_comparison_in_comparison(left); - warn_comparison_in_comparison(right); - } + warn_comparison(pos, left, right); + warn_comparison(pos, right, left); type_t *orig_type_left = left->base.type; type_t *orig_type_right = right->base.type; @@ -8524,7 +8259,7 @@ static void semantic_comparison(binary_expression_t *expression) type_t *arithmetic_type = semantic_arithmetic(type_left, type_right); /* test for signed vs unsigned compares */ - if (warning.sign_compare && is_type_integer(arithmetic_type)) { + if (is_type_integer(arithmetic_type)) { bool const signed_left = is_type_signed(type_left); bool const signed_right = is_type_signed(type_right); if (signed_left != signed_right) { @@ -8532,8 +8267,7 @@ static void semantic_comparison(binary_expression_t *expression) /* TODO check whether constant value can be represented by other type */ if ((signed_left && maybe_negative(left)) || (signed_right && maybe_negative(right))) { - warningf(&expression->base.source_position, - "comparison between signed and unsigned"); + warningf(WARN_SIGN_COMPARE, pos, "comparison between signed and unsigned"); } } } @@ -8541,12 +8275,10 @@ static void semantic_comparison(binary_expression_t *expression) expression->left = create_implicit_cast(left, arithmetic_type); expression->right = create_implicit_cast(right, arithmetic_type); expression->base.type = arithmetic_type; - if (warning.float_equal && - (expression->base.kind == EXPR_BINARY_EQUAL || + if ((expression->base.kind == EXPR_BINARY_EQUAL || expression->base.kind == EXPR_BINARY_NOTEQUAL) && is_type_float(arithmetic_type)) { - warningf(&expression->base.source_position, - "comparing floating point with == or != is unsafe"); + warningf(WARN_FLOAT_EQUAL, pos, "comparing floating point with == or != is unsafe"); } } else if (is_type_pointer(type_left) && is_type_pointer(type_right)) { /* TODO check compatibility */ @@ -8555,9 +8287,7 @@ static void semantic_comparison(binary_expression_t *expression) } else if (is_type_pointer(type_right)) { expression->left = create_implicit_cast(left, type_right); } else if (is_type_valid(type_left) && is_type_valid(type_right)) { - type_error_incompatible("invalid operands in comparison", - &expression->base.source_position, - type_left, type_right); + type_error_incompatible("invalid operands in comparison", pos, type_left, type_right); } expression->base.type = c_mode & _CXX ? type_bool : type_int; } @@ -8588,33 +8318,33 @@ static bool is_valid_assignment_lhs(expression_t const* const left) type_t *const type_left = skip_typeref(orig_type_left); if (!is_lvalue(left)) { - errorf(HERE, "left hand side '%E' of assignment is not an lvalue", + errorf(&left->base.source_position, "left hand side '%E' of assignment is not an lvalue", left); return false; } if (left->kind == EXPR_REFERENCE && left->reference.entity->kind == ENTITY_FUNCTION) { - errorf(HERE, "cannot assign to function '%E'", left); + errorf(&left->base.source_position, "cannot assign to function '%E'", left); return false; } if (is_type_array(type_left)) { - errorf(HERE, "cannot assign to array '%E'", left); + errorf(&left->base.source_position, "cannot assign to array '%E'", left); return false; } if (type_left->base.qualifiers & TYPE_QUALIFIER_CONST) { - errorf(HERE, "assignment to readonly location '%E' (type '%T')", left, + errorf(&left->base.source_position, "assignment to read-only location '%E' (type '%T')", left, orig_type_left); return false; } if (is_type_incomplete(type_left)) { - errorf(HERE, "left-hand side '%E' of assignment has incomplete type '%T'", + errorf(&left->base.source_position, "left-hand side '%E' of assignment has incomplete type '%T'", left, orig_type_left); return false; } if (is_type_compound(type_left) && has_const_fields(&type_left->compound)) { - errorf(HERE, "cannot assign to '%E' because compound type '%T' has readonly fields", + errorf(&left->base.source_position, "cannot assign to '%E' because compound type '%T' has read-only fields", left, orig_type_left); return false; } @@ -8740,8 +8470,8 @@ static void warn_logical_and_within_or(const expression_t *const expr) return; if (expr->base.parenthesized) return; - warningf(&expr->base.source_position, - "suggest parentheses around && within ||"); + source_position_t const *const pos = &expr->base.source_position; + warningf(WARN_PARENTHESES, pos, "suggest parentheses around && within ||"); } /** @@ -8753,8 +8483,7 @@ static void semantic_logical_op(binary_expression_t *expression) * §6.5.14:2 Each of the operands shall have scalar type. */ semantic_condition(expression->left, "left operand of logical operator"); semantic_condition(expression->right, "right operand of logical operator"); - if (expression->base.kind == EXPR_BINARY_LOGICAL_OR && - warning.parentheses) { + if (expression->base.kind == EXPR_BINARY_LOGICAL_OR) { warn_logical_and_within_or(expression->left); warn_logical_and_within_or(expression->right); } @@ -8794,7 +8523,6 @@ static void semantic_binexpr_assign(binary_expression_t *expression) static bool expression_has_effect(const expression_t *const expr) { switch (expr->kind) { - case EXPR_UNKNOWN: break; case EXPR_INVALID: return true; /* do NOT warn */ case EXPR_REFERENCE: return false; case EXPR_REFERENCE_ENUM_VALUE: return false; @@ -8868,7 +8596,6 @@ static bool expression_has_effect(const expression_t *const expr) return is_type_atomic(type, ATOMIC_TYPE_VOID); } - case EXPR_UNARY_CAST_IMPLICIT: return true; case EXPR_UNARY_ASSUME: return true; case EXPR_UNARY_DELETE: return true; case EXPR_UNARY_DELETE_ARRAY: return true; @@ -8925,12 +8652,10 @@ static bool expression_has_effect(const expression_t *const expr) static void semantic_comma(binary_expression_t *expression) { - if (warning.unused_value) { - const expression_t *const left = expression->left; - if (!expression_has_effect(left)) { - warningf(&left->base.source_position, - "left-hand operand of comma expression has no effect"); - } + const expression_t *const left = expression->left; + if (!expression_has_effect(left)) { + source_position_t const *const pos = &left->base.source_position; + warningf(WARN_UNUSED_VALUE, pos, "left-hand operand of comma expression has no effect"); } expression->base.type = expression->right->base.type; } @@ -8938,12 +8663,12 @@ static void semantic_comma(binary_expression_t *expression) /** * @param prec_r precedence of the right operand */ -#define CREATE_BINEXPR_PARSER(token_type, binexpression_type, prec_r, sfunc) \ +#define CREATE_BINEXPR_PARSER(token_kind, binexpression_type, prec_r, sfunc) \ static expression_t *parse_##binexpression_type(expression_t *left) \ { \ expression_t *binexpr = allocate_expression_zero(binexpression_type); \ binexpr->binary.left = left; \ - eat(token_type); \ + eat(token_kind); \ \ expression_t *right = parse_subexpression(prec_r); \ \ @@ -8966,9 +8691,9 @@ CREATE_BINEXPR_PARSER(T_LESSEQUAL, EXPR_BINARY_LESSEQUAL, PR 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('&', EXPR_BINARY_BITWISE_AND, PREC_EQUALITY, semantic_binexpr_integer) +CREATE_BINEXPR_PARSER('^', EXPR_BINARY_BITWISE_XOR, PREC_AND, semantic_binexpr_integer) +CREATE_BINEXPR_PARSER('|', EXPR_BINARY_BITWISE_OR, PREC_XOR, semantic_binexpr_integer) 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) @@ -8987,13 +8712,12 @@ CREATE_BINEXPR_PARSER(',', EXPR_BINARY_COMMA, PR static expression_t *parse_subexpression(precedence_t precedence) { - if (token.type < 0) { + if (token.kind < 0) { return expected_expression_error(); } expression_parser_function_t *parser - = &expression_parsers[token.type]; - source_position_t source_position = token.source_position; + = &expression_parsers[token.kind]; expression_t *left; if (parser->parser != NULL) { @@ -9002,14 +8726,13 @@ static expression_t *parse_subexpression(precedence_t precedence) left = parse_primary_expression(); } assert(left != NULL); - left->base.source_position = source_position; while (true) { - if (token.type < 0) { + if (token.kind < 0) { return expected_expression_error(); } - parser = &expression_parsers[token.type]; + parser = &expression_parsers[token.kind]; if (parser->infix_parser == NULL) break; if (parser->infix_precedence < precedence) @@ -9018,8 +8741,6 @@ static expression_t *parse_subexpression(precedence_t precedence) left = parser->infix_parser(left); assert(left != NULL); - assert(left->kind != EXPR_UNKNOWN); - left->base.source_position = source_position; } return left; @@ -9037,15 +8758,15 @@ static expression_t *parse_expression(void) * Register a parser for a prefix-like operator. * * @param parser the parser function - * @param token_type the token type of the prefix token + * @param token_kind the token type of the prefix token */ static void register_expression_parser(parse_expression_function parser, - int token_type) + int token_kind) { - expression_parser_function_t *entry = &expression_parsers[token_type]; + expression_parser_function_t *entry = &expression_parsers[token_kind]; if (entry->parser != NULL) { - diagnosticf("for token '%k'\n", (token_type_t)token_type); + diagnosticf("for token '%k'\n", (token_kind_t)token_kind); panic("trying to register multiple expression parsers for a token"); } entry->parser = parser; @@ -9055,16 +8776,16 @@ static void register_expression_parser(parse_expression_function parser, * Register a parser for an infix operator with given precedence. * * @param parser the parser function - * @param token_type the token type of the infix operator + * @param token_kind the token type of the infix operator * @param precedence the precedence of the operator */ static void register_infix_parser(parse_expression_infix_function parser, - int token_type, precedence_t precedence) + int token_kind, precedence_t precedence) { - expression_parser_function_t *entry = &expression_parsers[token_type]; + expression_parser_function_t *entry = &expression_parsers[token_kind]; if (entry->infix_parser != NULL) { - diagnosticf("for token '%k'\n", (token_type_t)token_type); + diagnosticf("for token '%k'\n", (token_kind_t)token_kind); panic("trying to register multiple infix expression parsers for a " "token"); } @@ -9141,17 +8862,17 @@ static asm_argument_t *parse_asm_arguments(bool is_out) asm_argument_t *result = NULL; asm_argument_t **anchor = &result; - while (token.type == T_STRING_LITERAL || token.type == '[') { + while (token.kind == T_STRING_LITERAL || token.kind == '[') { asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0])); memset(argument, 0, sizeof(argument[0])); if (next_if('[')) { - if (token.type != T_IDENTIFIER) { + if (token.kind != T_IDENTIFIER) { parse_error_expected("while parsing asm argument", T_IDENTIFIER, NULL); return NULL; } - argument->symbol = token.symbol; + argument->symbol = token.identifier.symbol; expect(']', end_error); } @@ -9177,7 +8898,7 @@ static asm_argument_t *parse_asm_arguments(bool is_out) size = get_atomic_type_size(akind); } else { flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC; - size = get_atomic_type_size(get_intptr_kind()); + size = get_type_size(type_void_ptr); } do { @@ -9193,7 +8914,7 @@ static asm_argument_t *parse_asm_arguments(bool is_out) value_size = get_atomic_type_size(value_akind); } else if (value_kind == TYPE_POINTER) { value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC; - value_size = get_atomic_type_size(get_intptr_kind()); + value_size = get_type_size(type_void_ptr); } else { break; } @@ -9243,7 +8964,7 @@ static asm_clobber_t *parse_asm_clobbers(void) asm_clobber_t *result = NULL; asm_clobber_t **anchor = &result; - while (token.type == T_STRING_LITERAL) { + while (token.kind == T_STRING_LITERAL) { asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0])); clobber->clobber = parse_string_literals(); @@ -9272,7 +8993,7 @@ static statement_t *parse_asm_statement(void) expect('(', end_error); add_anchor_token(')'); - if (token.type != T_STRING_LITERAL) { + if (token.kind != T_STRING_LITERAL) { parse_error_expected("after asm(", T_STRING_LITERAL, NULL); goto end_of_asm; } @@ -9318,7 +9039,7 @@ end_error: static statement_t *parse_label_inner_statement(statement_t const *const label, char const *const label_kind) { statement_t *inner_stmt; - switch (token.type) { + switch (token.kind) { case '}': errorf(&label->base.source_position, "%s at end of compound statement", label_kind); inner_stmt = create_invalid_statement(); @@ -9337,7 +9058,8 @@ static statement_t *parse_label_inner_statement(statement_t const *const label, default: inner_stmt = parse_statement(); - /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */ + /* ISO/IEC 9899:1999(E) §6.8:1/6.8.2:1 Declarations are no statements */ + /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */ if (inner_stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) { errorf(&inner_stmt->base.source_position, "declaration after %s", label_kind); } @@ -9384,9 +9106,9 @@ static statement_t *parse_case_statement(void) long const val = fold_constant_to_int(end_range); statement->case_label.last_case = val; - if (warning.other && val < statement->case_label.first_case) { + if (val < statement->case_label.first_case) { statement->case_label.is_empty_range = true; - warningf(pos, "empty range specified"); + warningf(WARN_OTHER, pos, "empty range specified"); } } } @@ -9426,7 +9148,7 @@ end_error: statement->case_label.statement = parse_label_inner_statement(statement, "case label"); - POP_PARENT; + POP_PARENT(); return statement; } @@ -9447,8 +9169,7 @@ end_error: if (current_switch != NULL) { const case_label_statement_t *def_label = current_switch->default_label; if (def_label != NULL) { - errorf(HERE, "multiple default labels in one switch (previous declared %P)", - &def_label->base.source_position); + errorf(&statement->base.source_position, "multiple default labels in one switch (previous declared %P)", &def_label->base.source_position); } else { current_switch->default_label = &statement->case_label; @@ -9467,7 +9188,7 @@ end_error: statement->case_label.statement = parse_label_inner_statement(statement, "default label"); - POP_PARENT; + POP_PARENT(); return statement; } @@ -9476,40 +9197,50 @@ end_error: */ static statement_t *parse_label_statement(void) { - assert(token.type == T_IDENTIFIER); - symbol_t *symbol = token.symbol; - label_t *label = get_label(symbol); - statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL); - statement->label.label = label; - - next_token(); + label_t *const label = get_label(); + statement->label.label = label; PUSH_PARENT(statement); /* if statement is already set then the label is defined twice, * otherwise it was just mentioned in a goto/local label declaration so far */ + source_position_t const* const pos = &statement->base.source_position; if (label->statement != NULL) { - errorf(HERE, "duplicate label '%Y' (declared %P)", - symbol, &label->base.source_position); + errorf(pos, "duplicate '%N' (declared %P)", (entity_t const*)label, &label->base.source_position); } else { - label->base.source_position = token.source_position; + label->base.source_position = *pos; label->statement = statement; } eat(':'); + if (token.kind == T___attribute__ && !(c_mode & _CXX)) { + parse_attributes(NULL); // TODO process attributes + } + statement->label.statement = parse_label_inner_statement(statement, "label"); /* remember the labels in a list for later checking */ *label_anchor = &statement->label; label_anchor = &statement->label.next; - POP_PARENT; + POP_PARENT(); return statement; } +static statement_t *parse_inner_statement(void) +{ + statement_t *const stmt = parse_statement(); + /* ISO/IEC 9899:1999(E) §6.8:1/6.8.2:1 Declarations are no statements */ + /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */ + if (stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) { + errorf(&stmt->base.source_position, "declaration as inner statement, use {}"); + } + return stmt; +} + /** * Parse an if statement. */ @@ -9538,20 +9269,29 @@ end_error: rem_anchor_token('{'); add_anchor_token(T_else); - statement_t *const true_stmt = parse_statement(); + statement_t *const true_stmt = parse_inner_statement(); statement->ifs.true_statement = true_stmt; rem_anchor_token(T_else); + if (true_stmt->kind == STATEMENT_EMPTY) { + warningf(WARN_EMPTY_BODY, HERE, + "suggest braces around empty body in an ‘if’ statement"); + } + if (next_if(T_else)) { - statement->ifs.false_statement = parse_statement(); - } else if (warning.parentheses && - true_stmt->kind == STATEMENT_IF && + statement->ifs.false_statement = parse_inner_statement(); + + if (statement->ifs.false_statement->kind == STATEMENT_EMPTY) { + warningf(WARN_EMPTY_BODY, HERE, + "suggest braces around empty body in an ‘if’ statement"); + } + } else if (true_stmt->kind == STATEMENT_IF && true_stmt->ifs.false_statement != NULL) { - warningf(&true_stmt->base.source_position, - "suggest explicit braces to avoid ambiguous 'else'"); + source_position_t const *const pos = &true_stmt->base.source_position; + warningf(WARN_PARENTHESES, pos, "suggest explicit braces to avoid ambiguous 'else'"); } - POP_PARENT; + POP_PARENT(); return statement; } @@ -9562,6 +9302,8 @@ end_error: */ static void check_enum_cases(const switch_statement_t *statement) { + if (!is_warn_on(WARN_SWITCH_ENUM)) + return; const type_t *type = skip_typeref(statement->expression->base.type); if (! is_type_enum(type)) return; @@ -9588,10 +9330,9 @@ static void check_enum_cases(const switch_statement_t *statement) break; } } - if (! found) { - warningf(&statement->base.source_position, - "enumeration value '%Y' not handled in switch", - entry->base.symbol); + if (!found) { + source_position_t const *const pos = &statement->base.source_position; + warningf(WARN_SWITCH_ENUM, pos, "'%N' not handled in switch", entry); } last_value = value; } @@ -9615,12 +9356,8 @@ static statement_t *parse_switch(void) type_t * type = skip_typeref(expr->base.type); if (is_type_integer(type)) { type = promote_integer(type); - if (warning.traditional) { - if (get_rank(type) >= get_akind_rank(ATOMIC_TYPE_LONG)) { - warningf(&expr->base.source_position, - "'%T' switch expression not converted to '%T' in ISO C", - type, type_int); - } + if (get_rank(type) >= get_akind_rank(ATOMIC_TYPE_LONG)) { + warningf(WARN_TRADITIONAL, &expr->base.source_position, "'%T' switch expression not converted to '%T' in ISO C", type, type_int); } } else if (is_type_valid(type)) { errorf(&expr->base.source_position, @@ -9633,20 +9370,18 @@ static statement_t *parse_switch(void) switch_statement_t *rem = current_switch; current_switch = &statement->switchs; - statement->switchs.body = parse_statement(); + statement->switchs.body = parse_inner_statement(); current_switch = rem; - if (warning.switch_default && - statement->switchs.default_label == NULL) { - warningf(&statement->base.source_position, "switch has no default case"); + if (statement->switchs.default_label == NULL) { + warningf(WARN_SWITCH_DEFAULT, &statement->base.source_position, "switch has no default case"); } - if (warning.switch_enum) - check_enum_cases(&statement->switchs); + check_enum_cases(&statement->switchs); - POP_PARENT; + POP_PARENT(); return statement; end_error: - POP_PARENT; + POP_PARENT(); return create_invalid_statement(); } @@ -9655,7 +9390,7 @@ static statement_t *parse_loop_body(statement_t *const loop) statement_t *const rem = current_loop; current_loop = loop; - statement_t *const body = parse_statement(); + statement_t *const body = parse_inner_statement(); current_loop = rem; return body; @@ -9685,10 +9420,10 @@ static statement_t *parse_while(void) statement->whiles.body = parse_loop_body(statement); - POP_PARENT; + POP_PARENT(); return statement; end_error: - POP_PARENT; + POP_PARENT(); return create_invalid_statement(); } @@ -9720,10 +9455,10 @@ static statement_t *parse_do(void) expect(')', end_error); expect(';', end_error); - POP_PARENT; + POP_PARENT(); return statement; end_error: - POP_PARENT; + POP_PARENT(); return create_invalid_statement(); } @@ -9740,33 +9475,28 @@ static statement_t *parse_for(void) add_anchor_token(')'); PUSH_PARENT(statement); + PUSH_SCOPE(&statement->fors.scope); - size_t const top = environment_top(); - scope_t *old_scope = scope_push(&statement->fors.scope); - - bool old_gcc_extension = in_gcc_extension; - while (next_if(T___extension__)) { - in_gcc_extension = true; - } + PUSH_EXTENSION(); if (next_if(';')) { - } else if (is_declaration_specifier(&token, false)) { + } else if (is_declaration_specifier(&token)) { parse_declaration(record_entity, DECL_FLAGS_NONE); } else { add_anchor_token(';'); expression_t *const init = parse_expression(); statement->fors.initialisation = init; mark_vars_read(init, ENT_ANY); - if (warning.unused_value && !expression_has_effect(init)) { - warningf(&init->base.source_position, - "initialisation of 'for'-statement has no effect"); + if (!expression_has_effect(init)) { + warningf(WARN_UNUSED_VALUE, &init->base.source_position, "initialisation of 'for'-statement has no effect"); } rem_anchor_token(';'); expect(';', end_error2); } - in_gcc_extension = old_gcc_extension; - if (token.type != ';') { + POP_EXTENSION(); + + if (token.kind != ';') { add_anchor_token(';'); expression_t *const cond = parse_expression(); statement->fors.condition = cond; @@ -9777,32 +9507,26 @@ static statement_t *parse_for(void) rem_anchor_token(';'); } expect(';', end_error2); - if (token.type != ')') { + if (token.kind != ')') { expression_t *const step = parse_expression(); statement->fors.step = step; mark_vars_read(step, ENT_ANY); - if (warning.unused_value && !expression_has_effect(step)) { - warningf(&step->base.source_position, - "step of 'for'-statement has no effect"); + if (!expression_has_effect(step)) { + warningf(WARN_UNUSED_VALUE, &step->base.source_position, "step of 'for'-statement has no effect"); } } expect(')', end_error2); rem_anchor_token(')'); statement->fors.body = parse_loop_body(statement); - assert(current_scope == &statement->fors.scope); - scope_pop(old_scope); - environment_pop_to(top); - - POP_PARENT; + POP_SCOPE(); + POP_PARENT(); return statement; end_error2: - POP_PARENT; + POP_PARENT(); rem_anchor_token(')'); - assert(current_scope == &statement->fors.scope); - scope_pop(old_scope); - environment_pop_to(top); + POP_SCOPE(); /* fallthrough */ end_error1: @@ -9829,18 +9553,17 @@ static statement_t *parse_goto(void) if (!is_type_pointer(type) && !is_type_integer(type)) { 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); + } else if (type != type_void_ptr) { + warningf(WARN_OTHER, &expression->base.source_position, "type of computed goto expression should be 'void*' not '%T'", type); } expression = create_implicit_cast(expression, type_void_ptr); } statement->gotos.expression = expression; - } else if (token.type == T_IDENTIFIER) { - symbol_t *symbol = token.symbol; - next_token(); - statement->gotos.label = get_label(symbol); + } else if (token.kind == T_IDENTIFIER) { + label_t *const label = get_label(); + label->used = true; + statement->gotos.label = label; } else { if (GNU_MODE) parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL); @@ -9970,12 +9693,11 @@ entity_t *expression_is_variable(const expression_t *expression) */ static statement_t *parse_return(void) { - eat(T_return); - statement_t *statement = allocate_statement_zero(STATEMENT_RETURN); + eat(T_return); expression_t *return_value = NULL; - if (token.type != ';') { + if (token.kind != ';') { return_value = parse_expression(); mark_vars_read(return_value, NULL); } @@ -9995,42 +9717,38 @@ static statement_t *parse_return(void) if (c_mode & _CXX || strict_mode) { errorf(pos, "'return' with a value, in function returning 'void'"); - } else if (warning.other) { - warningf(pos, - "'return' with a value, in function returning 'void'"); + } else { + warningf(WARN_OTHER, pos, "'return' with a value, in function returning 'void'"); } } else if (!(c_mode & _CXX)) { /* ISO/IEC 14882:1998(E) §6.6.3:3 */ /* Only warn in C mode, because GCC does the same */ if (strict_mode) { errorf(pos, "'return' with expression in function returning 'void'"); - } else if (warning.other) { - warningf(pos, - "'return' with expression in function returning 'void'"); + } else { + warningf(WARN_OTHER, pos, "'return' with expression in function returning 'void'"); } } } else { assign_error_t error = semantic_assign(return_type, return_value); - report_assign_error(error, return_type, return_value, "'return'", - pos); + report_assign_error(error, return_type, return_value, "'return'", + pos); } return_value = create_implicit_cast(return_value, return_type); /* check for returning address of a local var */ - if (warning.other && return_value != NULL - && return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) { + if (return_value != NULL && return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) { const expression_t *expression = return_value->unary.value; if (expression_is_local_variable(expression)) { - warningf(pos, "function returns address of local variable"); + warningf(WARN_OTHER, pos, "function returns address of local variable"); } } - } else if (warning.other && !is_type_atomic(return_type, ATOMIC_TYPE_VOID)) { + } else if (!is_type_atomic(return_type, ATOMIC_TYPE_VOID)) { /* ISO/IEC 14882:1998(E) §6.6.3:3 */ if (c_mode & _CXX || strict_mode) { errorf(pos, - "'return' without value, in function returning non-void"); + "'return' without value, in function returning non-void"); } else { - warningf(pos, - "'return' without value, in function returning non-void"); + warningf(WARN_OTHER, pos, "'return' without value, in function returning non-void"); } } statement->returns.value = return_value; @@ -10097,7 +9815,7 @@ static statement_t *parse_ms_try_statment(void) statement->ms_try.try_statement = parse_compound_statement(false); current_try = rem; - POP_PARENT; + POP_PARENT(); if (next_if(T___except)) { expect('(', end_error); @@ -10129,9 +9847,7 @@ end_error: static statement_t *parse_empty_statement(void) { - if (warning.empty_statement) { - warningf(HERE, "statement is empty"); - } + warningf(WARN_EMPTY_STATEMENT, HERE, "statement is empty"); statement_t *const statement = create_empty_statement(); eat(';'); return statement; @@ -10147,23 +9863,20 @@ static statement_t *parse_local_label_declaration(void) entity_t *end = NULL; entity_t **anchor = &begin; do { - if (token.type != T_IDENTIFIER) { + if (token.kind != T_IDENTIFIER) { parse_error_expected("while parsing local label declaration", T_IDENTIFIER, NULL); goto end_error; } - symbol_t *symbol = token.symbol; + symbol_t *symbol = token.identifier.symbol; entity_t *entity = get_entity(symbol, NAMESPACE_LABEL); if (entity != NULL && entity->base.parent_scope == current_scope) { - errorf(HERE, "multiple definitions of '__label__ %Y' (previous definition %P)", - symbol, &entity->base.source_position); + source_position_t const *const ppos = &entity->base.source_position; + errorf(HERE, "multiple definitions of '%N' (previous definition %P)", entity, ppos); } else { - entity = allocate_entity_zero(ENTITY_LOCAL_LABEL); - + entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol); entity->base.parent_scope = current_scope; - entity->base.namespc = NAMESPACE_LABEL; - entity->base.source_position = token.source_position; - entity->base.symbol = symbol; + entity->base.source_position = token.base.source_position; *anchor = entity; anchor = &entity->base.next; @@ -10187,8 +9900,8 @@ static void parse_namespace_definition(void) entity_t *entity = NULL; symbol_t *symbol = NULL; - if (token.type == T_IDENTIFIER) { - symbol = token.symbol; + if (token.kind == T_IDENTIFIER) { + symbol = token.identifier.symbol; next_token(); entity = get_entity(symbol, NAMESPACE_NORMAL); @@ -10196,7 +9909,7 @@ static void parse_namespace_definition(void) && entity->kind != ENTITY_NAMESPACE && entity->base.parent_scope == current_scope) { if (is_entity_valid(entity)) { - error_redefined_as_different_kind(&token.source_position, + error_redefined_as_different_kind(&token.base.source_position, entity, ENTITY_NAMESPACE); } entity = NULL; @@ -10204,14 +9917,12 @@ static void parse_namespace_definition(void) } if (entity == NULL) { - entity = allocate_entity_zero(ENTITY_NAMESPACE); - entity->base.symbol = symbol; - entity->base.source_position = token.source_position; - entity->base.namespc = NAMESPACE_NORMAL; + entity = allocate_entity_zero(ENTITY_NAMESPACE, NAMESPACE_NORMAL, symbol); + entity->base.source_position = token.base.source_position; entity->base.parent_scope = current_scope; } - if (token.type == '=') { + if (token.kind == '=') { /* TODO: parse namespace alias */ panic("namespace alias definition not supported yet"); } @@ -10219,8 +9930,7 @@ static void parse_namespace_definition(void) environment_push(entity); append_entity(current_scope, entity); - size_t const top = environment_top(); - scope_t *old_scope = scope_push(&entity->namespacee.members); + PUSH_SCOPE(&entity->namespacee.members); entity_t *old_current_entity = current_entity; current_entity = entity; @@ -10230,11 +9940,9 @@ static void parse_namespace_definition(void) expect('}', end_error); end_error: - assert(current_scope == &entity->namespacee.members); assert(current_entity == entity); current_entity = old_current_entity; - scope_pop(old_scope); - environment_pop_to(top); + POP_SCOPE(); } /** @@ -10248,12 +9956,12 @@ static statement_t *intern_parse_statement(void) /* declaration or statement */ add_anchor_token(';'); - switch (token.type) { + switch (token.kind) { case T_IDENTIFIER: { - token_type_t la1_type = (token_type_t)look_ahead(1)->type; + token_kind_t la1_type = (token_kind_t)look_ahead(1)->kind; if (la1_type == ':') { statement = parse_label_statement(); - } else if (is_typedef_symbol(token.symbol)) { + } else if (is_typedef_symbol(token.identifier.symbol)) { statement = parse_declaration_statement(); } else { /* it's an identifier, the grammar says this must be an @@ -10263,7 +9971,7 @@ static statement_t *intern_parse_statement(void) switch (la1_type) { case '&': case '*': - if (get_entity(token.symbol, NAMESPACE_NORMAL) != NULL) { + if (get_entity(token.identifier.symbol, NAMESPACE_NORMAL) != NULL) { default: statement = parse_expression_statement(); } else { @@ -10277,15 +9985,14 @@ static statement_t *intern_parse_statement(void) break; } - case T___extension__: + case T___extension__: { /* This can be a prefix to a declaration or an expression statement. * We simply eat it now and parse the rest with tail recursion. */ - while (next_if(T___extension__)) {} - bool old_gcc_extension = in_gcc_extension; - in_gcc_extension = true; + PUSH_EXTENSION(); statement = intern_parse_statement(); - in_gcc_extension = old_gcc_extension; + POP_EXTENSION(); break; + } DECLARATION_START statement = parse_declaration_statement(); @@ -10341,11 +10048,10 @@ static statement_t *parse_statement(void) { statement_t *statement = intern_parse_statement(); - if (statement->kind == STATEMENT_EXPRESSION && warning.unused_value) { + if (statement->kind == STATEMENT_EXPRESSION) { expression_t *expression = statement->expression.expression; if (!expression_has_effect(expression)) { - warningf(&expression->base.source_position, - "statement has no effect"); + warningf(WARN_UNUSED_VALUE, &expression->base.source_position, "statement has no effect"); } } @@ -10360,6 +10066,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) statement_t *statement = allocate_statement_zero(STATEMENT_COMPOUND); PUSH_PARENT(statement); + PUSH_SCOPE(&statement->compound.scope); eat('{'); add_anchor_token('}'); @@ -10452,13 +10159,10 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) add_anchor_token(T_wchar_t); add_anchor_token(T_while); - size_t const top = environment_top(); - scope_t *old_scope = scope_push(&statement->compound.scope); - statement_t **anchor = &statement->compound.statements; bool only_decls_so_far = true; - while (token.type != '}') { - if (token.type == T_EOF) { + while (token.kind != '}') { + if (token.kind == T_EOF) { errorf(&statement->base.source_position, "EOF while parsing compound statement"); break; @@ -10471,13 +10175,11 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) continue; } - if (warning.declaration_after_statement) { - if (sub_statement->kind != STATEMENT_DECLARATION) { - only_decls_so_far = false; - } else if (!only_decls_so_far) { - warningf(&sub_statement->base.source_position, - "ISO C90 forbids mixed declarations and code"); - } + if (sub_statement->kind != STATEMENT_DECLARATION) { + only_decls_so_far = false; + } else if (!only_decls_so_far) { + source_position_t const *const pos = &sub_statement->base.source_position; + warningf(WARN_DECLARATION_AFTER_STATEMENT, pos, "ISO C90 forbids mixed declarations and code"); } *anchor = sub_statement; @@ -10490,7 +10192,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) next_token(); /* look over all statements again to produce no effect warnings */ - if (warning.unused_value) { + if (is_warn_on(WARN_UNUSED_VALUE)) { statement_t *sub_statement = statement->compound.statements; for (; sub_statement != NULL; sub_statement = sub_statement->base.next) { if (sub_statement->kind != STATEMENT_EXPRESSION) @@ -10502,8 +10204,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) expression_t *expression = sub_statement->expression.expression; if (!expression_has_effect(expression)) { - warningf(&expression->base.source_position, - "statement has no effect"); + warningf(WARN_UNUSED_VALUE, &expression->base.source_position, "statement has no effect"); } } } @@ -10596,11 +10297,9 @@ end_error: rem_anchor_token('&'); rem_anchor_token('!'); rem_anchor_token('}'); - assert(current_scope == &statement->compound.scope); - scope_pop(old_scope); - environment_pop_to(top); - POP_PARENT; + POP_SCOPE(); + POP_PARENT(); return statement; } @@ -10609,7 +10308,7 @@ end_error: */ static void check_unused_globals(void) { - if (!warning.unused_function && !warning.unused_variable) + if (!is_warn_on(WARN_UNUSED_FUNCTION) && !is_warn_on(WARN_UNUSED_VARIABLE)) return; for (const entity_t *entity = file_scope->entities; entity != NULL; @@ -10624,20 +10323,21 @@ static void check_unused_globals(void) declaration->storage_class != STORAGE_CLASS_STATIC) continue; - type_t *const type = declaration->type; - const char *s; + warning_t why; + char const *s; if (entity->kind == ENTITY_FUNCTION) { /* inhibit warning for static inline functions */ if (entity->function.is_inline) continue; - s = entity->function.statement != NULL ? "defined" : "declared"; + why = WARN_UNUSED_FUNCTION; + s = entity->function.statement != NULL ? "defined" : "declared"; } else { - s = "defined"; + why = WARN_UNUSED_VARIABLE; + s = "defined"; } - warningf(&declaration->base.source_position, "'%#T' %s but not used", - type, declaration->base.symbol, s); + warningf(why, &declaration->base.source_position, "'%#N' %s but not used", entity, s); } } @@ -10662,7 +10362,8 @@ static void parse_linkage_specification(void) { eat(T_extern); - const char *linkage = parse_string_literals().begin; + source_position_t const pos = *HERE; + char const *const linkage = parse_string_literals().begin; linkage_kind_t old_linkage = current_linkage; linkage_kind_t new_linkage; @@ -10671,7 +10372,7 @@ static void parse_linkage_specification(void) } else if (strcmp(linkage, "C++") == 0) { new_linkage = LINKAGE_CXX; } else { - errorf(HERE, "linkage string \"%s\" not recognized", linkage); + errorf(&pos, "linkage string \"%s\" not recognized", linkage); new_linkage = LINKAGE_INVALID; } current_linkage = new_linkage; @@ -10690,23 +10391,22 @@ end_error: static void parse_external(void) { - switch (token.type) { + switch (token.kind) { + case T_extern: + if (look_ahead(1)->kind == T_STRING_LITERAL) { + parse_linkage_specification(); + } else { DECLARATION_START_NO_EXTERN case T_IDENTIFIER: case T___extension__: /* tokens below are for implicit int */ - case '&': /* & x; -> int& x; (and error later, because C++ has no - implicit int) */ - case '*': /* * x; -> int* x; */ - case '(': /* (x); -> int (x); */ - parse_external_declaration(); - return; - - case T_extern: - if (look_ahead(1)->type == T_STRING_LITERAL) { - parse_linkage_specification(); - } else { + case '&': /* & x; -> int& x; (and error later, because C++ has no + implicit int) */ + case '*': /* * x; -> int* x; */ + case '(': /* (x); -> int (x); */ + PUSH_EXTENSION(); parse_external_declaration(); + POP_EXTENSION(); } return; @@ -10720,8 +10420,7 @@ static void parse_external(void) case ';': if (!strict_mode) { - if (warning.other) - warningf(HERE, "stray ';' outside of function"); + warningf(WARN_STRAY_SEMICOLON, HERE, "stray ';' outside of function"); next_token(); return; } @@ -10729,8 +10428,8 @@ static void parse_external(void) default: errorf(HERE, "stray %K outside of function", &token); - if (token.type == '(' || token.type == '{' || token.type == '[') - eat_until_matching_token(token.type); + if (token.kind == '(' || token.kind == '{' || token.kind == '[') + eat_until_matching_token(token.kind); next_token(); return; } @@ -10743,29 +10442,23 @@ static void parse_externals(void) #ifndef NDEBUG /* make a copy of the anchor set, so we can check if it is restored after parsing */ - unsigned char token_anchor_copy[T_LAST_TOKEN]; + unsigned short token_anchor_copy[T_LAST_TOKEN]; memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy)); #endif - while (token.type != T_EOF && token.type != '}') { + while (token.kind != T_EOF && token.kind != '}') { #ifndef NDEBUG - bool anchor_leak = false; for (int i = 0; i < T_LAST_TOKEN; ++i) { - unsigned char count = token_anchor_set[i] - token_anchor_copy[i]; + unsigned short count = token_anchor_set[i] - token_anchor_copy[i]; if (count != 0) { /* the anchor set and its copy differs */ - errorf(HERE, "Leaked anchor token %k %d times", i, count); - anchor_leak = true; + internal_errorf(HERE, "Leaked anchor token %k %d times", i, count); } } if (in_gcc_extension) { /* an gcc extension scope was not closed */ - errorf(HERE, "Leaked __extension__"); - anchor_leak = true; + internal_errorf(HERE, "Leaked __extension__"); } - - if (anchor_leak) - abort(); #endif parse_external(); @@ -10785,16 +10478,21 @@ static void parse_translation_unit(void) while (true) { parse_externals(); - if (token.type == T_EOF) + if (token.kind == T_EOF) break; errorf(HERE, "stray %K outside of function", &token); - if (token.type == '(' || token.type == '{' || token.type == '[') - eat_until_matching_token(token.type); + if (token.kind == '(' || token.kind == '{' || token.kind == '[') + eat_until_matching_token(token.kind); next_token(); } } +void set_default_visibility(elf_visibility_tag_t visibility) +{ + default_visibility = visibility; +} + /** * Parse the input. * @@ -10847,18 +10545,14 @@ static void complete_incomplete_arrays(void) { size_t n = ARR_LEN(incomplete_arrays); for (size_t i = 0; i != n; ++i) { - declaration_t *const decl = incomplete_arrays[i]; - type_t *const orig_type = decl->type; - type_t *const type = skip_typeref(orig_type); + declaration_t *const decl = incomplete_arrays[i]; + type_t *const type = skip_typeref(decl->type); if (!is_type_incomplete(type)) continue; - if (warning.other) { - warningf(&decl->base.source_position, - "array '%#T' assumed to have one element", - orig_type, decl->base.symbol); - } + source_position_t const *const pos = &decl->base.source_position; + warningf(WARN_OTHER, pos, "array '%#N' assumed to have one element", (entity_t const*)decl); type_t *const new_type = duplicate_type(type); new_type->array.size_constant = true; @@ -10926,9 +10620,6 @@ void init_parser(void) init_expression_parsers(); obstack_init(&temp_obst); - - symbol_t *const va_list_sym = symbol_table_insert("__builtin_va_list"); - type_valist = create_builtin_type(va_list_sym, type_void_ptr); } /**