X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;ds=sidebyside;f=parser.c;h=d60a90d58d66e3e792247d061738ea7da748e66d;hb=d9f64d8f165b5c987cc723765f15b8535af6ac67;hp=baa8797dee0dd9ff949463a327f11a2203a05338;hpb=fda688cb0802286970961e7013217055ce94218f;p=cparser diff --git a/parser.c b/parser.c index baa8797..d60a90d 100644 --- a/parser.c +++ b/parser.c @@ -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,8 +100,6 @@ 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; @@ -111,16 +108,33 @@ static declaration_t **incomplete_arrays; static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT; -#define PUSH_PARENT(stmt) \ - statement_t *const prev_parent = current_parent; \ - ((void)(current_parent = (stmt))) -#define POP_PARENT ((void)(current_parent = prev_parent)) +#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) @@ -404,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. * @@ -664,9 +669,9 @@ static void type_error_incompatible(const char *msg, 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.type != (expected)) \ + goto error_label; \ } \ next_token(); \ } while (0) @@ -882,23 +887,6 @@ static type_t *promote_integer(type_t *type) 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. * @@ -907,8 +895,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; @@ -938,7 +925,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 { @@ -950,10 +942,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); @@ -963,48 +952,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: @@ -1095,9 +1065,7 @@ 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) @@ -1135,7 +1103,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; } @@ -1204,9 +1173,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(); @@ -1269,9 +1237,7 @@ static attribute_t *parse_attribute_gnu_single(void) char const *const name = symbol->string; for (kind = ATTRIBUTE_GNU_FIRST;; ++kind) { if (kind > ATTRIBUTE_GNU_LAST) { - if (warning.attribute) { - warningf(HERE, "unknown attribute '%s' ignored", name); - } + warningf(WARN_ATTRIBUTE, HERE, "unknown attribute '%s' ignored", name); /* TODO: we should still save the attribute in the list... */ kind = ATTRIBUTE_UNKNOWN; break; @@ -1283,9 +1249,8 @@ static attribute_t *parse_attribute_gnu_single(void) break; } - next_token(); - attribute_t *attribute = allocate_attribute_zero(kind); + next_token(); /* parse arguments */ if (next_if('(')) @@ -1339,31 +1304,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: /* TODO record modifier */ - if (warning.other) - warningf(HERE, "Ignoring declaration modifier %K", &token); - eat(T___thiscall); + warningf(WARN_OTHER, HERE, "Ignoring declaration modifier %K", &token); attribute = allocate_attribute_zero(ATTRIBUTE_MS_THISCALL); + eat(T___thiscall); break; default: @@ -1529,7 +1493,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); @@ -1751,8 +1714,7 @@ static initializer_t *parse_scalar_initializer(type_t *type, /* there might be extra {} hierarchies */ int braces = 0; if (token.type == '{') { - if (warning.other) - warningf(HERE, "extra curly braces around scalar initializer"); + warningf(WARN_OTHER, HERE, "extra curly braces around scalar initializer"); do { eat('{'); ++braces; @@ -1781,8 +1743,8 @@ static initializer_t *parse_scalar_initializer(type_t *type, while (braces > 0) { next_if(','); if (token.type != '}') { - if (!additional_warning_displayed && warning.other) { - warningf(HERE, "additional elements in scalar initializer"); + if (!additional_warning_displayed) { + warningf(WARN_OTHER, HERE, "additional elements in scalar initializer"); additional_warning_displayed = true; } } @@ -2201,13 +2163,11 @@ finish_designator: goto error_parse_next; } - if (warning.other) { - source_position_t const* const pos = &expression->base.source_position; - if (env->entity != NULL) { - warningf(pos, "excess elements in initializer for '%Y'", env->entity->base.symbol); - } else { - warningf(pos, "excess elements in initializer"); - } + 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; } @@ -2219,9 +2179,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.type != '}') { + warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", orig_type); } /* TODO: eat , ... */ return sub; @@ -2433,9 +2392,8 @@ static compound_t *parse_compound_type_specifier(bool is_struct) * existing definition in outer scope */ entity = NULL; } else if (entity->compound.complete && token.type == '{') { - errorf(&pos, "multiple definitions of '%s %Y' (previous definition %P)", - is_struct ? "struct" : "union", symbol, - &entity->base.source_position); + 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 */ entity->compound.members.entities = NULL; } @@ -2540,8 +2498,8 @@ static type_t *parse_enum_specifier(void) * existing definition in outer scope */ entity = NULL; } else if (entity->enume.complete && token.type == '{') { - errorf(&pos, "multiple definitions of 'enum %Y' (previous definition %P)", - symbol, &entity->base.source_position); + source_position_t const *const ppos = &entity->base.source_position; + errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos); } } break; @@ -2609,14 +2567,6 @@ 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) { case T_IDENTIFIER: if (is_typedef_symbol(token.symbol)) { @@ -2629,8 +2579,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); @@ -2738,16 +2686,16 @@ 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); } - eat(T_IDENTIFIER); } else { parse_error_expected("while parsing __declspec", T_IDENTIFIER, NULL); return NULL; } attribute_t *attribute = allocate_attribute_zero(kind); + eat(T_IDENTIFIER); if (kind == ATTRIBUTE_MS_PROPERTY) { return parse_attribute_ms_property(attribute); @@ -2812,12 +2760,11 @@ 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; memset(specifiers, 0, sizeof(*specifiers)); specifiers->source_position = token.source_position; @@ -2889,11 +2836,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: \ @@ -2947,11 +2889,8 @@ wrong_thread_storage_class: next_token(); break; -#define CHECK_DOUBLE_TYPE() \ - do { \ - if ( type != NULL) \ - errorf(HERE, "multiple data types in declaration specifiers"); \ - } while(0) +#define CHECK_DOUBLE_TYPE() \ + (type != NULL ? errorf(HERE, "multiple types in declaration specifiers") : (void)0) case T_struct: CHECK_DOUBLE_TYPE(); @@ -3047,8 +2986,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; @@ -3112,10 +3049,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: @@ -3194,9 +3128,7 @@ warn_about_long_long: if (!saw_error) { /* ISO/IEC 14882:1998(E) §C.1.5:4 */ if (!(c_mode & _CXX) && !strict_mode) { - if (warning.implicit_int) { - warningf(pos, "no type specifiers in declaration, using 'int'"); - } + warningf(WARN_IMPLICIT_INT, pos, "no type specifiers in declaration, using 'int'"); atomic_type = ATOMIC_TYPE_INT; break; } else { @@ -3308,9 +3240,7 @@ 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); } } @@ -3368,7 +3298,6 @@ static void parse_parameters(function_type_t *type, scope_t *scope) goto parameters_finished; case T_IDENTIFIER: - case T___extension__: DECLARATION_START { entity_t *entity = parse_parameter(); @@ -3721,8 +3650,8 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, } else if (is_type_array(skipped_return_type)) { errorf(pos, "function returning array is not allowed"); } else { - if (skipped_return_type->base.qualifiers != 0 && warning.other) { - warningf(pos, "type qualifiers in return type of function type are meaningless"); + if (skipped_return_type->base.qualifiers != 0) { + warningf(WARN_OTHER, pos, "type qualifiers in return type of function type are meaningless"); } } @@ -3816,7 +3745,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'', @@ -3827,7 +3756,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 @@ -3837,7 +3766,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) @@ -3909,10 +3838,8 @@ 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, NAMESPACE_NORMAL, env.symbol); + 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, NAMESPACE_NORMAL, env.symbol); entity->function.is_inline = specifiers->is_inline; @@ -3928,8 +3855,7 @@ 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 { @@ -3939,8 +3865,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, 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; @@ -3957,8 +3882,7 @@ 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); } } } @@ -4016,30 +3940,28 @@ 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 = skip_typeref(parm->type); type_t *const first_type_unqual = get_unqualified_type(first_type); if (!types_compatible(first_type_unqual, type_int)) { - warningf(pos, - "first argument of 'main' should be 'int', but is '%T'", - parm->type); + warningf(WARN_MAIN, pos, "first argument of 'main' should be 'int', but is '%T'", parm->type); } parm = parm->next; if (parm != NULL) { @@ -4047,8 +3969,7 @@ static void check_main(const entity_t *entity) type_t *const second_type_unqual = get_unqualified_type(second_type); if (!types_compatible(second_type_unqual, type_char_ptr_ptr)) { - warningf(pos, "second argument of 'main' should be 'char**', but is '%T'", - parm->type); + warningf(WARN_MAIN, pos, "second argument of 'main' should be 'char**', but is '%T'", parm->type); } parm = parm->next; if (parm != NULL) { @@ -4056,8 +3977,7 @@ static void check_main(const entity_t *entity) type_t *const third_type_unqual = get_unqualified_type(third_type); if (!types_compatible(third_type_unqual, type_char_ptr_ptr)) { - warningf(pos, "third argument of 'main' should be 'char**', but is '%T'", - parm->type); + warningf(WARN_MAIN, pos, "third argument of 'main' should be 'char**', but is '%T'", parm->type); } parm = parm->next; if (parm != NULL) @@ -4065,7 +3985,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"); } } } @@ -4081,9 +4001,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) @@ -4161,35 +4081,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; } @@ -4202,14 +4117,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; } @@ -4230,27 +4143,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; @@ -4271,11 +4176,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; @@ -4299,20 +4201,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; @@ -4325,12 +4221,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); } } } @@ -4342,33 +4235,30 @@ error_redeclaration: return previous_entity; } - if (warning.shadow || - (warning.shadow_local && previous_entity->base.parent_scope != file_scope)) { - 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); } } @@ -4408,9 +4298,8 @@ 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; @@ -4432,9 +4321,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; } @@ -4442,10 +4330,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 @@ -4462,31 +4348,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; } } @@ -4502,8 +4385,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; @@ -4514,8 +4396,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); } @@ -4538,9 +4419,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); } } } @@ -4578,7 +4458,7 @@ static entity_t *finished_kr_declaration(entity_t *entity, bool is_definition) } if (is_definition) { - errorf(HERE, "parameter '%Y' is initialised", entity->base.symbol); + errorf(HERE, "'%N' is initialised", entity); } return record_entity(entity, false); @@ -4627,9 +4507,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) { @@ -4642,7 +4520,6 @@ static void parse_kr_declaration_list(entity_t *entity) for (;;) { switch (token.type) { 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. */ @@ -4655,10 +4532,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); @@ -4697,12 +4571,10 @@ decl_list_end: if (parameter_type == NULL) { source_position_t const* const pos = ¶meter->base.source_position; if (strict_mode) { - errorf(pos, "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(pos, "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; @@ -4737,15 +4609,12 @@ decl_list_end: 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(&entity->base.source_position, - "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('{'); @@ -4761,9 +4630,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); } } @@ -4783,12 +4651,12 @@ static void check_labels(void) label_t *label = goto_statement->label; 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) { @@ -4796,14 +4664,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) { @@ -4816,14 +4684,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); } } } @@ -4835,13 +4699,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: @@ -4854,15 +4717,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); } @@ -5275,12 +5138,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; } @@ -5413,8 +5275,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; @@ -5424,21 +5286,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; @@ -5469,8 +5331,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; } } @@ -5528,30 +5392,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(&ndeclaration->base.source_position, "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(&ndeclaration->base.source_position, "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(&ndeclaration->base.source_position, "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 @@ -5576,9 +5435,7 @@ static void parse_external_declaration(void) 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) { @@ -5605,7 +5462,7 @@ static void parse_external_declaration(void) entity_t *old_current_entity = current_entity; current_function = function; current_entity = entity; - current_parent = NULL; + PUSH_PARENT(NULL); goto_first = NULL; goto_anchor = &goto_first; @@ -5617,24 +5474,21 @@ 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); current_entity = old_current_entity; @@ -5642,9 +5496,7 @@ static void parse_external_declaration(void) label_pop_to(label_stack_top); } - assert(current_scope == &function->parameters); - scope_pop(old_scope); - environment_pop_to(top); + POP_SCOPE(); } static type_t *make_bitfield_type(type_t *base_type, expression_t *size, @@ -5713,23 +5565,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); } } @@ -5789,7 +5635,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); } @@ -5838,9 +5684,9 @@ static void parse_compound_declarators(compound_t *compound, } 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); @@ -5849,9 +5695,8 @@ 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); } } @@ -5871,17 +5716,13 @@ static void parse_compound_declarators(compound_t *compound, 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); + errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type); } } } @@ -5901,20 +5742,28 @@ 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; + for (;;) { + switch (token.type) { + 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; + } + + default: + rem_anchor_token('}'); + expect('}', end_error); +end_error: + /* §6.7.2.1:7 */ + compound->complete = true; + return; } - declaration_specifiers_t specifiers; - parse_declaration_specifiers(&specifiers); - parse_compound_declarators(compound, &specifiers); } - rem_anchor_token('}'); - next_token(); - - /* §6.7.2.1:7 */ - compound->complete = true; } static type_t *parse_typename(void) @@ -5965,12 +5814,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; } /** @@ -6011,10 +5860,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; @@ -6022,10 +5870,7 @@ 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 '%Y' suffix", token.symbol); } static void check_integer_suffix(void) @@ -6129,10 +5974,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.literal; + literal->literal.suffix = token.symbol; next_token(); /* integer type depends on the size of the number and the size @@ -6149,17 +5993,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.literal; size_t len = literal->literal.value.size; 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"); } } @@ -6173,13 +6016,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.literal; size_t len = wstrlen(&literal->literal.value); if (len > 1) { - warningf(HERE, "multi-character character constant"); + warningf(WARN_MULTICHAR, HERE, "multi-character character constant"); } next_token(); @@ -6202,12 +6044,8 @@ static entity_t *create_implicit_function(symbol_t *symbol, entity->declaration.implicit = true; 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; } @@ -6357,19 +6195,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 == '(') { /* 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); @@ -6378,12 +6215,6 @@ 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) @@ -6433,13 +6264,6 @@ static expression_t *parse_reference(void) check_deprecated(&pos, entity); - if (warning.init_self && entity == current_init_decl && !in_type_prop - && entity->kind == ENTITY_VARIABLE) { - current_init_decl = NULL; - warningf(&pos, "variable '%#T' is initialized by itself", - entity->declaration.type, entity->base.symbol); - } - return expression; } @@ -6475,25 +6299,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; @@ -6514,7 +6335,7 @@ static expression_t *parse_compound_literal(type_t *type) */ static expression_t *parse_cast(void) { - source_position_t source_position = token.source_position; + source_position_t const pos = *HERE; eat('('); add_anchor_token(')'); @@ -6525,11 +6346,11 @@ static expression_t *parse_cast(void) expect(')', end_error); if (token.type == '{') { - return parse_compound_literal(type); + 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; @@ -6568,8 +6389,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; @@ -7035,10 +6857,9 @@ 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); @@ -7162,8 +6983,9 @@ 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) && warning.char_subscripts) { - warningf(&idx->base.source_position, "array subscript has char 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)) { @@ -7191,13 +7013,10 @@ 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))) { + source_position_t const pos = *HERE; next_token(); add_anchor_token(')'); orig_type = parse_typename(); @@ -7207,7 +7026,7 @@ static expression_t *parse_typeprop(expression_kind_t const kind) if (token.type == '{') { /* 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 { @@ -7229,11 +7048,9 @@ 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"; } @@ -7252,7 +7069,6 @@ typeprop_expression: } end_error: - in_type_prop = old; return tp_expression; } @@ -7374,15 +7190,14 @@ static void check_call_argument(type_t *expected_type, 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) { + } 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); } } } @@ -7528,10 +7343,9 @@ static expression_t *parse_call_expression(expression_t *expression) check_format(call); - if (warning.aggregate_return && - is_type_compound(skip_typeref(function_type->return_type))) { - warningf(&expression->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 (expression->kind == EXPR_REFERENCE) { @@ -7586,27 +7400,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, @@ -7659,7 +7468,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 */ @@ -7668,12 +7478,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; } @@ -7712,11 +7519,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; } @@ -7724,23 +7527,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; } @@ -7758,12 +7553,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; } @@ -7815,10 +7607,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; @@ -7876,10 +7667,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) { @@ -7887,10 +7676,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; @@ -7961,9 +7748,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) @@ -8023,9 +7809,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) { @@ -8232,8 +8017,7 @@ static void semantic_binexpr_integer(binary_expression_t *const expression) 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; @@ -8241,7 +8025,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"); } } @@ -8266,8 +8051,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) @@ -8291,14 +8076,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"); } } @@ -8316,10 +8100,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); @@ -8390,8 +8172,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; @@ -8412,27 +8194,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"); } } @@ -8445,6 +8208,32 @@ static bool maybe_negative(expression_t const *const expr) } } +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. * @@ -8452,32 +8241,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); - } + source_position_t const *const pos = &expression->base.source_position; + expression_t *const left = expression->left; + expression_t *const right = expression->right; - 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); - } - } - - 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; @@ -8489,7 +8258,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) { @@ -8497,8 +8266,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"); } } } @@ -8506,12 +8274,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 */ @@ -8520,9 +8286,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; } @@ -8705,8 +8469,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 ||"); } /** @@ -8718,8 +8482,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); } @@ -8833,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; @@ -8890,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; } @@ -8958,7 +8718,6 @@ static expression_t *parse_subexpression(precedence_t precedence) expression_parser_function_t *parser = &expression_parsers[token.type]; - source_position_t source_position = token.source_position; expression_t *left; if (parser->parser != NULL) { @@ -8967,7 +8726,6 @@ 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) { @@ -8984,7 +8742,6 @@ static expression_t *parse_subexpression(precedence_t precedence) assert(left != NULL); assert(left->kind != EXPR_UNKNOWN); - left->base.source_position = source_position; } return left; @@ -9302,7 +9059,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); } @@ -9349,9 +9107,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"); } } } @@ -9391,7 +9149,7 @@ end_error: statement->case_label.statement = parse_label_inner_statement(statement, "case label"); - POP_PARENT; + POP_PARENT(); return statement; } @@ -9431,7 +9189,7 @@ end_error: statement->case_label.statement = parse_label_inner_statement(statement, "default label"); - POP_PARENT; + POP_PARENT(); return statement; } @@ -9451,7 +9209,7 @@ static statement_t *parse_label_statement(void) */ source_position_t const* const pos = &statement->base.source_position; if (label->statement != NULL) { - errorf(pos, "duplicate label '%Y' (declared %P)", label->base.symbol, &label->base.source_position); + errorf(pos, "duplicate '%N' (declared %P)", (entity_t const*)label, &label->base.source_position); } else { label->base.source_position = *pos; label->statement = statement; @@ -9459,16 +9217,31 @@ static statement_t *parse_label_statement(void) eat(':'); + if (token.type == 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. */ @@ -9497,20 +9270,19 @@ 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 (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(); + } 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; } @@ -9521,6 +9293,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; @@ -9547,10 +9321,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; } @@ -9574,12 +9347,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, @@ -9592,20 +9361,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(); } @@ -9614,7 +9381,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; @@ -9644,10 +9411,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(); } @@ -9679,10 +9446,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(); } @@ -9699,14 +9466,9 @@ 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)) { @@ -9716,14 +9478,14 @@ static statement_t *parse_for(void) 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; + + POP_EXTENSION(); if (token.type != ';') { add_anchor_token(';'); @@ -9740,28 +9502,22 @@ static statement_t *parse_for(void) 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: @@ -9788,9 +9544,8 @@ 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); } @@ -9929,9 +9684,8 @@ 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 != ';') { @@ -9954,18 +9708,16 @@ 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 { @@ -9975,21 +9727,19 @@ static statement_t *parse_return(void) } 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"); } 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; @@ -10056,7 +9806,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); @@ -10088,9 +9838,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; @@ -10114,8 +9862,8 @@ static statement_t *parse_local_label_declaration(void) symbol_t *symbol = token.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, NAMESPACE_LABEL, symbol); entity->base.parent_scope = current_scope; @@ -10173,8 +9921,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; @@ -10184,11 +9931,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(); } /** @@ -10231,15 +9976,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(); @@ -10295,11 +10039,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"); } } @@ -10314,6 +10057,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('}'); @@ -10406,9 +10150,6 @@ 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 != '}') { @@ -10425,13 +10166,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; @@ -10444,7 +10183,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) @@ -10456,8 +10195,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"); } } } @@ -10550,11 +10288,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; } @@ -10563,7 +10299,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; @@ -10578,20 +10314,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); } } @@ -10646,22 +10383,21 @@ end_error: static void parse_external(void) { switch (token.type) { - 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 { + 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); */ + PUSH_EXTENSION(); parse_external_declaration(); + POP_EXTENSION(); } return; @@ -10675,8 +10411,7 @@ static void parse_external(void) case ';': if (!strict_mode) { - if (warning.other) - warningf(HERE, "stray ';' outside of function"); + warningf(WARN_OTHER, HERE, "stray ';' outside of function"); next_token(); return; } @@ -10698,14 +10433,14 @@ 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 != '}') { #ifndef NDEBUG 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 */ internal_errorf(HERE, "Leaked anchor token %k %d times", i, count); @@ -10801,18 +10536,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;