X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=5e5b41931ec0bd0be913ad4fa53db04e02cf15ee;hb=5415928cc4c29c1754b6562bad26ab7d7f23882d;hp=5ff6397162c4b1d699996b8d62d166ee17fb33db;hpb=253a514a79c5b4524df61e5a58a194eaed982f47;p=cparser diff --git a/parser.c b/parser.c index 5ff6397..5e5b419 100644 --- a/parser.c +++ b/parser.c @@ -41,21 +41,13 @@ #include "adt/error.h" #include "adt/array.h" -/** if wchar_t is equal to unsigned short. */ -bool opt_short_wchar_t = -#ifdef _WIN32 - true; -#else - false; -#endif - //#define PRINT_TOKENS #define MAX_LOOKAHEAD 2 typedef struct { - entity_t *old_entity; - symbol_t *symbol; - namespace_t namespc; + entity_t *old_entity; + symbol_t *symbol; + entity_namespace_t namespc; } stack_entry_t; typedef struct argument_list_t argument_list_t; @@ -84,8 +76,9 @@ struct declaration_specifiers_t { source_position_t source_position; storage_class_t storage_class; unsigned char alignment; /**< Alignment, 0 if not set. */ - bool is_inline : 1; - bool deprecated : 1; + bool is_inline : 1; + bool thread_local : 1; /**< GCC __thread */ + bool deprecated : 1; decl_modifiers_t modifiers; /**< declaration modifiers */ gnu_attribute_t *gnu_attributes; /**< list of GNU attributes */ const char *deprecated_string; /**< can be set if declaration was marked deprecated. */ @@ -105,39 +98,46 @@ typedef struct parse_initializer_env_t { bool must_be_constant; } parse_initializer_env_t; +/** + * Capture a MS __base extension. + */ +typedef struct based_spec_t { + source_position_t source_position; + variable_t *base_variable; +} based_spec_t; + typedef entity_t* (*parsed_declaration_func) (entity_t *declaration, bool is_definition); /** The current token. */ -static token_t token; +static token_t token; /** The lookahead ring-buffer. */ -static token_t lookahead_buffer[MAX_LOOKAHEAD]; +static token_t lookahead_buffer[MAX_LOOKAHEAD]; /** Position of the next token in the lookahead buffer. */ -static int lookahead_bufpos; -static stack_entry_t *environment_stack = NULL; -static stack_entry_t *label_stack = NULL; -static stack_entry_t *local_label_stack = NULL; -/** The global file scope. */ -static scope_t *file_scope = NULL; -/** The current scope. */ -static scope_t *scope = NULL; +static int lookahead_bufpos; +static stack_entry_t *environment_stack = NULL; +static stack_entry_t *label_stack = NULL; +static scope_t *file_scope = NULL; +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_init_decl = NULL; -static switch_statement_t *current_switch = NULL; -static statement_t *current_loop = NULL; -static statement_t *current_parent = NULL; -static ms_try_statement_t *current_try = NULL; -static goto_statement_t *goto_first = NULL; -static goto_statement_t *goto_last = NULL; -static label_statement_t *label_first = NULL; -static label_statement_t *label_last = NULL; +static function_t *current_function = 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; +static ms_try_statement_t *current_try = NULL; +static linkage_kind_t current_linkage = LINKAGE_INVALID; +static goto_statement_t *goto_first = NULL; +static goto_statement_t **goto_anchor = NULL; +static label_statement_t *label_first = NULL; +static label_statement_t **label_anchor = NULL; /** current translation unit. */ -static translation_unit_t *unit = NULL; +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; +static bool in_type_prop = false; /** true in we are in a __extension__ context. */ -static bool in_gcc_extension = false; -static struct obstack temp_obst; +static bool in_gcc_extension = false; +static struct obstack temp_obst; +static entity_t *anonymous_entity; #define PUSH_PARENT(stmt) \ @@ -185,18 +185,31 @@ static statement_t *parse_statement(void); static expression_t *parse_sub_expression(precedence_t); static expression_t *parse_expression(void); static type_t *parse_typename(void); +static void parse_externals(void); +static void parse_external(void); static void parse_compound_type_entries(compound_t *compound_declaration); + +typedef enum declarator_flags_t { + DECL_FLAGS_NONE = 0, + DECL_MAY_BE_ABSTRACT = 1U << 0, + DECL_CREATE_COMPOUND_MEMBER = 1U << 1, + DECL_IS_PARAMETER = 1U << 2 +} declarator_flags_t; + static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, - bool may_be_abstract, - bool create_compound_member); + declarator_flags_t flags); + static entity_t *record_entity(entity_t *entity, bool is_definition); static void semantic_comparison(binary_expression_t *expression); -#define STORAGE_CLASSES \ +#define STORAGE_CLASSES \ + STORAGE_CLASSES_NO_EXTERN \ + case T_extern: + +#define STORAGE_CLASSES_NO_EXTERN \ case T_typedef: \ - case T_extern: \ case T_static: \ case T_auto: \ case T_register: \ @@ -210,15 +223,10 @@ static void semantic_comparison(binary_expression_t *expression); case T__forceinline: \ case T___attribute__: -#ifdef PROVIDE_COMPLEX #define COMPLEX_SPECIFIERS \ case T__Complex: #define IMAGINARY_SPECIFIERS \ case T__Imaginary: -#else -#define COMPLEX_SPECIFIERS -#define IMAGINARY_SPECIFIERS -#endif #define TYPE_SPECIFIERS \ case T__Bool: \ @@ -246,6 +254,11 @@ static void semantic_comparison(binary_expression_t *expression); TYPE_QUALIFIERS \ TYPE_SPECIFIERS +#define DECLARATION_START_NO_EXTERN \ + STORAGE_CLASSES_NO_EXTERN \ + TYPE_QUALIFIERS \ + TYPE_SPECIFIERS + #define TYPENAME_START \ TYPE_QUALIFIERS \ TYPE_SPECIFIERS @@ -326,9 +339,10 @@ static size_t get_entity_struct_size(entity_kind_t kind) [ENTITY_ENUM] = sizeof(enum_t), [ENTITY_ENUM_VALUE] = sizeof(enum_value_t), [ENTITY_LABEL] = sizeof(label_t), - [ENTITY_LOCAL_LABEL] = sizeof(label_t) + [ENTITY_LOCAL_LABEL] = sizeof(label_t), + [ENTITY_NAMESPACE] = sizeof(namespace_t) }; - assert(kind <= sizeof(sizes) / sizeof(sizes[0])); + assert(kind < sizeof(sizes) / sizeof(sizes[0])); assert(sizes[kind] != 0); return sizes[kind]; } @@ -370,7 +384,7 @@ static size_t get_statement_struct_size(statement_kind_t kind) [STATEMENT_MS_TRY] = sizeof(ms_try_statement_t), [STATEMENT_LEAVE] = sizeof(leave_statement_t) }; - assert(kind <= sizeof(sizes) / sizeof(sizes[0])); + assert(kind < sizeof(sizes) / sizeof(sizes[0])); assert(sizes[kind] != 0); return sizes[kind]; } @@ -417,7 +431,7 @@ static size_t get_expression_struct_size(expression_kind_t kind) if (kind >= EXPR_BINARY_FIRST && kind <= EXPR_BINARY_LAST) { return sizes[EXPR_BINARY_FIRST]; } - assert(kind <= sizeof(sizes) / sizeof(sizes[0])); + assert(kind < sizeof(sizes) / sizeof(sizes[0])); assert(sizes[kind] != 0); return sizes[kind]; } @@ -575,14 +589,6 @@ static size_t label_top(void) return ARR_LEN(label_stack); } -/** - * Returns the index of the top element of the local label stack. - */ -static size_t local_label_top(void) -{ - return ARR_LEN(local_label_stack); -} - /** * Return the next token. */ @@ -743,15 +749,6 @@ void parse_error_expected(const char *message, ...) va_end(ap); } -/** - * Report a type error. - */ -static void type_error(const char *msg, const source_position_t *source_position, - type_t *type) -{ - errorf(source_position, "%s, but found type '%T'", msg, type); -} - /** * Report an incompatible type. */ @@ -783,25 +780,26 @@ static void type_error_incompatible(const char *msg, static void scope_push(scope_t *new_scope) { - if (scope != NULL) { - new_scope->depth = scope->depth + 1; + if (current_scope != NULL) { + new_scope->depth = current_scope->depth + 1; } - new_scope->parent = scope; - scope = new_scope; + new_scope->parent = current_scope; + current_scope = new_scope; } static void scope_pop(void) { - scope = scope->parent; + current_scope = current_scope->parent; } /** * Search an entity by its symbol in a given namespace. */ -static entity_t *get_entity(const symbol_t *const symbol, namespace_t namespc) +static entity_t *get_entity(const symbol_t *const symbol, + namespace_tag_t namespc) { entity_t *entity = symbol->entity; - for( ; entity != NULL; entity = entity->base.symbol_next) { + for (; entity != NULL; entity = entity->base.symbol_next) { if (entity->base.namespc == namespc) return entity; } @@ -815,8 +813,8 @@ static entity_t *get_entity(const symbol_t *const symbol, namespace_t namespc) */ static void stack_push(stack_entry_t **stack_ptr, entity_t *entity) { - symbol_t *symbol = entity->base.symbol; - namespace_t namespc = entity->base.namespc; + symbol_t *symbol = entity->base.symbol; + entity_namespace_t namespc = entity->base.namespc; assert(namespc != NAMESPACE_INVALID); /* replace/add entity into entity list of the symbol */ @@ -865,18 +863,6 @@ static void label_push(entity_t *label) stack_push(&label_stack, label); } -/** - * Push a declaration of the local label stack. - * - * @param declaration the declaration - */ -static void local_label_push(entity_t *label) -{ - assert(label->base.parent_scope != NULL); - label->base.parent_scope = scope; - stack_push(&local_label_stack, label); -} - /** * pops symbols from the environment stack until @p new_top is the top element */ @@ -890,12 +876,12 @@ static void stack_pop_to(stack_entry_t **stack_ptr, size_t new_top) if (new_top == top) return; - for(i = top; i > new_top; --i) { + for (i = top; i > new_top; --i) { stack_entry_t *entry = &stack[i - 1]; - entity_t *old_entity = entry->old_entity; - symbol_t *symbol = entry->symbol; - namespace_t namespc = entry->namespc; + entity_t *old_entity = entry->old_entity; + symbol_t *symbol = entry->symbol; + entity_namespace_t namespc = entry->namespc; /* replace with old_entity/remove */ entity_t **anchor; @@ -943,18 +929,6 @@ static void label_pop_to(size_t new_top) stack_pop_to(&label_stack, new_top); } -/** - * Pop all entries from the local label stack until the new_top - * is reached. - * - * @param new_top the new stack top - */ -static void local_label_pop_to(size_t new_top) -{ - stack_pop_to(&local_label_stack, new_top); -} - - static int get_akind_rank(atomic_type_kind_t akind) { return (int) akind; @@ -1196,25 +1170,6 @@ static expression_t *parse_assignment_expression(void) return parse_sub_expression(PREC_ASSIGNMENT); } -static type_t *make_global_typedef(const char *name, type_t *type) -{ - symbol_t *const symbol = symbol_table_insert(name); - - entity_t *const entity = allocate_entity_zero(ENTITY_TYPEDEF); - entity->base.symbol = symbol; - entity->base.source_position = builtin_source_position; - entity->base.namespc = NAMESPACE_NORMAL; - entity->typedefe.type = type; - entity->typedefe.builtin = true; - - record_entity(entity, false); - - type_t *typedef_type = allocate_type_zero(TYPE_TYPEDEF); - typedef_type->typedeft.typedefe = &entity->typedefe; - - return typedef_type; -} - static string_t parse_string_literals(void) { assert(token.type == T_STRING_LITERAL); @@ -1407,7 +1362,7 @@ static void parse_gnu_attribute_tls_model_arg(gnu_attribute_t *attribute) string_t string = { NULL, 0 }; parse_gnu_attribute_string_arg(attribute, &string); if (string.begin != NULL) { - for(size_t i = 0; i < 4; ++i) { + for (size_t i = 0; i < 4; ++i) { if (strcmp(tls_models[i], string.begin) == 0) { attribute->u.value = i; return; @@ -1432,7 +1387,7 @@ static void parse_gnu_attribute_visibility_arg(gnu_attribute_t *attribute) string_t string = { NULL, 0 }; parse_gnu_attribute_string_arg(attribute, &string); if (string.begin != NULL) { - for(size_t i = 0; i < 4; ++i) { + for (size_t i = 0; i < 4; ++i) { if (strcmp(visibilities[i], string.begin) == 0) { attribute->u.value = i; return; @@ -1456,7 +1411,7 @@ static void parse_gnu_attribute_model_arg(gnu_attribute_t *attribute) string_t string = { NULL, 0 }; parse_gnu_attribute_string_arg(attribute, &string); if (string.begin != NULL) { - for(int i = 0; i < 3; ++i) { + for (int i = 0; i < 3; ++i) { if (strcmp(visibilities[i], string.begin) == 0) { attribute->u.value = i; return; @@ -1522,7 +1477,7 @@ static void parse_gnu_attribute_interrupt_arg(gnu_attribute_t *attribute) string_t string = { NULL, 0 }; parse_gnu_attribute_string_arg(attribute, &string); if (string.begin != NULL) { - for(size_t i = 0; i < 5; ++i) { + for (size_t i = 0; i < 5; ++i) { if (strcmp(interrupts[i], string.begin) == 0) { attribute->u.value = i; return; @@ -1551,7 +1506,7 @@ static void parse_gnu_attribute_format_args(gnu_attribute_t *attribute) goto end_error; } const char *name = token.v.symbol->string; - for(i = 0; i < 4; ++i) { + for (i = 0; i < 4; ++i) { if (strcmp_underscore(format_names[i], name) == 0) break; } @@ -1706,7 +1661,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes) next_token(); int i; - for(i = 0; i < GNU_AK_LAST; ++i) { + for (i = 0; i < GNU_AK_LAST; ++i) { if (strcmp_underscore(gnu_attribute_names[i], name) == 0) break; } @@ -2395,7 +2350,7 @@ static __attribute__((unused)) void debug_print_type_path( { size_t len = ARR_LEN(path->path); - for(size_t i = 0; i < len; ++i) { + for (size_t i = 0; i < len; ++i) { const type_path_entry_t *entry = & path->path[i]; type_t *type = skip_typeref(entry->type); @@ -2408,7 +2363,7 @@ static __attribute__((unused)) void debug_print_type_path( fprintf(stderr, ".%s", entry->v.compound_entry->base.symbol->string); } else if (is_type_array(type)) { - fprintf(stderr, "[%zu]", entry->v.index); + fprintf(stderr, "[%u]", (unsigned) entry->v.index); } else { fprintf(stderr, "-INVALID-"); } @@ -2505,7 +2460,7 @@ static void ascend_to(type_path_t *path, size_t top_path_level) static bool walk_designator(type_path_t *path, const designator_t *designator, bool used_in_offsetof) { - for( ; designator != NULL; designator = designator->next) { + for (; designator != NULL; designator = designator->next) { type_path_entry_t *top = get_type_path_top(path); type_t *orig_type = top->type; @@ -2526,7 +2481,7 @@ static bool walk_designator(type_path_t *path, const designator_t *designator, } else { compound_t *compound = type->compound.compound; entity_t *iter = compound->members.entities; - for( ; iter != NULL; iter = iter->base.next) { + for (; iter != NULL; iter = iter->base.next) { if (iter->base.symbol == symbol) { break; } @@ -2995,7 +2950,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct) eat(T_union); } - symbol_t *symbol = NULL; + symbol_t *symbol = NULL; compound_t *compound = NULL; if (token.type == T___attribute__) { @@ -3006,13 +2961,13 @@ static compound_t *parse_compound_type_specifier(bool is_struct) symbol = token.v.symbol; next_token(); - namespace_t const namespc = + namespace_tag_t const namespc = is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION; entity_t *entity = get_entity(symbol, namespc); if (entity != NULL) { assert(entity->kind == (is_struct ? ENTITY_STRUCT : ENTITY_UNION)); compound = &entity->compound; - if (compound->base.parent_scope != scope && + if (compound->base.parent_scope != current_scope && (token.type == '{' || token.type == ';')) { /* we're in an inner scope and have a definition. Override existing definition in outer scope */ @@ -3047,18 +3002,21 @@ static compound_t *parse_compound_type_specifier(bool is_struct) (is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION); compound->base.source_position = token.source_position; compound->base.symbol = symbol; - compound->base.parent_scope = scope; + compound->base.parent_scope = current_scope; if (symbol != NULL) { environment_push(entity); } - append_entity(scope, entity); + append_entity(current_scope, entity); } if (token.type == '{') { - compound->complete = true; - parse_compound_type_entries(compound); modifiers |= parse_attributes(&attributes); + + if (symbol == NULL) { + assert(anonymous_entity == NULL); + anonymous_entity = (entity_t*)compound; + } } compound->modifiers |= modifiers; @@ -3070,8 +3028,8 @@ static void parse_enum_entries(type_t *const enum_type) eat('{'); if (token.type == '}') { - next_token(); errorf(HERE, "empty enum not allowed"); + next_token(); return; } @@ -3141,7 +3099,7 @@ static type_t *parse_enum_specifier(void) entity->base.namespc = NAMESPACE_ENUM; entity->base.source_position = token.source_position; entity->base.symbol = symbol; - entity->base.parent_scope = scope; + entity->base.parent_scope = current_scope; } type_t *const type = allocate_type_zero(TYPE_ENUM); @@ -3155,12 +3113,17 @@ static type_t *parse_enum_specifier(void) if (symbol != NULL) { environment_push(entity); } - append_entity(scope, entity); + append_entity(current_scope, entity); entity->enume.complete = true; parse_enum_entries(type); parse_attributes(&attributes); - } else if(!entity->enume.complete && !(c_mode & _GNUC)) { + + if (symbol == NULL) { + assert(anonymous_entity == NULL); + anonymous_entity = entity; + } + } else if (!entity->enume.complete && !(c_mode & _GNUC)) { errorf(HERE, "enum %Y used before definition (incomplete enumes are a GNU extension)", symbol); } @@ -3454,6 +3417,41 @@ static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind) return entity; } +static void parse_microsoft_based(based_spec_t *based_spec) +{ + if (token.type != T_IDENTIFIER) { + parse_error_expected("while parsing __based", T_IDENTIFIER, NULL); + return; + } + symbol_t *symbol = token.v.symbol; + entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL); + + if (entity == NULL || entity->base.kind != ENTITY_VARIABLE) { + errorf(HERE, "'%Y' is not a variable name.", symbol); + entity = create_error_entity(symbol, ENTITY_VARIABLE); + } else { + variable_t *variable = &entity->variable; + + if (based_spec->base_variable != NULL) { + errorf(HERE, "__based type qualifier specified more than once"); + } + based_spec->source_position = token.source_position; + based_spec->base_variable = variable; + + type_t *const type = variable->base.type; + + if (is_type_valid(type)) { + if (! is_type_pointer(skip_typeref(type))) { + errorf(HERE, "variable in __based modifier must have pointer type instead of %T", type); + } + if (variable->base.base.parent_scope != file_scope) { + errorf(HERE, "a nonstatic local variable may not be used in a __based specification"); + } + } + } + next_token(); +} + /** * Finish the construction of a struct type by calculating * its size, offsets, alignment. @@ -3571,7 +3569,6 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION; switch (token.type) { - /* storage class */ #define MATCH_STORAGE_CLASS(token, class) \ case token: \ @@ -3579,6 +3576,8 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) errorf(HERE, "multiple storage classes in declaration specifiers"); \ } \ specifiers->storage_class = class; \ + if (specifiers->thread_local) \ + goto check_thread_storage_class; \ next_token(); \ break; @@ -3598,22 +3597,25 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) break; case T___thread: - switch (specifiers->storage_class) { - case STORAGE_CLASS_NONE: - specifiers->storage_class = STORAGE_CLASS_THREAD; - break; - - case STORAGE_CLASS_EXTERN: - specifiers->storage_class = STORAGE_CLASS_THREAD_EXTERN; - break; - - case STORAGE_CLASS_STATIC: - specifiers->storage_class = STORAGE_CLASS_THREAD_STATIC; - break; + if (specifiers->thread_local) { + errorf(HERE, "duplicate '__thread'"); + } else { + specifiers->thread_local = true; +check_thread_storage_class: + switch (specifiers->storage_class) { + case STORAGE_CLASS_EXTERN: + case STORAGE_CLASS_NONE: + case STORAGE_CLASS_STATIC: + break; - default: - errorf(HERE, "multiple storage classes in declaration specifiers"); - break; + char const* wrong; + case STORAGE_CLASS_AUTO: wrong = "auto"; goto wrong_thread_stoarge_class; + case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_stoarge_class; + case STORAGE_CLASS_TYPEDEF: wrong = "typedef"; goto wrong_thread_stoarge_class; +wrong_thread_stoarge_class: + errorf(HERE, "'__thread' used with '%s'", wrong); + break; + } } next_token(); break; @@ -3642,12 +3644,12 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) /* type specifiers */ #define MATCH_SPECIFIER(token, specifier, name) \ case token: \ - next_token(); \ if (type_specifiers & specifier) { \ errorf(HERE, "multiple " name " type specifiers given"); \ } else { \ type_specifiers |= specifier; \ } \ + next_token(); \ break MATCH_SPECIFIER(T__Bool, SPECIFIER_BOOL, "_Bool"); @@ -3679,7 +3681,6 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) break; case T_long: - next_token(); if (type_specifiers & SPECIFIER_LONG_LONG) { errorf(HERE, "multiple type specifiers given"); } else if (type_specifiers & SPECIFIER_LONG) { @@ -3687,6 +3688,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) } else { type_specifiers |= SPECIFIER_LONG; } + next_token(); break; case T_struct: { @@ -3730,6 +3732,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) case T_inline: case T__forceinline: /* ^ DECLARATION_START except for __attribute__ */ case T_IDENTIFIER: + case '&': case '*': errorf(HERE, "discarding stray %K in declaration specifier", &token); next_token(); @@ -3749,6 +3752,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) switch (la1_type) { DECLARATION_START case T_IDENTIFIER: + case '&': case '*': { errorf(HERE, "%K does not name a type", &token); @@ -3760,7 +3764,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) next_token(); saw_error = true; - if (la1_type == '*') + if (la1_type == '&' || la1_type == '*') goto finish_specifiers; continue; } @@ -4024,14 +4028,14 @@ static void parse_identifier_list(scope_t *scope) } while (token.type == T_IDENTIFIER); } -static type_t *automatic_type_conversion(type_t *orig_type); - static void semantic_parameter(declaration_t *declaration) { /* TODO: improve error messages */ source_position_t const* const pos = &declaration->base.source_position; - /* §6.9.1:6 */ + /* §6.9.1:6 The declarations in the declaration list shall contain no + * storage-class specifier other than register and no + * initializations. */ switch (declaration->declared_storage_class) { /* Allowed storage classes */ case STORAGE_CLASS_NONE: @@ -4043,18 +4047,13 @@ static void semantic_parameter(declaration_t *declaration) break; } - type_t *const orig_type = declaration->type; - /* §6.7.5.3(7): Array as last part of a parameter type is just syntactic - * sugar. Turn it into a pointer. - * §6.7.5.3(8): A declaration of a parameter as ``function returning type'' - * shall be adjusted to ``pointer to function returning type'', as in 6.3.2.1. - */ - type_t *const type = automatic_type_conversion(orig_type); - declaration->type = type; - + /* §6.7.5.3:4 After adjustment, the parameters in a parameter type list in + * a function declarator that is part of a definition of that + * function shall not have incomplete type. */ + type_t *type = declaration->type; if (is_type_incomplete(skip_typeref(type))) { - errorf(pos, "parameter '%#T' is of incomplete type", - orig_type, declaration->base.symbol); + errorf(pos, "parameter '%#T' has incomplete type", + type, declaration->base.symbol); } } @@ -4065,7 +4064,9 @@ static entity_t *parse_parameter(void) parse_declaration_specifiers(&specifiers); - entity_t *entity = parse_declarator(&specifiers, true, false); + entity_t *entity = parse_declarator(&specifiers, + DECL_MAY_BE_ABSTRACT | DECL_IS_PARAMETER); + anonymous_entity = NULL; return entity; } @@ -4165,6 +4166,7 @@ end_error: typedef enum construct_type_kind_t { CONSTRUCT_INVALID, CONSTRUCT_POINTER, + CONSTRUCT_REFERENCE, CONSTRUCT_FUNCTION, CONSTRUCT_ARRAY } construct_type_kind_t; @@ -4179,6 +4181,12 @@ typedef struct parsed_pointer_t parsed_pointer_t; struct parsed_pointer_t { construct_type_t construct_type; type_qualifiers_t type_qualifiers; + variable_t *base_variable; /**< MS __based extension. */ +}; + +typedef struct parsed_reference_t parsed_reference_t; +struct parsed_reference_t { + construct_type_t construct_type; }; typedef struct construct_function_type_t construct_function_type_t; @@ -4202,7 +4210,7 @@ struct construct_base_type_t { type_t *type; }; -static construct_type_t *parse_pointer_declarator(void) +static construct_type_t *parse_pointer_declarator(variable_t *base_variable) { eat('*'); @@ -4210,8 +4218,20 @@ static construct_type_t *parse_pointer_declarator(void) memset(pointer, 0, sizeof(pointer[0])); pointer->construct_type.kind = CONSTRUCT_POINTER; pointer->type_qualifiers = parse_type_qualifiers(); + pointer->base_variable = base_variable; - return (construct_type_t*) pointer; + return &pointer->construct_type; +} + +static construct_type_t *parse_reference_declarator(void) +{ + eat('&'); + + parsed_reference_t *reference = obstack_alloc(&temp_obst, sizeof(reference[0])); + memset(reference, 0, sizeof(reference[0])); + reference->construct_type.kind = CONSTRUCT_REFERENCE; + + return (construct_type_t*)reference; } static construct_type_t *parse_array_declarator(void) @@ -4248,54 +4268,30 @@ static construct_type_t *parse_array_declarator(void) expect(']'); end_error: - return (construct_type_t*) array; + return &array->construct_type; } -static construct_type_t *parse_function_declarator(scope_t *scope) +static construct_type_t *parse_function_declarator(scope_t *scope, + decl_modifiers_t modifiers) { - type_t *type = allocate_type_zero(TYPE_FUNCTION); - - /* TODO: revive this... once we know exactly how to do it */ -#if 0 - decl_modifiers_t modifiers = entity->declaration.modifiers; + type_t *type = allocate_type_zero(TYPE_FUNCTION); + function_type_t *ftype = &type->function; - unsigned mask = modifiers & (DM_CDECL|DM_STDCALL|DM_FASTCALL|DM_THISCALL); + ftype->linkage = current_linkage; - if (mask & (mask-1)) { - const char *first = NULL, *second = NULL; + switch (modifiers & (DM_CDECL | DM_STDCALL | DM_FASTCALL | DM_THISCALL)) { + case DM_NONE: break; + case DM_CDECL: ftype->calling_convention = CC_CDECL; break; + case DM_STDCALL: ftype->calling_convention = CC_STDCALL; break; + case DM_FASTCALL: ftype->calling_convention = CC_FASTCALL; break; + case DM_THISCALL: ftype->calling_convention = CC_THISCALL; break; - /* more than one calling convention set */ - if (modifiers & DM_CDECL) { - if (first == NULL) first = "cdecl"; - else if (second == NULL) second = "cdecl"; - } - if (modifiers & DM_STDCALL) { - if (first == NULL) first = "stdcall"; - else if (second == NULL) second = "stdcall"; - } - if (modifiers & DM_FASTCALL) { - if (first == NULL) first = "fastcall"; - else if (second == NULL) second = "fastcall"; - } - if (modifiers & DM_THISCALL) { - if (first == NULL) first = "thiscall"; - else if (second == NULL) second = "thiscall"; - } - errorf(&entity->base.source_position, - "%s and %s attributes are not compatible", first, second); + default: + errorf(HERE, "multiple calling conventions in declaration"); + break; } - if (modifiers & DM_CDECL) - type->function.calling_convention = CC_CDECL; - else if (modifiers & DM_STDCALL) - type->function.calling_convention = CC_STDCALL; - else if (modifiers & DM_FASTCALL) - type->function.calling_convention = CC_FASTCALL; - else if (modifiers & DM_THISCALL) - type->function.calling_convention = CC_THISCALL; -#endif - - parse_parameters(&type->function, scope); + parse_parameters(ftype, scope); construct_function_type_t *construct_function_type = obstack_alloc(&temp_obst, sizeof(construct_function_type[0])); @@ -4324,9 +4320,43 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env, decl_modifiers_t modifiers = parse_attributes(&attributes); - /* pointers */ - while (token.type == '*') { - construct_type_t *type = parse_pointer_declarator(); + /* MS __based extension */ + based_spec_t base_spec; + base_spec.base_variable = NULL; + + for (;;) { + construct_type_t *type; + switch (token.type) { + case '&': + if (!(c_mode & _CXX)) + errorf(HERE, "references are only available for C++"); + if (base_spec.base_variable != NULL && warning.other) { + warningf(&base_spec.source_position, + "__based does not precede a pointer operator, ignored"); + } + type = parse_reference_declarator(); + /* consumed */ + base_spec.base_variable = NULL; + break; + + case '*': + type = parse_pointer_declarator(base_spec.base_variable); + /* consumed */ + base_spec.base_variable = NULL; + break; + + case T__based: + next_token(); + expect('('); + add_anchor_token(')'); + parse_microsoft_based(&base_spec); + rem_anchor_token(')'); + expect(')'); + continue; + + default: + goto ptr_operator_end; + } if (last == NULL) { first = type; @@ -4339,9 +4369,16 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env, /* TODO: find out if this is correct */ modifiers |= parse_attributes(&attributes); } +ptr_operator_end: + if (base_spec.base_variable != NULL && warning.other) { + warningf(&base_spec.source_position, + "__based does not precede a pointer operator, ignored"); + } - if (env != NULL) - env->modifiers |= modifiers; + if (env != NULL) { + modifiers |= env->modifiers; + env->modifiers = modifiers; + } construct_type_t *inner_types = NULL; @@ -4376,7 +4413,7 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env, construct_type_t *p = last; - while(true) { + while (true) { construct_type_t *type; switch (token.type) { case '(': { @@ -4384,7 +4421,7 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env, if (env != NULL) scope = &env->parameters; - type = parse_function_declarator(scope); + type = parse_function_declarator(scope, modifiers); break; } case '[': @@ -4495,11 +4532,10 @@ static void parse_declaration_attributes(entity_t *entity) } } -static type_t *construct_declarator_type(construct_type_t *construct_list, - type_t *type) +static type_t *construct_declarator_type(construct_type_t *construct_list, type_t *type) { construct_type_t *iter = construct_list; - for( ; iter != NULL; iter = iter->next) { + for (; iter != NULL; iter = iter->next) { switch (iter->kind) { case CONSTRUCT_INVALID: internal_errorf(HERE, "invalid type construction found"); @@ -4529,12 +4565,25 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, } case CONSTRUCT_POINTER: { + if (is_type_reference(skip_typeref(type))) + errorf(HERE, "cannot declare a pointer to reference"); + parsed_pointer_t *parsed_pointer = (parsed_pointer_t*) iter; - type = make_pointer_type(type, parsed_pointer->type_qualifiers); + type = make_based_pointer_type(type, parsed_pointer->type_qualifiers, parsed_pointer->base_variable); continue; } + case CONSTRUCT_REFERENCE: + if (is_type_reference(skip_typeref(type))) + errorf(HERE, "cannot declare a reference to reference"); + + type = make_reference_type(type); + continue; + case CONSTRUCT_ARRAY: { + if (is_type_reference(skip_typeref(type))) + errorf(HERE, "cannot declare an array of references"); + parsed_array_t *parsed_array = (parsed_array_t*) iter; type_t *array_type = allocate_type_zero(TYPE_ARRAY); @@ -4586,16 +4635,20 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, return type; } +static type_t *automatic_type_conversion(type_t *orig_type); + static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, - bool may_be_abstract, - bool create_compound_member) + declarator_flags_t flags) { parse_declarator_env_t env; memset(&env, 0, sizeof(env)); + env.modifiers = specifiers->modifiers; - construct_type_t *construct_type - = parse_inner_declarator(&env, may_be_abstract); - type_t *type = construct_declarator_type(construct_type, specifiers->type); + construct_type_t *construct_type = + parse_inner_declarator(&env, (flags & DECL_MAY_BE_ABSTRACT) != 0); + type_t *orig_type = + construct_declarator_type(construct_type, specifiers->type); + type_t *type = skip_typeref(orig_type); if (construct_type != NULL) { obstack_free(&temp_obst, construct_type); @@ -4606,16 +4659,62 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, entity = allocate_entity_zero(ENTITY_TYPEDEF); entity->base.symbol = env.symbol; entity->base.source_position = env.source_position; - entity->typedefe.type = type; + entity->typedefe.type = orig_type; + + if (anonymous_entity != NULL) { + if (is_type_compound(type)) { + assert(anonymous_entity->compound.alias == NULL); + assert(anonymous_entity->kind == ENTITY_STRUCT || + anonymous_entity->kind == ENTITY_UNION); + anonymous_entity->compound.alias = entity; + anonymous_entity = NULL; + } else if (is_type_enum(type)) { + assert(anonymous_entity->enume.alias == NULL); + assert(anonymous_entity->kind == ENTITY_ENUM); + anonymous_entity->enume.alias = entity; + anonymous_entity = NULL; + } + } } else { - if (create_compound_member) { - entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER); - } else if (is_type_function(skip_typeref(type))) { + if (flags & DECL_CREATE_COMPOUND_MEMBER) { + entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER); + + if (specifiers->is_inline && is_type_valid(type)) { + errorf(&env.source_position, + "compound member '%Y' declared 'inline'", env.symbol); + } + + if (specifiers->thread_local || + specifiers->storage_class != STORAGE_CLASS_NONE) { + errorf(&env.source_position, + "compound member '%Y' must have no storage class", + env.symbol); + } + } else if (flags & DECL_IS_PARAMETER) { + /* §6.7.5.3:7 A declaration of a parameter as ``array of type'' + * shall be adjusted to ``qualified pointer to type'', + * [...] + * §6.7.5.3:8 A declaration of a parameter as ``function returning + * type'' shall be adjusted to ``pointer to function + * returning type'', as in 6.3.2.1. */ + orig_type = automatic_type_conversion(type); + goto create_variable; + } else if (is_type_function(type)) { entity = allocate_entity_zero(ENTITY_FUNCTION); entity->function.is_inline = specifiers->is_inline; entity->function.parameters = env.parameters; + + if (specifiers->thread_local || ( + specifiers->storage_class != STORAGE_CLASS_EXTERN && + specifiers->storage_class != STORAGE_CLASS_NONE && + specifiers->storage_class != STORAGE_CLASS_STATIC) + ) { + errorf(&env.source_position, + "invalid storage class for function '%Y'", env.symbol); + } } else { +create_variable: entity = allocate_entity_zero(ENTITY_VARIABLE); entity->variable.get_property_sym = specifiers->get_property_sym; @@ -4625,23 +4724,44 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, entity->variable.alignment = specifiers->alignment; } - if (warning.other && specifiers->is_inline && is_type_valid(type)) { - warningf(&env.source_position, - "variable '%Y' declared 'inline'\n", env.symbol); + if (specifiers->is_inline && is_type_valid(type)) { + errorf(&env.source_position, + "variable '%Y' declared 'inline'", env.symbol); + } + + entity->variable.thread_local = specifiers->thread_local; + + bool invalid_storage_class = false; + if (current_scope == file_scope) { + if (specifiers->storage_class != STORAGE_CLASS_EXTERN && + specifiers->storage_class != STORAGE_CLASS_NONE && + specifiers->storage_class != STORAGE_CLASS_STATIC) { + invalid_storage_class = true; + } + } else { + if (specifiers->thread_local && + specifiers->storage_class == STORAGE_CLASS_NONE) { + invalid_storage_class = true; + } + } + if (invalid_storage_class) { + errorf(&env.source_position, + "invalid storage class for variable '%Y'", env.symbol); } } - entity->base.source_position = env.source_position; - entity->base.symbol = env.symbol; - entity->base.namespc = NAMESPACE_NORMAL; - entity->declaration.type = type; - entity->declaration.modifiers = env.modifiers | specifiers->modifiers; + entity->base.source_position = env.source_position; + entity->base.symbol = env.symbol; + entity->base.namespc = NAMESPACE_NORMAL; + entity->declaration.type = orig_type; + entity->declaration.modifiers = env.modifiers; entity->declaration.deprecated_string = specifiers->deprecated_string; storage_class_t storage_class = specifiers->storage_class; entity->declaration.declared_storage_class = storage_class; - if (storage_class == STORAGE_CLASS_NONE && scope != file_scope) { + if (storage_class == STORAGE_CLASS_NONE + && current_scope != file_scope) { storage_class = STORAGE_CLASS_AUTO; } entity->declaration.storage_class = storage_class; @@ -4733,6 +4853,34 @@ static bool is_sym_main(const symbol_t *const sym) return strcmp(sym->string, "main") == 0; } +static const char *get_entity_kind_name(entity_kind_t kind) +{ + switch ((entity_kind_tag_t) kind) { + case ENTITY_FUNCTION: return "function"; + case ENTITY_VARIABLE: return "variable"; + case ENTITY_COMPOUND_MEMBER: return "compound type member"; + case ENTITY_STRUCT: return "struct"; + case ENTITY_UNION: return "union"; + case ENTITY_ENUM: return "enum"; + case ENTITY_ENUM_VALUE: return "enum value"; + case ENTITY_LABEL: return "label"; + case ENTITY_LOCAL_LABEL: return "local label"; + case ENTITY_TYPEDEF: return "typedef"; + case ENTITY_NAMESPACE: return "namespace"; + case ENTITY_INVALID: break; + } + + panic("Invalid entity kind encountered in get_entity_kind_name"); +} + +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); +} + /** * record entities for the NAMESPACE_NORMAL, and produce error messages/warnings * for various problems that occur for multiple definitions @@ -4740,7 +4888,7 @@ static bool is_sym_main(const symbol_t *const sym) static entity_t *record_entity(entity_t *entity, const bool is_definition) { const symbol_t *const symbol = entity->base.symbol; - const namespace_t namespc = entity->base.namespc; + const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc; const source_position_t *pos = &entity->base.source_position; assert(symbol != NULL); @@ -4760,7 +4908,8 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition) orig_type, symbol); } - if (warning.main && scope == file_scope && is_sym_main(symbol)) { + if (warning.main && current_scope == file_scope + && is_sym_main(symbol)) { check_type_of_main(entity); } } @@ -4768,7 +4917,7 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition) if (is_declaration(entity)) { if (warning.nested_externs && entity->declaration.storage_class == STORAGE_CLASS_EXTERN - && scope != file_scope) { + && current_scope != file_scope) { warningf(pos, "nested extern declaration of '%#T'", entity->declaration.type, symbol); } @@ -4776,7 +4925,7 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition) if (previous_entity != NULL && previous_entity->base.parent_scope == ¤t_function->parameters - && scope->depth == previous_entity->base.parent_scope->depth + 1) { + && current_scope->depth == previous_entity->base.parent_scope->depth+1){ assert(previous_entity->kind == ENTITY_VARIABLE); errorf(pos, @@ -4788,12 +4937,11 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition) } if (previous_entity != NULL - && previous_entity->base.parent_scope == scope) { + && previous_entity->base.parent_scope == current_scope) { if (previous_entity->kind != entity->kind) { - errorf(pos, - "redeclaration of '%Y' as different kind of symbol (declared %P)", - symbol, &previous_entity->base.source_position); + error_redefined_as_different_kind(pos, previous_entity, + entity->kind); goto finish; } if (previous_entity->kind == ENTITY_ENUM_VALUE) { @@ -4950,10 +5098,9 @@ error_redeclaration: } } else if (warning.missing_declarations && entity->kind == ENTITY_VARIABLE - && scope == file_scope) { + && current_scope == file_scope) { declaration_t *declaration = &entity->declaration; - if (declaration->storage_class == STORAGE_CLASS_NONE || - declaration->storage_class == STORAGE_CLASS_THREAD) { + if (declaration->storage_class == STORAGE_CLASS_NONE) { warningf(pos, "no previous declaration for '%#T'", declaration->type, symbol); } @@ -4961,12 +5108,12 @@ error_redeclaration: finish: assert(entity->base.parent_scope == NULL); - assert(scope != NULL); + assert(current_scope != NULL); - entity->base.parent_scope = scope; + entity->base.parent_scope = current_scope; entity->base.namespc = NAMESPACE_NORMAL; environment_push(entity); - append_entity(scope, entity); + append_entity(current_scope, entity); return entity; } @@ -5013,8 +5160,7 @@ static void parse_init_declarator_rest(entity_t *entity) } bool must_be_constant = false; - if (declaration->storage_class == STORAGE_CLASS_STATIC || - declaration->storage_class == STORAGE_CLASS_THREAD_STATIC || + if (declaration->storage_class == STORAGE_CLASS_STATIC || entity->base.parent_scope == file_scope) { must_be_constant = true; } @@ -5048,9 +5194,11 @@ static void parse_anonymous_declaration_rest( const declaration_specifiers_t *specifiers) { eat(';'); + anonymous_entity = NULL; if (warning.other) { - if (specifiers->storage_class != STORAGE_CLASS_NONE) { + if (specifiers->storage_class != STORAGE_CLASS_NONE || + specifiers->thread_local) { warningf(&specifiers->source_position, "useless storage class in empty declaration"); } @@ -5076,30 +5224,65 @@ static void parse_anonymous_declaration_rest( } } +static void check_variable_type_complete(entity_t *ent) +{ + if (ent->kind != ENTITY_VARIABLE) + return; + + /* §6.7:7 If an identifier for an object is declared with no linkage, the + * type for the object shall be complete [...] */ + declaration_t *decl = &ent->declaration; + if (decl->storage_class != STORAGE_CLASS_NONE) + return; + + type_t *type = decl->type; + if (!is_type_incomplete(skip_typeref(type))) + return; + + errorf(&ent->base.source_position, "variable '%#T' has incomplete type", + type, ent->base.symbol); +} + + static void parse_declaration_rest(entity_t *ndeclaration, const declaration_specifiers_t *specifiers, parsed_declaration_func finished_declaration) { add_anchor_token(';'); add_anchor_token(','); - while(true) { + while (true) { entity_t *entity = finished_declaration(ndeclaration, token.type == '='); if (token.type == '=') { parse_init_declarator_rest(entity); + } else if (entity->kind == ENTITY_VARIABLE) { + /* ISO/IEC 14882:1998(E) §8.5.3:3 The initializer can be omitted + * [...] where the extern specifier is explicitly used. */ + declaration_t *decl = &entity->declaration; + 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); + } + } } + check_variable_type_complete(entity); + if (token.type != ',') break; eat(','); add_anchor_token('='); - ndeclaration = parse_declarator(specifiers, /*may_be_abstract=*/false, false); + ndeclaration = parse_declarator(specifiers, DECL_FLAGS_NONE); rem_anchor_token('='); } expect(';'); end_error: + anonymous_entity = NULL; rem_anchor_token(';'); rem_anchor_token(','); } @@ -5115,7 +5298,7 @@ static entity_t *finished_kr_declaration(entity_t *entity, bool is_definition) assert(entity->base.namespc == NAMESPACE_NORMAL); entity_t *previous_entity = get_entity(symbol, NAMESPACE_NORMAL); if (previous_entity == NULL - || previous_entity->base.parent_scope != scope) { + || previous_entity->base.parent_scope != current_scope) { errorf(HERE, "expected declaration of a function parameter, found '%Y'", symbol); return entity; @@ -5140,7 +5323,7 @@ static void parse_declaration(parsed_declaration_func finished_declaration) if (token.type == ';') { parse_anonymous_declaration_rest(&specifiers); } else { - entity_t *entity = parse_declarator(&specifiers, /*may_be_abstract=*/false, false); + entity_t *entity = parse_declarator(&specifiers, DECL_FLAGS_NONE); parse_declaration_rest(entity, &specifiers, finished_declaration); } } @@ -5179,7 +5362,7 @@ static void parse_kr_declaration_list(entity_t *entity) entity_t *parameter = entity->function.parameters.entities; for ( ; parameter != NULL; parameter = parameter->base.next) { assert(parameter->base.parent_scope == NULL); - parameter->base.parent_scope = scope; + parameter->base.parent_scope = current_scope; environment_push(parameter); } @@ -5189,7 +5372,7 @@ static void parse_kr_declaration_list(entity_t *entity) } /* pop function parameters */ - assert(scope == &entity->function.parameters); + assert(current_scope == &entity->function.parameters); scope_pop(); environment_pop_to(top); @@ -5200,7 +5383,7 @@ static void parse_kr_declaration_list(entity_t *entity) function_parameter_t *last_parameter = NULL; entity_t *parameter_declaration = entity->function.parameters.entities; - for( ; parameter_declaration != NULL; + for (; parameter_declaration != NULL; parameter_declaration = parameter_declaration->base.next) { type_t *parameter_type = parameter_declaration->declaration.type; if (parameter_type == NULL) { @@ -5291,8 +5474,6 @@ static void check_labels(void) "label '%Y' used but not defined", label->base.symbol); } } - goto_first = NULL; - goto_last = NULL; if (warning.unused_label) { for (const label_statement_t *label_statement = label_first; @@ -5307,7 +5488,6 @@ static void check_labels(void) } } } - label_first = label_last = NULL; } static void warn_unused_decl(entity_t *entity, entity_t *end, @@ -5882,7 +6062,7 @@ static void parse_external_declaration(void) add_anchor_token('{'); /* declarator is common to both function-definitions and declarations */ - entity_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false, false); + entity_t *ndeclaration = parse_declarator(&specifiers, DECL_FLAGS_NONE); rem_anchor_token('{'); rem_anchor_token(';'); @@ -5908,11 +6088,9 @@ static void parse_external_declaration(void) } assert(is_declaration(ndeclaration)); - type_t *type = ndeclaration->declaration.type; + type_t *type = skip_typeref(ndeclaration->declaration.type); - /* note that we don't skip typerefs: the standard doesn't allow them here - * (so we can't use is_type_function here) */ - if (type->kind != TYPE_FUNCTION) { + 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); @@ -5966,13 +6144,13 @@ static void parse_external_declaration(void) scope_push(&function->parameters); entity_t *parameter = function->parameters.entities; - for( ; parameter != NULL; parameter = parameter->base.next) { + for (; parameter != NULL; parameter = parameter->base.next) { if (parameter->base.parent_scope == &ndeclaration->function.parameters) { - parameter->base.parent_scope = scope; + parameter->base.parent_scope = current_scope; } assert(parameter->base.parent_scope == NULL - || parameter->base.parent_scope == scope); - parameter->base.parent_scope = scope; + || parameter->base.parent_scope == current_scope); + parameter->base.parent_scope = current_scope; if (parameter->base.symbol == NULL) { errorf(¶meter->base.source_position, "parameter name omitted"); continue; @@ -5990,7 +6168,12 @@ static void parse_external_declaration(void) current_function = function; current_parent = NULL; - statement_t *const body = parse_compound_statement(false); + goto_first = NULL; + goto_anchor = &goto_first; + label_first = NULL; + label_anchor = &label_first; + + statement_t *const body = parse_compound_statement(false); function->statement = body; first_err = true; check_labels(); @@ -6018,7 +6201,7 @@ static void parse_external_declaration(void) label_pop_to(label_stack_top); } - assert(scope == &function->parameters); + assert(current_scope == &function->parameters); scope_pop(); environment_pop_to(top); } @@ -6046,14 +6229,11 @@ static type_t *make_bitfield_type(type_t *base_type, expression_t *size, long v = fold_constant(size); if (v < 0) { - errorf(source_position, "negative width in bit-field '%Y'", - symbol); + errorf(source_position, "negative width in bit-field '%Y'", symbol); } else if (v == 0) { - errorf(source_position, "zero width for bit-field '%Y'", - symbol); + errorf(source_position, "zero width for bit-field '%Y'", symbol); } else if (bit_size > 0 && (il_size_t)v > bit_size) { - errorf(source_position, "width of '%Y' exceeds its type", - symbol); + errorf(source_position, "width of '%Y' exceeds its type", symbol); } else { type->bitfield.bit_size = v; } @@ -6065,11 +6245,13 @@ static type_t *make_bitfield_type(type_t *base_type, expression_t *size, static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol) { entity_t *iter = compound->members.entities; - for( ; iter != NULL; iter = iter->base.next) { + for (; iter != NULL; iter = iter->base.next) { if (iter->kind != ENTITY_COMPOUND_MEMBER) continue; - if (iter->base.symbol == NULL) { + if (iter->base.symbol == symbol) { + return iter; + } else if (iter->base.symbol == NULL) { type_t *type = skip_typeref(iter->declaration.type); if (is_type_compound(type)) { entity_t *result @@ -6079,10 +6261,6 @@ static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol) } continue; } - - if (iter->base.symbol == symbol) { - return iter; - } } return NULL; @@ -6112,7 +6290,8 @@ static void parse_compound_declarators(compound_t *compound, entity->declaration.modifiers = specifiers->modifiers; entity->declaration.type = type; } else { - entity = parse_declarator(specifiers,/*may_be_abstract=*/true, true); + entity = parse_declarator(specifiers, + DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER); assert(entity->kind == ENTITY_COMPOUND_MEMBER); if (token.type == ':') { @@ -6133,7 +6312,6 @@ static void parse_compound_declarators(compound_t *compound, entity_t *prev = find_compound_entry(compound, symbol); if (prev != NULL) { - assert(prev->base.symbol == symbol); errorf(&entity->base.source_position, "multiple declarations of symbol '%Y' (declared %P)", symbol, &prev->base.source_position); @@ -6142,40 +6320,33 @@ static void parse_compound_declarators(compound_t *compound, append_entity(&compound->members, entity); - if (token.type != ',') - break; - next_token(); - } - expect(';'); - -end_error: - ; -} - -static void semantic_compound(compound_t *compound) -{ - entity_t *entity = compound->members.entities; - for ( ; entity != NULL; entity = entity->base.next) { - assert(entity->kind == ENTITY_COMPOUND_MEMBER); - type_t *orig_type = entity->declaration.type; type_t *type = skip_typeref(orig_type); - if (is_type_function(type)) { - errorf(HERE, - "compound member '%Y' must not have function type '%T'", - entity->base.symbol, orig_type); + errorf(&entity->base.source_position, + "compound member '%Y' must not have function type '%T'", + entity->base.symbol, orig_type); } else if (is_type_incomplete(type)) { - /* §6.7.2.1 (16) flexible array member */ - if (is_type_array(type) && entity->base.next == NULL) { + /* §6.7.2.1:16 flexible array member */ + if (is_type_array(type) && + token.type == ';' && + look_ahead(1)->type == '}') { compound->has_flexible_member = true; } else { - errorf(HERE, - "compound member '%Y' has incomplete type '%T'", - entity->base.symbol, orig_type); + errorf(&entity->base.source_position, + "compound member '%Y' has incomplete type '%T'", + entity->base.symbol, orig_type); } } + + if (token.type != ',') + break; + next_token(); } + expect(';'); + +end_error: + anonymous_entity = NULL; } static void parse_compound_type_entries(compound_t *compound) @@ -6194,9 +6365,11 @@ static void parse_compound_type_entries(compound_t *compound) parse_compound_declarators(compound, &specifiers); } - semantic_compound(compound); rem_anchor_token('}'); next_token(); + + /* §6.7.2.1:7 */ + compound->complete = true; } static type_t *parse_typename(void) @@ -6204,7 +6377,8 @@ static type_t *parse_typename(void) declaration_specifiers_t specifiers; memset(&specifiers, 0, sizeof(specifiers)); parse_declaration_specifiers(&specifiers); - if (specifiers.storage_class != STORAGE_CLASS_NONE) { + if (specifiers.storage_class != STORAGE_CLASS_NONE || + specifiers.thread_local) { /* TODO: improve error message, user does probably not know what a * storage class is... */ @@ -6333,10 +6507,10 @@ static expression_t *parse_character_constant(void) cnst->conste.v.character = token.v.string; if (cnst->conste.v.character.size != 1) { - if (warning.multichar && GNU_MODE) { + if (!GNU_MODE) { + errorf(HERE, "more than 1 character in character constant"); + } else if (warning.multichar) { warningf(HERE, "multi-character character constant"); - } else { - errorf(HERE, "more than 1 characters in character constant"); } } next_token(); @@ -6354,10 +6528,10 @@ static expression_t *parse_wide_character_constant(void) cnst->conste.v.wide_character = token.v.wide_string; if (cnst->conste.v.wide_character.size != 1) { - if (warning.multichar && GNU_MODE) { + if (!GNU_MODE) { + errorf(HERE, "more than 1 character in character constant"); + } else if (warning.multichar) { warningf(HERE, "multi-character character constant"); - } else { - errorf(HERE, "more than 1 characters in character constant"); } } next_token(); @@ -6930,7 +7104,7 @@ static designator_t *parse_designator(void) next_token(); designator_t *last_designator = result; - while(true) { + while (true) { if (token.type == '.') { next_token(); if (token.type != T_IDENTIFIER) { @@ -7244,11 +7418,11 @@ static label_t *get_label(symbol_t *symbol) entity_t *label; assert(current_function != NULL); - label = get_entity(symbol, NAMESPACE_LOCAL_LABEL); + label = get_entity(symbol, NAMESPACE_LABEL); /* if we found a local label, we already created the declaration */ if (label != NULL && label->kind == ENTITY_LOCAL_LABEL) { - if (label->base.parent_scope != scope) { - assert(label->base.parent_scope->depth < scope->depth); + if (label->base.parent_scope != current_scope) { + assert(label->base.parent_scope->depth < current_scope->depth); current_function->goto_to_outer = true; } return &label->label; @@ -7321,7 +7495,7 @@ static expression_t *parse_noop_expression(void) add_anchor_token(','); if (token.type != ')') { - while(true) { + while (true) { (void)parse_assignment_expression(); if (token.type != ',') break; @@ -7461,8 +7635,6 @@ static expression_t *parse_typeprop(expression_kind_t const kind) eat(kind == EXPR_SIZEOF ? T_sizeof : T___alignof__); - char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; - /* we only refer to a type property, mark this case */ bool old = in_type_prop; in_type_prop = true; @@ -7500,6 +7672,7 @@ typeprop_expression: type->kind == TYPE_BITFIELD ? "bitfield" : NULL; if (wrong_type != NULL) { + char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; errorf(&tp_expression->base.source_position, "operand of %s expression must not be of %s type '%T'", what, wrong_type, orig_type); @@ -7736,7 +7909,7 @@ static expression_t *parse_call_expression(expression_t *expression) } /* do default promotion */ - for( ; argument != NULL; argument = argument->next) { + for (; argument != NULL; argument = argument->next) { type_t *type = argument->expression->base.type; type = get_default_promoted_type(type); @@ -7767,6 +7940,60 @@ static bool same_compound_type(const type_t *type1, const type_t *type2) type1->compound.compound == type2->compound.compound; } +static expression_t const *get_reference_address(expression_t const *expr) +{ + bool regular_take_address = true; + for (;;) { + if (expr->kind == EXPR_UNARY_TAKE_ADDRESS) { + expr = expr->unary.value; + } else { + regular_take_address = false; + } + + if (expr->kind != EXPR_UNARY_DEREFERENCE) + break; + + expr = expr->unary.value; + } + + if (expr->kind != EXPR_REFERENCE) + return NULL; + + /* special case for functions which are automatically converted to a + * pointer to function without an extra TAKE_ADDRESS operation */ + if (!regular_take_address && + expr->reference.entity->kind != ENTITY_FUNCTION) { + return NULL; + } + + return 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); + } +} + +static void semantic_condition(expression_t const *const expr, + char const *const context) +{ + type_t *const type = skip_typeref(expr->base.type); + if (is_type_scalar(type)) { + warn_reference_address_as_bool(expr); + } else if (is_type_valid(type)) { + errorf(&expr->base.source_position, + "%s must have scalar type", context); + } +} + /** * Parse a conditional expression, ie. 'expression ? ... : ...'. * @@ -7782,13 +8009,8 @@ static expression_t *parse_conditional_expression(expression_t *expression) eat('?'); add_anchor_token(':'); - /* 6.5.15.2 */ - type_t *const condition_type_orig = expression->base.type; - type_t *const condition_type = skip_typeref(condition_type_orig); - if (!is_type_scalar(condition_type) && is_type_valid(condition_type)) { - type_error("expected a scalar type in conditional condition", - &expression->base.source_position, condition_type_orig); - } + /* §6.5.15:2 The first operand shall have scalar type. */ + semantic_condition(expression, "condition of conditional operator"); expression_t *true_expression = expression; bool gnu_cond = false; @@ -8063,11 +8285,16 @@ static bool is_lvalue(const expression_t *expression) case EXPR_UNARY_DEREFERENCE: return true; - default: + default: { + type_t *type = skip_typeref(expression->base.type); + return + /* ISO/IEC 14882:1998(E) §3.10:3 */ + is_type_reference(type) || /* Claim it is an lvalue, if the type is invalid. There was a parse * error before, which maybe prevented properly recognizing it as * lvalue. */ - return !is_type_valid(skip_typeref(expression->base.type)); + !is_type_valid(type); + } } } @@ -8117,56 +8344,10 @@ static void semantic_unexpr_plus(unary_expression_t *expression) "traditional C rejects the unary plus operator"); } -static expression_t const *get_reference_address(expression_t const *expr) -{ - bool regular_take_address = true; - for (;;) { - if (expr->kind == EXPR_UNARY_TAKE_ADDRESS) { - expr = expr->unary.value; - } else { - regular_take_address = false; - } - - if (expr->kind != EXPR_UNARY_DEREFERENCE) - break; - - expr = expr->unary.value; - } - - /* special case for functions which are automatically converted to a - * pointer to function without an extra TAKE_ADDRESS operation */ - if (!regular_take_address && expr->kind == EXPR_REFERENCE - && expr->reference.entity->kind == ENTITY_FUNCTION) { - return expr; - } - - return NULL; -} - -static void warn_function_address_as_bool(expression_t const* expr) -{ - if (!warning.address) - return; - - expr = get_reference_address(expr); - if (expr != NULL) { - warningf(&expr->base.source_position, - "the address of '%Y' will always evaluate as 'true'", - expr->reference.entity->base.symbol); - } -} - static void semantic_not(unary_expression_t *expression) { - type_t *const orig_type = expression->value->base.type; - type_t *const type = skip_typeref(orig_type); - if (!is_type_scalar(type) && is_type_valid(type)) { - errorf(&expression->base.source_position, - "operand of ! must be of scalar type"); - } - - warn_function_address_as_bool(expression->value); - + /* §6.5.3.3:1 The operand [...] of the ! operator, scalar type. */ + semantic_condition(expression->value, "operand of !"); expression->base.type = c_mode & _CXX ? type_bool : type_int; } @@ -8242,11 +8423,8 @@ static void semantic_take_addr(unary_expression_t *expression) return; /* §6.5.3.2 */ - if (value->kind != EXPR_ARRAY_ACCESS - && value->kind != EXPR_UNARY_DEREFERENCE - && !is_lvalue(value)) { - errorf(&expression->base.source_position, - "'&' requires an lvalue"); + if (!is_lvalue(value)) { + errorf(&expression->base.source_position, "'&' requires an lvalue"); } if (type->kind == TYPE_BITFIELD) { errorf(&expression->base.source_position, @@ -8758,25 +8936,10 @@ static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression) */ static void semantic_logical_op(binary_expression_t *expression) { - expression_t *const left = expression->left; - expression_t *const right = expression->right; - type_t *const orig_type_left = left->base.type; - type_t *const orig_type_right = right->base.type; - type_t *const type_left = skip_typeref(orig_type_left); - type_t *const type_right = skip_typeref(orig_type_right); - - warn_function_address_as_bool(left); - warn_function_address_as_bool(right); - - if (!is_type_scalar(type_left) || !is_type_scalar(type_right)) { - /* TODO: improve error message */ - if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(&expression->base.source_position, - "operation needs scalar types"); - } - return; - } - + /* §6.5.13:2 Each of the operands shall have scalar type. + * §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"); expression->base.type = c_mode & _CXX ? type_bool : type_int; } @@ -9016,7 +9179,7 @@ static expression_t *parse_sub_expression(precedence_t precedence) assert(left != NULL); left->base.source_position = source_position; - while(true) { + while (true) { if (token.type < 0) { return expected_expression_error(); } @@ -9150,8 +9313,8 @@ static void init_expression_parsers(void) */ static asm_argument_t *parse_asm_arguments(bool is_out) { - asm_argument_t *result = NULL; - asm_argument_t *last = NULL; + asm_argument_t *result = NULL; + asm_argument_t **anchor = &result; while (token.type == T_STRING_LITERAL || token.type == '[') { asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0])); @@ -9234,12 +9397,8 @@ static asm_argument_t *parse_asm_arguments(bool is_out) set_address_taken(expression, true); - if (last != NULL) { - last->next = argument; - } else { - result = argument; - } - last = argument; + *anchor = argument; + anchor = &argument->next; if (token.type != ',') break; @@ -9259,7 +9418,7 @@ static asm_clobber_t *parse_asm_clobbers(void) asm_clobber_t *result = NULL; asm_clobber_t *last = NULL; - while(token.type == T_STRING_LITERAL) { + while (token.type == T_STRING_LITERAL) { asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0])); clobber->clobber = parse_string_literals(); @@ -9531,12 +9690,8 @@ static statement_t *parse_label_statement(void) } /* remember the labels in a list for later checking */ - if (label_last == NULL) { - label_first = &statement->label; - } else { - label_last->next = &statement->label; - } - label_last = &statement->label; + *label_anchor = &statement->label; + label_anchor = &statement->label.next; POP_PARENT; return statement; @@ -9559,6 +9714,9 @@ static statement_t *parse_if(void) add_anchor_token(')'); expression_t *const expr = parse_expression(); statement->ifs.condition = expr; + /* §6.8.4.1:1 The controlling expression of an if statement shall have + * scalar type. */ + semantic_condition(expr, "condition of 'if'-statment"); mark_vars_read(expr, NULL); rem_anchor_token(')'); expect(')'); @@ -9699,6 +9857,9 @@ static statement_t *parse_while(void) add_anchor_token(')'); expression_t *const cond = parse_expression(); statement->whiles.condition = cond; + /* §6.8.5:2 The controlling expression of an iteration statement shall + * have scalar type. */ + semantic_condition(cond, "condition of 'while'-statement"); mark_vars_read(cond, NULL); rem_anchor_token(')'); expect(')'); @@ -9732,6 +9893,9 @@ static statement_t *parse_do(void) add_anchor_token(')'); expression_t *const cond = parse_expression(); statement->do_while.condition = cond; + /* §6.8.5:2 The controlling expression of an iteration statement shall + * have scalar type. */ + semantic_condition(cond, "condition of 'do-while'-statement"); mark_vars_read(cond, NULL); rem_anchor_token(')'); expect(')'); @@ -9761,22 +9925,20 @@ static statement_t *parse_for(void) expect('('); add_anchor_token(')'); - if (token.type != ';') { - if (is_declaration_specifier(&token, false)) { - parse_declaration(record_entity); - } else { - add_anchor_token(';'); - expression_t *const init = parse_expression(); - statement->fors.initialisation = init; - mark_vars_read(init, VAR_ANY); - if (warning.unused_value && !expression_has_effect(init)) { - warningf(&init->base.source_position, - "initialisation of 'for'-statement has no effect"); - } - rem_anchor_token(';'); - expect(';'); - } + if (token.type == ';') { + next_token(); + } else if (is_declaration_specifier(&token, false)) { + parse_declaration(record_entity); } else { + add_anchor_token(';'); + expression_t *const init = parse_expression(); + statement->fors.initialisation = init; + mark_vars_read(init, VAR_ANY); + if (warning.unused_value && !expression_has_effect(init)) { + warningf(&init->base.source_position, + "initialisation of 'for'-statement has no effect"); + } + rem_anchor_token(';'); expect(';'); } @@ -9784,6 +9946,9 @@ static statement_t *parse_for(void) add_anchor_token(';'); expression_t *const cond = parse_expression(); statement->fors.condition = cond; + /* §6.8.5:2 The controlling expression of an iteration statement shall + * have scalar type. */ + semantic_condition(cond, "condition of 'for'-statement"); mark_vars_read(cond, NULL); rem_anchor_token(';'); } @@ -9801,7 +9966,7 @@ static statement_t *parse_for(void) rem_anchor_token(')'); statement->fors.body = parse_loop_body(statement); - assert(scope == &statement->fors.scope); + assert(current_scope == &statement->fors.scope); scope_pop(); environment_pop_to(top); @@ -9811,7 +9976,7 @@ static statement_t *parse_for(void) end_error: POP_PARENT; rem_anchor_token(')'); - assert(scope == &statement->fors.scope); + assert(current_scope == &statement->fors.scope); scope_pop(); environment_pop_to(top); @@ -9831,8 +9996,8 @@ static statement_t *parse_goto(void) expression_t *expression = parse_expression(); mark_vars_read(expression, NULL); - /* Argh: although documentation say the expression must be of type void *, - * gcc excepts anything that can be casted into void * without error */ + /* Argh: although documentation says the expression must be of type void*, + * gcc accepts anything that can be casted into void* without error */ type_t *type = expression->base.type; if (type != type_error_type) { @@ -9863,12 +10028,8 @@ static statement_t *parse_goto(void) } /* remember the goto's in a list for later checking */ - if (goto_last == NULL) { - goto_first = &statement->gotos; - } else { - goto_last->next = &statement->gotos; - } - goto_last = &statement->gotos; + *goto_anchor = &statement->gotos; + goto_anchor = &statement->gotos.next; expect(';'); @@ -9997,7 +10158,7 @@ static statement_t *parse_return(void) mark_vars_read(return_value, NULL); } - const type_t *const func_type = current_function->base.type; + const type_t *const func_type = skip_typeref(current_function->base.type); assert(is_type_function(func_type)); type_t *const return_type = skip_typeref(func_type->function.return_type); @@ -10045,18 +10206,18 @@ static statement_t *parse_declaration_statement(void) { statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION); - entity_t *before = scope->last_entity; + entity_t *before = current_scope->last_entity; if (GNU_MODE) parse_external_declaration(); else parse_declaration(record_entity); if (before == NULL) { - statement->declaration.declarations_begin = scope->entities; + statement->declaration.declarations_begin = current_scope->entities; } else { statement->declaration.declarations_begin = before->base.next; } - statement->declaration.declarations_end = scope->last_entity; + statement->declaration.declarations_end = current_scope->last_entity; return statement; } @@ -10151,15 +10312,15 @@ static statement_t *parse_local_label_declaration(void) goto end_error; } symbol_t *symbol = token.v.symbol; - entity_t *entity = get_entity(symbol, NAMESPACE_LOCAL_LABEL); - if (entity != NULL && entity->base.parent_scope == scope) { + 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); } else { entity = allocate_entity_zero(ENTITY_LOCAL_LABEL); - entity->base.parent_scope = scope; - entity->base.namespc = NAMESPACE_LOCAL_LABEL; + entity->base.parent_scope = current_scope; + entity->base.namespc = NAMESPACE_LABEL; entity->base.source_position = token.source_position; entity->base.symbol = symbol; @@ -10169,7 +10330,7 @@ static statement_t *parse_local_label_declaration(void) if (begin == NULL) begin = entity; - local_label_push(entity); + environment_push(entity); } next_token(); @@ -10184,6 +10345,55 @@ end_error: return statement; } +static void parse_namespace_definition(void) +{ + eat(T_namespace); + + entity_t *entity = NULL; + symbol_t *symbol = NULL; + + if (token.type == T_IDENTIFIER) { + symbol = token.v.symbol; + next_token(); + + entity = get_entity(symbol, NAMESPACE_NORMAL); + if (entity != NULL && entity->kind != ENTITY_NAMESPACE + && entity->base.parent_scope == current_scope) { + error_redefined_as_different_kind(&token.source_position, + entity, ENTITY_NAMESPACE); + entity = NULL; + } + } + + if (entity == NULL) { + entity = allocate_entity_zero(ENTITY_NAMESPACE); + entity->base.symbol = symbol; + entity->base.source_position = token.source_position; + entity->base.namespc = NAMESPACE_NORMAL; + entity->base.parent_scope = current_scope; + } + + if (token.type == '=') { + /* TODO: parse namespace alias */ + panic("namespace alias definition not supported yet"); + } + + environment_push(entity); + append_entity(current_scope, entity); + + size_t const top = environment_top(); + scope_push(&entity->namespacee.members); + + expect('{'); + parse_externals(); + expect('}'); + +end_error: + assert(current_scope == &entity->namespacee.members); + scope_pop(); + environment_pop_to(top); +} + /** * Parse a statement. * There's also parse_statement() which additionally checks for @@ -10208,6 +10418,7 @@ static statement_t *intern_parse_statement(void) * declaration types, so we guess a bit here to improve robustness * for incorrect programs */ switch (la1_type) { + case '&': case '*': if (get_entity(token.v.symbol, NAMESPACE_NORMAL) != NULL) goto expression_statment; @@ -10235,7 +10446,7 @@ expression_statment: } while (token.type == T___extension__); bool old_gcc_extension = in_gcc_extension; in_gcc_extension = true; - statement = parse_statement(); + statement = intern_parse_statement(); in_gcc_extension = old_gcc_extension; break; @@ -10247,22 +10458,22 @@ expression_statment: statement = parse_local_label_declaration(); break; - case ';': statement = parse_empty_statement(); break; - case '{': statement = parse_compound_statement(false); break; - case T___leave: statement = parse_leave_statement(); break; - case T___try: statement = parse_ms_try_statment(); break; - case T_asm: statement = parse_asm_statement(); break; - case T_break: statement = parse_break(); break; - case T_case: statement = parse_case_statement(); break; - case T_continue: statement = parse_continue(); break; - case T_default: statement = parse_default_statement(); break; - case T_do: statement = parse_do(); break; - case T_for: statement = parse_for(); break; - case T_goto: statement = parse_goto(); break; - case T_if: statement = parse_if(); break; - case T_return: statement = parse_return(); break; - case T_switch: statement = parse_switch(); break; - case T_while: statement = parse_while(); break; + case ';': statement = parse_empty_statement(); break; + case '{': statement = parse_compound_statement(false); break; + case T___leave: statement = parse_leave_statement(); break; + case T___try: statement = parse_ms_try_statment(); break; + case T_asm: statement = parse_asm_statement(); break; + case T_break: statement = parse_break(); break; + case T_case: statement = parse_case_statement(); break; + case T_continue: statement = parse_continue(); break; + case T_default: statement = parse_default_statement(); break; + case T_do: statement = parse_do(); break; + case T_for: statement = parse_for(); break; + case T_goto: statement = parse_goto(); break; + case T_if: statement = parse_if(); break; + case T_return: statement = parse_return(); break; + case T_switch: statement = parse_switch(); break; + case T_while: statement = parse_while(); break; EXPRESSION_START statement = parse_expression_statement(); @@ -10316,8 +10527,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) eat('{'); add_anchor_token('}'); - size_t const top = environment_top(); - size_t const top_local = local_label_top(); + size_t const top = environment_top(); scope_push(&statement->compound.scope); statement_t **anchor = &statement->compound.statements; @@ -10357,7 +10567,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) /* look over all statements again to produce no effect warnings */ if (warning.unused_value) { statement_t *sub_statement = statement->compound.statements; - for( ; sub_statement != NULL; sub_statement = sub_statement->base.next) { + for (; sub_statement != NULL; sub_statement = sub_statement->base.next) { if (sub_statement->kind != STATEMENT_EXPRESSION) continue; /* don't emit a warning for the last expression in an expression @@ -10375,42 +10585,14 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) end_error: rem_anchor_token('}'); - assert(scope == &statement->compound.scope); + assert(current_scope == &statement->compound.scope); scope_pop(); environment_pop_to(top); - local_label_pop_to(top_local); POP_PARENT; return statement; } -/** - * Initialize builtin types. - */ -static void initialize_builtin_types(void) -{ - type_intmax_t = make_global_typedef("__intmax_t__", type_long_long); - type_size_t = make_global_typedef("__SIZE_TYPE__", type_unsigned_long); - type_ssize_t = make_global_typedef("__SSIZE_TYPE__", type_long); - type_ptrdiff_t = make_global_typedef("__PTRDIFF_TYPE__", type_long); - type_uintmax_t = make_global_typedef("__uintmax_t__", type_unsigned_long_long); - type_uptrdiff_t = make_global_typedef("__UPTRDIFF_TYPE__", type_unsigned_long); - type_wchar_t = make_global_typedef("__WCHAR_TYPE__", opt_short_wchar_t ? type_unsigned_short : type_int); - type_wint_t = make_global_typedef("__WINT_TYPE__", type_int); - - type_intmax_t_ptr = make_pointer_type(type_intmax_t, TYPE_QUALIFIER_NONE); - type_ptrdiff_t_ptr = make_pointer_type(type_ptrdiff_t, TYPE_QUALIFIER_NONE); - type_ssize_t_ptr = make_pointer_type(type_ssize_t, TYPE_QUALIFIER_NONE); - type_wchar_t_ptr = make_pointer_type(type_wchar_t, TYPE_QUALIFIER_NONE); - - /* const version of wchar_t */ - type_const_wchar_t = allocate_type_zero(TYPE_TYPEDEF); - type_const_wchar_t->typedeft.typedefe = type_wchar_t->typedeft.typedefe; - type_const_wchar_t->base.qualifiers |= TYPE_QUALIFIER_CONST; - - type_const_wchar_t_ptr = make_pointer_type(type_const_wchar_t, TYPE_QUALIFIER_NONE); -} - /** * Check for unused global static functions and variables */ @@ -10465,18 +10647,94 @@ static void parse_global_asm(void) end_error:; } -/** - * Parse a translation unit. - */ -static void parse_translation_unit(void) +static void parse_linkage_specification(void) +{ + eat(T_extern); + assert(token.type == T_STRING_LITERAL); + + const char *linkage = parse_string_literals().begin; + + linkage_kind_t old_linkage = current_linkage; + linkage_kind_t new_linkage; + if (strcmp(linkage, "C") == 0) { + new_linkage = LINKAGE_C; + } else if (strcmp(linkage, "C++") == 0) { + new_linkage = LINKAGE_CXX; + } else { + errorf(HERE, "linkage string \"%s\" not recognized", linkage); + new_linkage = LINKAGE_INVALID; + } + current_linkage = new_linkage; + + if (token.type == '{') { + next_token(); + parse_externals(); + expect('}'); + } else { + parse_external(); + } + +end_error: + assert(current_linkage == new_linkage); + current_linkage = old_linkage; +} + +static void parse_external(void) +{ + switch (token.type) { + DECLARATION_START_NO_EXTERN + case T_IDENTIFIER: + case T___extension__: + case '(': /* for function declarations with implicit return type and + * parenthesized declarator, i.e. (f)(void); */ + parse_external_declaration(); + return; + + case T_extern: + if (look_ahead(1)->type == T_STRING_LITERAL) { + parse_linkage_specification(); + } else { + parse_external_declaration(); + } + return; + + case T_asm: + parse_global_asm(); + return; + + case T_namespace: + parse_namespace_definition(); + return; + + case ';': + if (!strict_mode) { + if (warning.other) + warningf(HERE, "stray ';' outside of function"); + next_token(); + return; + } + /* FALLTHROUGH */ + + default: + errorf(HERE, "stray %K outside of function", &token); + if (token.type == '(' || token.type == '{' || token.type == '[') + eat_until_matching_token(token.type); + next_token(); + return; + } +} + +static void parse_externals(void) { + add_anchor_token('}'); add_anchor_token(T_EOF); #ifndef NDEBUG unsigned char token_anchor_copy[T_LAST_TOKEN]; memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy)); #endif - for (;;) { + + while (token.type != T_EOF && token.type != '}') { #ifndef NDEBUG bool anchor_leak = false; for (int i = 0; i != T_LAST_TOKEN; ++i) { @@ -10495,37 +10753,30 @@ static void parse_translation_unit(void) abort(); #endif - switch (token.type) { - DECLARATION_START - case T_IDENTIFIER: - case T___extension__: - parse_external_declaration(); - break; + parse_external(); + } - case T_asm: - parse_global_asm(); - break; + rem_anchor_token(T_EOF); + rem_anchor_token('}'); +} - case T_EOF: - rem_anchor_token(T_EOF); - return; +/** + * Parse a translation unit. + */ +static void parse_translation_unit(void) +{ + add_anchor_token(T_EOF); - case ';': - if (!strict_mode) { - if (warning.other) - warningf(HERE, "stray ';' outside of function"); - next_token(); - break; - } - /* FALLTHROUGH */ + while (true) { + parse_externals(); - default: - errorf(HERE, "stray %K outside of function", &token); - if (token.type == '(' || token.type == '{' || token.type == '[') - eat_until_matching_token(token.type); - next_token(); - break; - } + if (token.type == T_EOF) + break; + + errorf(HERE, "stray %K outside of function", &token); + if (token.type == '(' || token.type == '{' || token.type == '[') + eat_until_matching_token(token.type); + next_token(); } } @@ -10538,7 +10789,6 @@ void start_parsing(void) { environment_stack = NEW_ARR_F(stack_entry_t, 0); label_stack = NEW_ARR_F(stack_entry_t, 0); - local_label_stack = NEW_ARR_F(stack_entry_t, 0); diagnostic_count = 0; error_count = 0; warning_count = 0; @@ -10552,17 +10802,15 @@ void start_parsing(void) assert(file_scope == NULL); file_scope = &unit->scope; - assert(scope == NULL); + assert(current_scope == NULL); scope_push(&unit->scope); - - initialize_builtin_types(); } translation_unit_t *finish_parsing(void) { /* do NOT use scope_pop() here, this will crash, will it by hand */ - assert(scope == &unit->scope); - scope = NULL; + assert(current_scope == &unit->scope); + current_scope = NULL; assert(file_scope == &unit->scope); check_unused_globals(); @@ -10570,7 +10818,6 @@ translation_unit_t *finish_parsing(void) DEL_ARR_F(environment_stack); DEL_ARR_F(label_stack); - DEL_ARR_F(local_label_stack); translation_unit_t *result = unit; unit = NULL; @@ -10583,6 +10830,7 @@ void parse(void) for (int i = 0; i < MAX_LOOKAHEAD + 2; ++i) { next_token(); } + current_linkage = c_mode & _CXX ? LINKAGE_CXX : LINKAGE_C; parse_translation_unit(); }