X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=7e44886f46008e79158729be22a7f0faf84fa522;hb=37f1ce3da5d6b4d308af26d117805fa8b357e277;hp=4d1b44b7205d5124e13017468a47d72163f5a5d4;hpb=6ce1c83ddd63ba283fdc50872a56439c6e292579;p=cparser diff --git a/parser.c b/parser.c index 4d1b44b..7e44886 100644 --- a/parser.c +++ b/parser.c @@ -1,6 +1,6 @@ /* * This file is part of cparser. - * Copyright (C) 2007-2008 Matthias Braun + * Copyright (C) 2007-2009 Matthias Braun * * This program is free software; you can redistribute it and/or * modify it under the terms of the GNU General Public License @@ -38,6 +38,7 @@ #include "lang_features.h" #include "walk_statements.h" #include "warning.h" +#include "printer.h" #include "adt/bitfiddle.h" #include "adt/error.h" #include "adt/array.h" @@ -87,6 +88,7 @@ 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_entity = NULL; static entity_t *current_init_decl = NULL; static switch_statement_t *current_switch = NULL; static statement_t *current_loop = NULL; @@ -99,9 +101,9 @@ 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. */ +/** true if we are in a type property context (evaluation only for type) */ static bool in_type_prop = false; -/** true in we are in a __extension__ context. */ +/** true if we are in an __extension__ context. */ static bool in_gcc_extension = false; static struct obstack temp_obst; static entity_t *anonymous_entity; @@ -114,7 +116,7 @@ static declaration_t **incomplete_arrays; #define POP_PARENT ((void)(current_parent = prev_parent)) /** special symbol used for anonymous entities. */ -static const symbol_t *sym_anonymous = NULL; +static symbol_t *sym_anonymous = NULL; /** The token anchor set */ static unsigned char token_anchor_set[T_LAST_TOKEN]; @@ -128,7 +130,7 @@ static unsigned char token_anchor_set[T_LAST_TOKEN]; static statement_t *parse_compound_statement(bool inside_expression_statement); static statement_t *parse_statement(void); -static expression_t *parse_sub_expression(precedence_t); +static expression_t *parse_subexpression(precedence_t); static expression_t *parse_expression(void); static type_t *parse_typename(void); static void parse_externals(void); @@ -149,13 +151,8 @@ typedef enum declarator_flags_t { static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, declarator_flags_t flags); -static entity_t *record_entity(entity_t *entity, bool is_definition); - static void semantic_comparison(binary_expression_t *expression); -static void create_gnu_builtins(void); -static void create_microsoft_intrinsics(void); - #define STORAGE_CLASSES \ STORAGE_CLASSES_NO_EXTERN \ case T_extern: @@ -221,100 +218,52 @@ static void create_microsoft_intrinsics(void); TYPE_QUALIFIERS \ TYPE_SPECIFIERS -#define EXPRESSION_START \ - case '!': \ - case '&': \ - case '(': \ - case '*': \ - case '+': \ - case '-': \ - case '~': \ - case T_ANDAND: \ - case T_CHARACTER_CONSTANT: \ - case T_FLOATINGPOINT: \ - case T_INTEGER: \ - case T_MINUSMINUS: \ - case T_PLUSPLUS: \ - case T_STRING_LITERAL: \ - case T_WIDE_CHARACTER_CONSTANT: \ - case T_WIDE_STRING_LITERAL: \ - case T___FUNCDNAME__: \ - case T___FUNCSIG__: \ - case T___FUNCTION__: \ - case T___PRETTY_FUNCTION__: \ - case T___alignof__: \ - case T___builtin_classify_type: \ - case T___builtin_constant_p: \ - case T___builtin_isgreater: \ - case T___builtin_isgreaterequal: \ - case T___builtin_isless: \ - case T___builtin_islessequal: \ - case T___builtin_islessgreater: \ - case T___builtin_isunordered: \ - case T___builtin_offsetof: \ - case T___builtin_va_arg: \ - case T___builtin_va_start: \ - case T___builtin_va_copy: \ - case T___func__: \ - case T___noop: \ - case T__assume: \ - case T_delete: \ - case T_false: \ - case T_sizeof: \ - case T_throw: \ +#define EXPRESSION_START \ + case '!': \ + case '&': \ + case '(': \ + case '*': \ + case '+': \ + case '-': \ + case '~': \ + case T_ANDAND: \ + case T_CHARACTER_CONSTANT: \ + case T_FLOATINGPOINT: \ + case T_FLOATINGPOINT_HEXADECIMAL: \ + case T_INTEGER: \ + case T_INTEGER_HEXADECIMAL: \ + case T_INTEGER_OCTAL: \ + case T_MINUSMINUS: \ + case T_PLUSPLUS: \ + case T_STRING_LITERAL: \ + case T_WIDE_CHARACTER_CONSTANT: \ + case T_WIDE_STRING_LITERAL: \ + case T___FUNCDNAME__: \ + case T___FUNCSIG__: \ + case T___FUNCTION__: \ + case T___PRETTY_FUNCTION__: \ + case T___alignof__: \ + case T___builtin_classify_type: \ + case T___builtin_constant_p: \ + case T___builtin_isgreater: \ + case T___builtin_isgreaterequal: \ + case T___builtin_isless: \ + case T___builtin_islessequal: \ + case T___builtin_islessgreater: \ + case T___builtin_isunordered: \ + case T___builtin_offsetof: \ + case T___builtin_va_arg: \ + case T___builtin_va_copy: \ + case T___builtin_va_start: \ + case T___func__: \ + case T___noop: \ + case T__assume: \ + case T_delete: \ + case T_false: \ + case T_sizeof: \ + case T_throw: \ case T_true: -/** - * Allocate an AST node with given size and - * initialize all fields with zero. - */ -static void *allocate_ast_zero(size_t size) -{ - void *res = allocate_ast(size); - memset(res, 0, size); - return res; -} - -/** - * Returns the size of an entity node. - * - * @param kind the entity kind - */ -static size_t get_entity_struct_size(entity_kind_t kind) -{ - static const size_t sizes[] = { - [ENTITY_VARIABLE] = sizeof(variable_t), - [ENTITY_PARAMETER] = sizeof(parameter_t), - [ENTITY_COMPOUND_MEMBER] = sizeof(compound_member_t), - [ENTITY_FUNCTION] = sizeof(function_t), - [ENTITY_TYPEDEF] = sizeof(typedef_t), - [ENTITY_STRUCT] = sizeof(compound_t), - [ENTITY_UNION] = sizeof(compound_t), - [ENTITY_ENUM] = sizeof(enum_t), - [ENTITY_ENUM_VALUE] = sizeof(enum_value_t), - [ENTITY_LABEL] = sizeof(label_t), - [ENTITY_LOCAL_LABEL] = sizeof(label_t), - [ENTITY_NAMESPACE] = sizeof(namespace_t) - }; - assert(kind < lengthof(sizes)); - assert(sizes[kind] != 0); - return sizes[kind]; -} - -/** - * Allocate an entity of given kind and initialize all - * fields with zero. - * - * @param kind the kind of the entity to allocate - */ -static entity_t *allocate_entity_zero(entity_kind_t kind) -{ - size_t size = get_entity_struct_size(kind); - entity_t *entity = allocate_ast_zero(size); - entity->kind = kind; - return entity; -} - /** * Returns the size of a statement node. * @@ -359,11 +308,15 @@ static size_t get_expression_struct_size(expression_kind_t kind) [EXPR_INVALID] = sizeof(expression_base_t), [EXPR_REFERENCE] = sizeof(reference_expression_t), [EXPR_REFERENCE_ENUM_VALUE] = sizeof(reference_expression_t), - [EXPR_CONST] = sizeof(const_expression_t), - [EXPR_CHARACTER_CONSTANT] = sizeof(const_expression_t), - [EXPR_WIDE_CHARACTER_CONSTANT] = sizeof(const_expression_t), + [EXPR_LITERAL_INTEGER] = sizeof(literal_expression_t), + [EXPR_LITERAL_INTEGER_OCTAL] = sizeof(literal_expression_t), + [EXPR_LITERAL_INTEGER_HEXADECIMAL]= sizeof(literal_expression_t), + [EXPR_LITERAL_FLOATINGPOINT] = sizeof(literal_expression_t), + [EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL] = sizeof(literal_expression_t), + [EXPR_LITERAL_CHARACTER] = sizeof(literal_expression_t), + [EXPR_LITERAL_WIDE_CHARACTER] = sizeof(literal_expression_t), [EXPR_STRING_LITERAL] = sizeof(string_literal_expression_t), - [EXPR_WIDE_STRING_LITERAL] = sizeof(wide_string_literal_expression_t), + [EXPR_WIDE_STRING_LITERAL] = sizeof(string_literal_expression_t), [EXPR_COMPOUND_LITERAL] = sizeof(compound_literal_expression_t), [EXPR_CALL] = sizeof(call_expression_t), [EXPR_UNARY_FIRST] = sizeof(unary_expression_t), @@ -453,53 +406,10 @@ static statement_t *create_empty_statement(void) return allocate_statement_zero(STATEMENT_EMPTY); } -/** - * Returns the size of a type node. - * - * @param kind the type kind - */ -static size_t get_type_struct_size(type_kind_t kind) -{ - static const size_t sizes[] = { - [TYPE_ATOMIC] = sizeof(atomic_type_t), - [TYPE_COMPLEX] = sizeof(complex_type_t), - [TYPE_IMAGINARY] = sizeof(imaginary_type_t), - [TYPE_BITFIELD] = sizeof(bitfield_type_t), - [TYPE_COMPOUND_STRUCT] = sizeof(compound_type_t), - [TYPE_COMPOUND_UNION] = sizeof(compound_type_t), - [TYPE_ENUM] = sizeof(enum_type_t), - [TYPE_FUNCTION] = sizeof(function_type_t), - [TYPE_POINTER] = sizeof(pointer_type_t), - [TYPE_ARRAY] = sizeof(array_type_t), - [TYPE_BUILTIN] = sizeof(builtin_type_t), - [TYPE_TYPEDEF] = sizeof(typedef_type_t), - [TYPE_TYPEOF] = sizeof(typeof_type_t), - }; - assert(lengthof(sizes) == (int)TYPE_TYPEOF + 1); - assert(kind <= TYPE_TYPEOF); - assert(sizes[kind] != 0); - return sizes[kind]; -} - -/** - * Allocate a type node of given kind and initialize all - * fields with zero. - * - * @param kind type kind to allocate - */ -static type_t *allocate_type_zero(type_kind_t kind) -{ - size_t size = get_type_struct_size(kind); - type_t *res = obstack_alloc(type_obst, size); - memset(res, 0, size); - res->base.kind = kind; - - return res; -} - static function_parameter_t *allocate_parameter(type_t *const type) { - function_parameter_t *const param = obstack_alloc(type_obst, sizeof(*param)); + function_parameter_t *const param + = obstack_alloc(type_obst, sizeof(*param)); memset(param, 0, sizeof(*param)); param->type = type; return param; @@ -569,6 +479,16 @@ static inline void next_token(void) #endif } +static inline bool next_if(int const type) +{ + if (token.type == type) { + next_token(); + return true; + } else { + return false; + } +} + /** * Return the next token with a given lookahead. */ @@ -702,8 +622,7 @@ static void eat_until_anchor(void) static void eat_block(void) { eat_until_matching_token('{'); - if (token.type == '}') - next_token(); + next_if('}'); } #define eat(token_type) (assert(token.type == (token_type)), next_token()) @@ -739,7 +658,7 @@ static void type_error_incompatible(const char *msg, /** * Expect the current token is the expected token. * If not, generate an error, eat the current statement, - * and goto the end_error label. + * and goto the error_label label. */ #define expect(expected, error_label) \ do { \ @@ -747,8 +666,7 @@ static void type_error_incompatible(const char *msg, parse_error_expected(NULL, (expected), NULL); \ add_anchor_token(expected); \ eat_until_anchor(); \ - if (token.type == expected) \ - next_token(); \ + next_if((expected)); \ rem_anchor_token(expected); \ goto error_label; \ } \ @@ -784,6 +702,7 @@ static void scope_pop(scope_t *old_scope) static entity_t *get_entity(const symbol_t *const symbol, namespace_tag_t namespc) { + assert(namespc != NAMESPACE_INVALID); entity_t *entity = symbol->entity; for (; entity != NULL; entity = entity->base.symbol_next) { if (entity->base.namespc == namespc) @@ -796,7 +715,7 @@ static entity_t *get_entity(const symbol_t *const symbol, /* §6.2.3:1 24) There is only one name space for tags even though three are * possible. */ static entity_t *get_tag(symbol_t const *const symbol, - entity_kind_tag_t const kind) + entity_kind_tag_t const kind) { entity_t *entity = get_entity(symbol, NAMESPACE_TAG); if (entity != NULL && entity->kind != kind) { @@ -905,7 +824,7 @@ static void stack_pop_to(stack_entry_t **stack_ptr, size_t new_top) } } - ARR_SHRINKLEN(*stack_ptr, (int) new_top); + ARR_SHRINKLEN(*stack_ptr, new_top); } /** @@ -998,10 +917,13 @@ static bool is_null_pointer_constant(const expression_t *expression) } type_t *const type = skip_typeref(expression->base.type); - return - is_type_integer(type) && - is_constant_expression(expression) && - !fold_constant_to_bool(expression); + if (!is_type_integer(type)) + return false; + switch (is_constant_expression(expression)) { + case EXPR_CLASS_ERROR: return true; + case EXPR_CLASS_CONSTANT: return !fold_constant_to_bool(expression); + default: return false; + } } /** @@ -1137,8 +1059,8 @@ static assign_error_t semantic_assign(type_t *orig_type_left, return ASSIGN_WARNING_POINTER_FROM_INT; } } else if ((is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) || - (is_type_atomic(type_left, ATOMIC_TYPE_BOOL) - && is_type_pointer(type_right))) { + (is_type_atomic(type_left, ATOMIC_TYPE_BOOL) + && is_type_pointer(type_right))) { return ASSIGN_SUCCESS; } else if ((is_type_compound(type_left) && is_type_compound(type_right)) || (is_type_builtin(type_left) && is_type_builtin(type_right))) { @@ -1159,9 +1081,9 @@ static assign_error_t semantic_assign(type_t *orig_type_left, static expression_t *parse_constant_expression(void) { - expression_t *result = parse_sub_expression(PREC_CONDITIONAL); + expression_t *result = parse_subexpression(PREC_CONDITIONAL); - if (!is_constant_expression(result)) { + if (is_constant_expression(result) == EXPR_CLASS_VARIABLE) { errorf(&result->base.source_position, "expression '%E' is not constant", result); } @@ -1171,18 +1093,26 @@ static expression_t *parse_constant_expression(void) static expression_t *parse_assignment_expression(void) { - return parse_sub_expression(PREC_ASSIGNMENT); + return parse_subexpression(PREC_ASSIGNMENT); +} + +static void warn_string_concat(const source_position_t *pos) +{ + if (warning.traditional) { + warningf(pos, "traditional C rejects string constant concatenation"); + } } static string_t parse_string_literals(void) { assert(token.type == T_STRING_LITERAL); - string_t result = token.v.string; + string_t result = token.literal; next_token(); while (token.type == T_STRING_LITERAL) { - result = concat_strings(&result, &token.v.string); + warn_string_concat(&token.source_position); + result = concat_strings(&result, &token.literal); next_token(); } @@ -1242,18 +1172,15 @@ static attribute_t *allocate_attribute_zero(attribute_kind_t kind) */ static attribute_argument_t *parse_attribute_arguments(void) { - if (token.type == ')') - return NULL; - - attribute_argument_t *first = NULL; - attribute_argument_t *last = NULL; - while (true) { + attribute_argument_t *first = NULL; + attribute_argument_t **anchor = &first; + if (token.type != ')') do { attribute_argument_t *argument = allocate_ast_zero(sizeof(*argument)); /* is it an identifier */ if (token.type == T_IDENTIFIER && (look_ahead(1)->type == ',' || look_ahead(1)->type == ')')) { - symbol_t *symbol = token.v.symbol; + symbol_t *symbol = token.symbol; argument->kind = ATTRIBUTE_ARGUMENT_SYMBOL; argument->v.symbol = symbol; next_token(); @@ -1266,20 +1193,10 @@ static attribute_argument_t *parse_attribute_arguments(void) } /* append argument */ - if (last == NULL) { - first = argument; - } else { - last->next = argument; - } - last = argument; - - if (token.type == ',') { - next_token(); - continue; - } - expect(')', end_error); - break; - } + *anchor = argument; + anchor = &argument->next; + } while (next_if(',')); + expect(')', end_error); return first; @@ -1306,7 +1223,7 @@ static symbol_t *get_symbol_from_token(void) { switch(token.type) { case T_IDENTIFIER: - return token.v.symbol; + return token.symbol; case T_auto: case T_char: case T_double: @@ -1348,7 +1265,7 @@ static attribute_t *parse_attribute_gnu_single(void) symbol_t *symbol = get_symbol_from_token(); if (symbol == NULL) { parse_error_expected("while parsing attribute((", T_IDENTIFIER, NULL); - goto end_error; + return NULL; } const char *name = symbol->string; @@ -1373,50 +1290,30 @@ static attribute_t *parse_attribute_gnu_single(void) attribute_t *attribute = allocate_attribute_zero(kind); /* parse arguments */ - if (token.type == '(') { - next_token(); + if (next_if('(')) attribute->a.arguments = parse_attribute_arguments(); - } return attribute; - -end_error: - return NULL; } static attribute_t *parse_attribute_gnu(void) { - attribute_t *first = NULL; - attribute_t *last = NULL; + attribute_t *first = NULL; + attribute_t **anchor = &first; eat(T___attribute__); expect('(', end_error); expect('(', end_error); - if (token.type == ')') { - next_token(); - expect(')', end_error); - return first; - } - - while (true) { + if (token.type != ')') do { attribute_t *attribute = parse_attribute_gnu_single(); if (attribute == NULL) goto end_error; - if (last == NULL) { - first = attribute; - } else { - last->next = attribute; - } - last = attribute; - - if (token.type == ')') { - next_token(); - break; - } - expect(',', end_error); - } + *anchor = attribute; + anchor = &attribute->next; + } while (next_if(',')); + expect(')', end_error); expect(')', end_error); end_error: @@ -1426,12 +1323,10 @@ end_error: /** Parse attributes. */ static attribute_t *parse_attributes(attribute_t *first) { - attribute_t *last = first; - while (true) { - if (last != NULL) { - while (last->next != NULL) - last = last->next; - } + attribute_t **anchor = &first; + for (;;) { + while (*anchor != NULL) + anchor = &(*anchor)->next; attribute_t *attribute; switch (token.type) { @@ -1475,12 +1370,8 @@ static attribute_t *parse_attributes(attribute_t *first) return first; } - if (last == NULL) { - first = attribute; - } else { - last->next = attribute; - } - last = attribute; + *anchor = attribute; + anchor = &attribute->next; } } @@ -1695,11 +1586,9 @@ unary: determine_lhs_ent(expr->va_starte.ap, lhs_ent); return; + EXPR_LITERAL_CASES case EXPR_UNKNOWN: case EXPR_INVALID: - case EXPR_CONST: - case EXPR_CHARACTER_CONSTANT: - case EXPR_WIDE_CHARACTER_CONSTANT: case EXPR_STRING_LITERAL: case EXPR_WIDE_STRING_LITERAL: case EXPR_COMPOUND_LITERAL: // TODO init? @@ -1721,10 +1610,10 @@ unary: static designator_t *parse_designation(void) { - designator_t *result = NULL; - designator_t *last = NULL; + designator_t *result = NULL; + designator_t **anchor = &result; - while (true) { + for (;;) { designator_t *designator; switch (token.type) { case '[': @@ -1745,7 +1634,7 @@ static designator_t *parse_designation(void) T_IDENTIFIER, NULL); return NULL; } - designator->symbol = token.v.symbol; + designator->symbol = token.symbol; next_token(); break; default: @@ -1754,18 +1643,14 @@ static designator_t *parse_designation(void) } assert(designator != NULL); - if (last != NULL) { - last->next = designator; - } else { - result = designator; - } - last = designator; + *anchor = designator; + anchor = &designator->next; } end_error: return NULL; } -static initializer_t *initializer_from_string(array_type_t *type, +static initializer_t *initializer_from_string(array_type_t *const type, const string_t *const string) { /* TODO: check len vs. size of array type */ @@ -1778,7 +1663,7 @@ static initializer_t *initializer_from_string(array_type_t *type, } static initializer_t *initializer_from_wide_string(array_type_t *const type, - wide_string_t *const string) + const string_t *const string) { /* TODO: check len vs. size of array type */ (void) type; @@ -1802,6 +1687,7 @@ static initializer_t *initializer_from_expression(type_t *orig_type, type_t *type = skip_typeref(orig_type); type_t *expr_type_orig = expression->base.type; type_t *expr_type = skip_typeref(expr_type_orig); + if (is_type_array(type) && expr_type->kind == TYPE_POINTER) { array_type_t *const array_type = &type->array; type_t *const element_type = skip_typeref(array_type->element_type); @@ -1809,26 +1695,26 @@ static initializer_t *initializer_from_expression(type_t *orig_type, if (element_type->kind == TYPE_ATOMIC) { atomic_type_kind_t akind = element_type->atomic.akind; switch (expression->kind) { - case EXPR_STRING_LITERAL: - if (akind == ATOMIC_TYPE_CHAR - || akind == ATOMIC_TYPE_SCHAR - || akind == ATOMIC_TYPE_UCHAR) { - return initializer_from_string(array_type, - &expression->string.value); - } - break; + case EXPR_STRING_LITERAL: + if (akind == ATOMIC_TYPE_CHAR + || akind == ATOMIC_TYPE_SCHAR + || akind == ATOMIC_TYPE_UCHAR) { + return initializer_from_string(array_type, + &expression->string_literal.value); + } + break; - case EXPR_WIDE_STRING_LITERAL: { - type_t *bare_wchar_type = skip_typeref(type_wchar_t); - if (get_unqualified_type(element_type) == bare_wchar_type) { - return initializer_from_wide_string(array_type, - &expression->wide_string.value); - } - break; + case EXPR_WIDE_STRING_LITERAL: { + type_t *bare_wchar_type = skip_typeref(type_wchar_t); + if (get_unqualified_type(element_type) == bare_wchar_type) { + return initializer_from_wide_string(array_type, + &expression->string_literal.value); } + break; + } - default: - break; + default: + break; } } } @@ -1840,11 +1726,6 @@ static initializer_t *initializer_from_expression(type_t *orig_type, &expression->base.source_position); initializer_t *const result = allocate_initializer_zero(INITIALIZER_VALUE); -#if 0 - if (type->kind == TYPE_BITFIELD) { - type = type->bitfield.base_type; - } -#endif result->value.value = create_implicit_cast(expression, type); return result; @@ -1855,8 +1736,9 @@ static initializer_t *initializer_from_expression(type_t *orig_type, */ static bool is_initializer_constant(const expression_t *expression) { - return is_constant_expression(expression) - || is_address_constant(expression); + return + is_constant_expression(expression) != EXPR_CLASS_VARIABLE || + is_address_constant(expression) != EXPR_CLASS_VARIABLE; } /** @@ -1869,20 +1751,19 @@ static initializer_t *parse_scalar_initializer(type_t *type, { /* there might be extra {} hierarchies */ int braces = 0; - if (token.type == '{') { + if (next_if('{')) { if (warning.other) warningf(HERE, "extra curly braces around scalar initializer"); do { ++braces; - next_token(); - } while (token.type == '{'); + } while (next_if('{')); } expression_t *expression = parse_assignment_expression(); mark_vars_read(expression, NULL); if (must_be_constant && !is_initializer_constant(expression)) { errorf(&expression->base.source_position, - "Initialisation expression '%E' is not constant", + "initialisation expression '%E' is not constant", expression); } @@ -1898,9 +1779,7 @@ static initializer_t *parse_scalar_initializer(type_t *type, bool additional_warning_displayed = false; while (braces > 0) { - if (token.type == ',') { - next_token(); - } + next_if(','); if (token.type != '}') { if (!additional_warning_displayed && warning.other) { warningf(HERE, "additional elements in scalar initializer"); @@ -2090,7 +1969,7 @@ static bool walk_designator(type_path_t *path, const designator_t *designator, type_t *real_type = skip_typeref(iter->declaration.type); if (real_type->kind == TYPE_BITFIELD) { errorf(&designator->source_position, - "offsetof designator '%Y' may not specify bitfield", + "offsetof designator '%Y' must not specify bitfield", symbol); goto failed; } @@ -2122,8 +2001,8 @@ static bool walk_designator(type_path_t *path, const designator_t *designator, long array_size = type->array.size; if (index >= array_size) { errorf(&designator->source_position, - "designator [%E] (%d) exceeds array size %d", - array_index, index, array_size); + "designator [%E] (%d) exceeds array size %d", + array_index, index, array_size); } } } @@ -2198,8 +2077,7 @@ static void advance_current_object(type_path_t *path, size_t top_path_level) */ static void skip_initializers(void) { - if (token.type == '{') - next_token(); + next_if('{'); while (token.type != '}') { if (token.type == T_EOF) @@ -2251,7 +2129,7 @@ static initializer_t *parse_sub_initializer(type_path_t *path, /* GNU-style designator ("identifier: value") */ designator = allocate_ast_zero(sizeof(designator[0])); designator->source_position = token.source_position; - designator->symbol = token.v.symbol; + designator->symbol = token.symbol; eat(T_IDENTIFIER); eat(':'); @@ -2316,6 +2194,8 @@ finish_designator: if (type == NULL) { /* we are already outside, ... */ + if (outer_type == NULL) + goto error_parse_next; type_t *const outer_type_skip = skip_typeref(outer_type); if (is_type_compound(outer_type_skip) && !outer_type_skip->compound.compound->complete) { @@ -2330,9 +2210,7 @@ finish_designator: && outer_type != NULL) { sub = initializer_from_expression(outer_type, expression); if (sub != NULL) { - if (token.type == ',') { - next_token(); - } + next_if(','); if (token.type != '}' && warning.other) { warningf(HERE, "excessive elements in initializer for type '%T'", orig_type); @@ -2382,10 +2260,10 @@ finish_designator: error_excess: if (warning.other) { if (env->entity != NULL) { - warningf(HERE, "excess elements in struct initializer for '%Y'", - env->entity->base.symbol); + warningf(HERE, "excess elements in initializer for '%Y'", + env->entity->base.symbol); } else { - warningf(HERE, "excess elements in struct initializer"); + warningf(HERE, "excess elements in initializer"); } } } @@ -2430,6 +2308,18 @@ end_error: return NULL; } +static expression_t *make_size_literal(size_t value) +{ + expression_t *literal = allocate_expression_zero(EXPR_LITERAL_INTEGER); + literal->base.type = type_size_t; + + char buf[128]; + snprintf(buf, sizeof(buf), "%u", (unsigned) value); + literal->literal.value = make_string(buf); + + return literal; +} + /** * Parses an initializer. Parsers either a compound literal * (env->declaration == NULL) or an initializer of a declaration. @@ -2437,7 +2327,7 @@ end_error: static initializer_t *parse_initializer(parse_initializer_env_t *env) { type_t *type = skip_typeref(env->type); - size_t max_index = 0xdeadbeaf; // TODO: Resolve this uninitialized variable problem + size_t max_index = 0; initializer_t *result; if (is_type_scalar(type)) { @@ -2495,13 +2385,9 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env) internal_errorf(HERE, "invalid initializer type"); } - expression_t *cnst = allocate_expression_zero(EXPR_CONST); - cnst->base.type = type_size_t; - cnst->conste.v.int_value = size; - type_t *new_type = duplicate_type(type); - new_type->array.size_expression = cnst; + new_type->array.size_expression = make_size_literal(size); new_type->array.size_constant = true; new_type->array.has_implicit_size = true; new_type->array.size = size; @@ -2520,17 +2406,14 @@ static void append_entity(scope_t *scope, entity_t *entity) } else { scope->entities = entity; } - scope->last_entity = entity; + entity->base.parent_entity = current_entity; + scope->last_entity = entity; } static compound_t *parse_compound_type_specifier(bool is_struct) { - if (is_struct) { - eat(T_struct); - } else { - eat(T_union); - } + eat(is_struct ? T_struct : T_union); symbol_t *symbol = NULL; compound_t *compound = NULL; @@ -2543,7 +2426,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct) entity_kind_tag_t const kind = is_struct ? ENTITY_STRUCT : ENTITY_UNION; if (token.type == T_IDENTIFIER) { /* the compound has a name, check if we have seen it already */ - symbol = token.v.symbol; + symbol = token.symbol; next_token(); entity_t *entity = get_tag(symbol, kind); @@ -2579,6 +2462,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct) entity_t *entity = allocate_entity_zero(kind); compound = &entity->compound; + compound->alignment = 1; compound->base.namespc = NAMESPACE_TAG; compound->base.source_position = token.source_position; compound->base.symbol = symbol; @@ -2627,12 +2511,12 @@ static void parse_enum_entries(type_t *const enum_type) entity_t *entity = allocate_entity_zero(ENTITY_ENUM_VALUE); entity->enum_value.enum_type = enum_type; - entity->base.symbol = token.v.symbol; + entity->base.namespc = NAMESPACE_NORMAL; + entity->base.symbol = token.symbol; entity->base.source_position = token.source_position; next_token(); - if (token.type == '=') { - next_token(); + if (next_if('=')) { expression_t *value = parse_constant_expression(); value = create_implicit_cast(value, enum_type); @@ -2642,11 +2526,7 @@ static void parse_enum_entries(type_t *const enum_type) } record_entity(entity, false); - - if (token.type != ',') - break; - next_token(); - } while (token.type != '}'); + } while (next_if(',') && token.type != '}'); rem_anchor_token('}'); expect('}', end_error); @@ -2657,33 +2537,38 @@ end_error: static type_t *parse_enum_specifier(void) { - entity_t *entity; - symbol_t *symbol; + entity_t *entity; + symbol_t *symbol; eat(T_enum); - if (token.type == T_IDENTIFIER) { - symbol = token.v.symbol; - next_token(); + switch (token.type) { + case T_IDENTIFIER: + symbol = token.symbol; + next_token(); - entity = get_tag(symbol, ENTITY_ENUM); - if (entity != NULL) { - if (entity->base.parent_scope != current_scope && - (token.type == '{' || token.type == ';')) { - /* we're in an inner scope and have a definition. Shadow - * existing definition in outer scope */ - entity = NULL; - } else if (entity->enume.complete && token.type == '{') { - errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)", - symbol, &entity->base.source_position); + entity = get_tag(symbol, ENTITY_ENUM); + if (entity != NULL) { + if (entity->base.parent_scope != current_scope && + (token.type == '{' || token.type == ';')) { + /* we're in an inner scope and have a definition. Shadow + * existing definition in outer scope */ + entity = NULL; + } else if (entity->enume.complete && token.type == '{') { + errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)", + symbol, &entity->base.source_position); + } } - } - } else if (token.type != '{') { - parse_error_expected("while parsing enum type specifier", - T_IDENTIFIER, '{', NULL); - return NULL; - } else { - entity = NULL; - symbol = NULL; + break; + + case '{': + entity = NULL; + symbol = NULL; + break; + + default: + parse_error_expected("while parsing enum type specifier", + T_IDENTIFIER, '{', NULL); + return NULL; } if (entity == NULL) { @@ -2745,29 +2630,21 @@ static type_t *parse_typeof(void) bool old_gcc_extension = in_gcc_extension; in_type_prop = true; - while (token.type == T___extension__) { + while (next_if(T___extension__)) { /* This can be a prefix to a typename or an expression. */ - next_token(); in_gcc_extension = true; } switch (token.type) { case T_IDENTIFIER: - if (is_typedef_symbol(token.v.symbol)) { + if (is_typedef_symbol(token.symbol)) { + TYPENAME_START type = parse_typename(); } else { + default: expression = parse_expression(); type = revert_automatic_type_conversion(expression); } break; - - TYPENAME_START - type = parse_typename(); - break; - - default: - expression = parse_expression(); - type = expression->base.type; - break; } in_type_prop = old_type_prop; in_gcc_extension = old_gcc_extension; @@ -2834,7 +2711,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute) attribute_property_argument_t *property = allocate_ast_zero(sizeof(*property)); - while (true) { + do { if (token.type != T_IDENTIFIER) { parse_error_expected("while parsing property declspec", T_IDENTIFIER, NULL); @@ -2842,7 +2719,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute) } bool is_put; - symbol_t *symbol = token.v.symbol; + symbol_t *symbol = token.symbol; next_token(); if (strcmp(symbol->string, "put") == 0) { is_put = true; @@ -2859,15 +2736,12 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute) goto end_error; } if (is_put) { - property->put_symbol = token.v.symbol; + property->put_symbol = token.symbol; } else { - property->get_symbol = token.v.symbol; + property->get_symbol = token.symbol; } next_token(); - if (token.type == ')') - break; - expect(',', end_error); - } + } while (next_if(',')); attribute->a.property = property; @@ -2880,11 +2754,10 @@ end_error: static attribute_t *parse_microsoft_extended_decl_modifier_single(void) { attribute_kind_t kind = ATTRIBUTE_UNKNOWN; - if (token.type == T_restrict) { + if (next_if(T_restrict)) { kind = ATTRIBUTE_MS_RESTRICT; - next_token(); } else if (token.type == T_IDENTIFIER) { - const char *name = token.v.symbol->string; + const char *name = token.symbol->string; next_token(); for (attribute_kind_t k = ATTRIBUTE_MS_FIRST; k <= ATTRIBUTE_MS_LAST; ++k) { @@ -2910,10 +2783,8 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void) } /* parse arguments */ - if (token.type == '(') { - next_token(); + if (next_if('(')) attribute->a.arguments = parse_attribute_arguments(); - } return attribute; } @@ -2924,37 +2795,24 @@ static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first) expect('(', end_error); - if (token.type == ')') { - next_token(); + if (next_if(')')) return NULL; - } add_anchor_token(')'); - attribute_t *last = first; - while (true) { - if (last != NULL) { - while (last->next != NULL) - last = last->next; - } + attribute_t **anchor = &first; + do { + while (*anchor != NULL) + anchor = &(*anchor)->next; attribute_t *attribute = parse_microsoft_extended_decl_modifier_single(); if (attribute == NULL) goto end_error; - if (last == NULL) { - first = attribute; - } else { - last->next = attribute; - } - last = attribute; - - if (token.type == ')') { - break; - } - expect(',', end_error); - } + *anchor = attribute; + anchor = &attribute->next; + } while (next_if(',')); rem_anchor_token(')'); expect(')', end_error); @@ -2968,6 +2826,7 @@ end_error: static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind) { entity_t *entity = allocate_entity_zero(kind); + entity->base.namespc = NAMESPACE_NORMAL; entity->base.source_position = *HERE; entity->base.symbol = symbol; if (is_declaration(entity)) { @@ -3033,10 +2892,10 @@ check_thread_storage_class: 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: + case STORAGE_CLASS_AUTO: wrong = "auto"; goto wrong_thread_storage_class; + case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_storage_class; + case STORAGE_CLASS_TYPEDEF: wrong = "typedef"; goto wrong_thread_storage_class; +wrong_thread_storage_class: errorf(HERE, "'__thread' used with '%s'", wrong); break; } @@ -3173,7 +3032,7 @@ wrong_thread_stoarge_class: } } - type_t *const typedef_type = get_typedef_type(token.v.symbol); + type_t *const typedef_type = get_typedef_type(token.symbol); if (typedef_type == NULL) { /* Be somewhat resilient to typos like 'vodi f()' at the beginning of a * declaration, so it doesn't generate 'implicit int' followed by more @@ -3187,7 +3046,7 @@ wrong_thread_stoarge_class: errorf(HERE, "%K does not name a type", &token); entity_t *entity = - create_error_entity(token.v.symbol, ENTITY_TYPEDEF); + create_error_entity(token.symbol, ENTITY_TYPEDEF); type = allocate_type_zero(TYPE_TYPEDEF); type->typedeft.typedefe = &entity->typedefe; @@ -3416,7 +3275,6 @@ warn_about_long_long: end_error: specifiers->type = type_error_type; - return; } static type_qualifiers_t parse_type_qualifiers(void) @@ -3451,18 +3309,13 @@ static void parse_identifier_list(scope_t *scope) entity_t *entity = allocate_entity_zero(ENTITY_PARAMETER); entity->base.source_position = token.source_position; entity->base.namespc = NAMESPACE_NORMAL; - entity->base.symbol = token.v.symbol; + entity->base.symbol = token.symbol; /* a K&R parameter has no type, yet */ next_token(); if (scope != NULL) append_entity(scope, entity); - - if (token.type != ',') { - break; - } - next_token(); - } while (token.type == T_IDENTIFIER); + } while (next_if(',') && token.type == T_IDENTIFIER); } static entity_t *parse_parameter(void) @@ -3498,7 +3351,7 @@ static bool has_parameters(void) { /* func(void) is not a parameter */ if (token.type == T_IDENTIFIER) { - entity_t const *const entity = get_entity(token.v.symbol, NAMESPACE_NORMAL); + entity_t const *const entity = get_entity(token.symbol, NAMESPACE_NORMAL); if (entity == NULL) return true; if (entity->kind != ENTITY_TYPEDEF) @@ -3525,11 +3378,10 @@ static void parse_parameters(function_type_t *type, scope_t *scope) int saved_comma_state = save_and_reset_anchor_state(','); if (token.type == T_IDENTIFIER && - !is_typedef_symbol(token.v.symbol)) { + !is_typedef_symbol(token.symbol)) { token_type_t la1_type = (token_type_t)look_ahead(1)->type; if (la1_type == ',' || la1_type == ')') { - type->kr_style_parameters = true; - type->unspecified_parameters = true; + type->kr_style_parameters = true; parse_identifier_list(scope); goto parameters_finished; } @@ -3544,7 +3396,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope) if (has_parameters()) { function_parameter_t **anchor = &type->parameters; - for (;;) { + do { switch (token.type) { case T_DOTDOTDOT: next_token(); @@ -3580,11 +3432,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope) default: goto parameters_finished; } - if (token.type != ',') { - goto parameters_finished; - } - next_token(); - } + } while (next_if(',')); } @@ -3643,60 +3491,64 @@ union construct_type_t { parsed_array_t array; }; +static construct_type_t *allocate_declarator_zero(construct_type_kind_t const kind, size_t const size) +{ + construct_type_t *const cons = obstack_alloc(&temp_obst, size); + memset(cons, 0, size); + cons->kind = kind; + return cons; +} + +/* §6.7.5.1 */ static construct_type_t *parse_pointer_declarator(void) { eat('*'); - parsed_pointer_t *pointer = obstack_alloc(&temp_obst, sizeof(pointer[0])); - memset(pointer, 0, sizeof(pointer[0])); - pointer->base.kind = CONSTRUCT_POINTER; - pointer->type_qualifiers = parse_type_qualifiers(); - //pointer->base_variable = base_variable; + construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_POINTER, sizeof(parsed_pointer_t)); + cons->pointer.type_qualifiers = parse_type_qualifiers(); + //cons->pointer.base_variable = base_variable; - return (construct_type_t*) pointer; + return cons; } +/* ISO/IEC 14882:1998(E) §8.3.2 */ static construct_type_t *parse_reference_declarator(void) { eat('&'); - construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->reference)); - parsed_reference_t *reference = &cons->reference; - memset(reference, 0, sizeof(*reference)); - cons->kind = CONSTRUCT_REFERENCE; + if (!(c_mode & _CXX)) + errorf(HERE, "references are only available for C++"); + + construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_REFERENCE, sizeof(parsed_reference_t)); return cons; } +/* §6.7.5.2 */ static construct_type_t *parse_array_declarator(void) { eat('['); add_anchor_token(']'); - construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->array)); - parsed_array_t *array = &cons->array; - memset(array, 0, sizeof(*array)); - cons->kind = CONSTRUCT_ARRAY; + construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_ARRAY, sizeof(parsed_array_t)); + parsed_array_t *const array = &cons->array; - if (token.type == T_static) { - array->is_static = true; - next_token(); - } + bool is_static = next_if(T_static); type_qualifiers_t type_qualifiers = parse_type_qualifiers(); - if (type_qualifiers != 0) { - if (token.type == T_static) { - array->is_static = true; - next_token(); - } - } + + if (!is_static) + is_static = next_if(T_static); + array->type_qualifiers = type_qualifiers; + array->is_static = is_static; + expression_t *size = NULL; if (token.type == '*' && look_ahead(1)->type == ']') { array->is_variable = true; next_token(); } else if (token.type != ']') { - expression_t *const size = parse_assignment_expression(); + size = parse_assignment_expression(); /* §6.7.5.2:1 Array size must have integer type */ type_t *const orig_type = size->base.type; @@ -3711,6 +3563,9 @@ static construct_type_t *parse_array_declarator(void) mark_vars_read(size, NULL); } + if (is_static && size == NULL) + errorf(HERE, "static array parameters require a size"); + rem_anchor_token(']'); expect(']', end_error); @@ -3718,34 +3573,19 @@ end_error: return cons; } +/* §6.7.5.3 */ static construct_type_t *parse_function_declarator(scope_t *scope) { type_t *type = allocate_type_zero(TYPE_FUNCTION); function_type_t *ftype = &type->function; - ftype->linkage = current_linkage; - -#if 0 - 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; - - default: - errorf(HERE, "multiple calling conventions in declaration"); - break; - } -#endif + ftype->linkage = current_linkage; + ftype->calling_convention = CC_DEFAULT; parse_parameters(ftype, scope); - construct_type_t *cons = obstack_alloc(&temp_obst, sizeof(cons->function)); - construct_function_type_t *function = &cons->function; - memset(function, 0, sizeof(*function)); - cons->kind = CONSTRUCT_FUNCTION; - function->function_type = type; + construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_FUNCTION, sizeof(construct_function_type_t)); + cons->function.function_type = type; return cons; } @@ -3760,6 +3600,7 @@ typedef struct parse_declarator_env_t { attribute_t *attributes; } parse_declarator_env_t; +/* §6.7.5 */ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env) { /* construct a single linked list of construct_type_t's which describe @@ -3774,32 +3615,11 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env) //variable_t *based = NULL; /* MS __based extension */ switch (token.type) { case '&': - if (!(c_mode & _CXX)) - errorf(HERE, "references are only available for C++"); type = parse_reference_declarator(); break; case T__based: { -#if 0 - source_position_t const pos = *HERE; - next_token(); - expect('(', end_error); - add_anchor_token(')'); - based = parse_microsoft_based(); - rem_anchor_token(')'); - expect(')', end_error); - if (token.type != '*') { - if (token.type == T__based) { - errorf(&pos, "__based type modifier specified more than once"); - } else if (warning.other) { - warningf(&pos, - "__based does not precede a pointer declarator, ignored"); - } - continue; - } -#else - panic("based currently disabled"); -#endif + panic("based not supported anymore"); /* FALLTHROUGH */ } @@ -3819,11 +3639,6 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env) } ptr_operator_end: ; -#if 0 - modifiers |= env->modifiers; - env->modifiers = modifiers; -#endif - construct_type_t *inner_types = NULL; switch (token.type) { @@ -3831,7 +3646,7 @@ ptr_operator_end: ; if (env->must_be_abstract) { errorf(HERE, "no identifier expected in typename"); } else { - env->symbol = token.v.symbol; + env->symbol = token.symbol; env->source_position = token.source_position; } next_token(); @@ -3850,12 +3665,16 @@ ptr_operator_end: ; } rem_anchor_token(')'); expect(')', end_error); + } else if (!env->may_be_abstract) { + errorf(HERE, "declarator must have a name"); + goto error_out; } break; default: if (env->may_be_abstract) break; parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL); +error_out: eat_until_anchor(); return NULL; } @@ -3898,7 +3717,8 @@ end_error: return NULL; } -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->base.next) { @@ -3966,24 +3786,31 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, type_ array_type->array.size_expression = size_expression; if (size_expression != NULL) { - if (is_constant_expression(size_expression)) { - long const size - = fold_constant_to_int(size_expression); - array_type->array.size = size; - array_type->array.size_constant = true; - /* §6.7.5.2:1 If the expression is a constant expression, it shall - * have a value greater than zero. */ - if (size <= 0) { - if (size < 0 || !GNU_MODE) { - errorf(&size_expression->base.source_position, - "size of array must be greater than zero"); - } else if (warning.other) { - warningf(&size_expression->base.source_position, - "zero length arrays are a GCC extension"); + switch (is_constant_expression(size_expression)) { + case EXPR_CLASS_CONSTANT: { + long const size = fold_constant_to_int(size_expression); + array_type->array.size = size; + array_type->array.size_constant = true; + /* §6.7.5.2:1 If the expression is a constant expression, it shall + * have a value greater than zero. */ + if (size <= 0) { + if (size < 0 || !GNU_MODE) { + errorf(&size_expression->base.source_position, + "size of array must be greater than zero"); + } else if (warning.other) { + warningf(&size_expression->base.source_position, + "zero length arrays are a GCC extension"); + } } + break; } - } else { - array_type->array.is_vla = true; + + case EXPR_CLASS_VARIABLE: + array_type->array.is_vla = true; + break; + + case EXPR_CLASS_ERROR: + break; } } @@ -4057,19 +3884,16 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, attribute_t *attributes = parse_attributes(env.attributes); /* append (shared) specifier attribute behind attributes of this - declarator */ - if (attributes != NULL) { - attribute_t *last = attributes; - while (last->next != NULL) - last = last->next; - last->next = specifiers->attributes; - } else { - attributes = specifiers->attributes; - } + * declarator */ + attribute_t **anchor = &attributes; + while (*anchor != NULL) + anchor = &(*anchor)->next; + *anchor = specifiers->attributes; entity_t *entity; if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) { entity = allocate_entity_zero(ENTITY_TYPEDEF); + entity->base.namespc = NAMESPACE_NORMAL; entity->base.symbol = env.symbol; entity->base.source_position = env.source_position; entity->typedefe.type = orig_type; @@ -4122,10 +3946,10 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, bool in_function_scope = current_function != NULL; if (specifiers->thread_local || ( - specifiers->storage_class != STORAGE_CLASS_EXTERN && - specifiers->storage_class != STORAGE_CLASS_NONE && - (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC) - )) { + specifiers->storage_class != STORAGE_CLASS_EXTERN && + 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); } @@ -4176,7 +4000,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, storage_class_t storage_class = specifiers->storage_class; entity->declaration.declared_storage_class = storage_class; - if (storage_class == STORAGE_CLASS_NONE && current_scope != file_scope) + if (storage_class == STORAGE_CLASS_NONE && current_function != NULL) storage_class = STORAGE_CLASS_AUTO; entity->declaration.storage_class = storage_class; } @@ -4216,7 +4040,7 @@ static type_t *parse_abstract_declarator(type_t *base_type) * @param decl the declaration to check * @param type the function type of the declaration */ -static void check_type_of_main(const entity_t *entity) +static void check_main(const entity_t *entity) { const source_position_t *pos = &entity->base.source_position; if (entity->kind != ENTITY_FUNCTION) { @@ -4286,18 +4110,59 @@ static void error_redefined_as_different_kind(const source_position_t *pos, static bool is_error_entity(entity_t *const ent) { if (is_declaration(ent)) { - return is_type_valid(skip_typeref(ent->declaration.type)); + return !is_type_valid(skip_typeref(ent->declaration.type)); } else if (ent->kind == ENTITY_TYPEDEF) { - return is_type_valid(skip_typeref(ent->typedefe.type)); + return !is_type_valid(skip_typeref(ent->typedefe.type)); + } + return false; +} + +static bool contains_attribute(const attribute_t *list, const attribute_t *attr) +{ + for (const attribute_t *tattr = list; tattr != NULL; tattr = tattr->next) { + if (attributes_equal(tattr, attr)) + return true; } return false; } +/** + * test wether new_list contains any attributes not included in old_list + */ +static bool has_new_attributes(const attribute_t *old_list, + const attribute_t *new_list) +{ + for (const attribute_t *attr = new_list; attr != NULL; attr = attr->next) { + if (!contains_attribute(old_list, attr)) + return true; + } + return false; +} + +/** + * Merge in attributes from an attribute list (probably from a previous + * declaration with the same name). Warning: destroys the old structure + * of the attribute list - don't reuse attributes after this call. + */ +static void merge_in_attributes(declaration_t *decl, attribute_t *attributes) +{ + attribute_t *next; + for (attribute_t *attr = attributes; attr != NULL; attr = next) { + next = attr->next; + if (contains_attribute(decl->attributes, attr)) + continue; + + /* move attribute to new declarations attributes list */ + attr->next = decl->attributes; + decl->attributes = attr; + } +} + /** * record entities for the NAMESPACE_NORMAL, and produce error messages/warnings * for various problems that occur for multiple definitions */ -static entity_t *record_entity(entity_t *entity, const bool is_definition) +entity_t *record_entity(entity_t *entity, const bool is_definition) { const symbol_t *const symbol = entity->base.symbol; const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc; @@ -4325,7 +4190,7 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition) if (warning.main && current_scope == file_scope && is_sym_main(symbol)) { - check_type_of_main(entity); + check_main(entity); } } @@ -4398,6 +4263,7 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition) &previous_entity->base.source_position); } else { unsigned old_storage_class = prev_decl->storage_class; + if (warning.redundant_decls && is_definition && !prev_decl->used && @@ -4446,22 +4312,28 @@ static entity_t *record_entity(entity_t *entity, const bool is_definition) if (old_storage_class == STORAGE_CLASS_EXTERN && new_storage_class == STORAGE_CLASS_EXTERN) { -warn_redundant_declaration: - if (!is_definition && + +warn_redundant_declaration: ; + bool has_new_attrs + = has_new_attributes(prev_decl->attributes, + decl->attributes); + 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); + "redundant declaration for '%Y' (declared %P)", + symbol, &previous_entity->base.source_position); } } 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); + "static declaration of '%Y' follows non-static declaration (declared %P)", + symbol, &previous_entity->base.source_position); } else if (old_storage_class == STORAGE_CLASS_EXTERN) { prev_decl->storage_class = STORAGE_CLASS_NONE; prev_decl->declared_storage_class = STORAGE_CLASS_NONE; @@ -4547,7 +4419,7 @@ static bool is_declaration_specifier(const token_t *token, TYPE_QUALIFIERS return true; case T_IDENTIFIER: - return is_typedef_symbol(token->v.symbol); + return is_typedef_symbol(token->symbol); case T___extension__: STORAGE_CLASSES @@ -4695,9 +4567,8 @@ static void parse_declaration_rest(entity_t *ndeclaration, check_variable_type_complete(entity); - if (token.type != ',') + if (!next_if(',')) break; - eat(','); add_anchor_token('='); ndeclaration = parse_declarator(specifiers, flags); @@ -4778,7 +4649,6 @@ static void parse_kr_declaration_list(entity_t *entity) if (!type->function.kr_style_parameters) return; - add_anchor_token('{'); /* push function parameters */ @@ -4820,8 +4690,30 @@ decl_list_end: function_parameter_t *parameters = NULL; function_parameter_t **anchor = ¶meters; + /* did we have an earlier prototype? */ + entity_t *proto_type = get_entity(entity->base.symbol, NAMESPACE_NORMAL); + if (proto_type != NULL && proto_type->kind != ENTITY_FUNCTION) + proto_type = NULL; + + function_parameter_t *proto_parameter = NULL; + if (proto_type != NULL) { + type_t *proto_type_type = proto_type->declaration.type; + proto_parameter = proto_type_type->function.parameters; + /* If a K&R function definition has a variadic prototype earlier, then + * make the function definition variadic, too. This should conform to + * §6.7.5.3:15 and §6.9.1:8. */ + new_type->function.variadic = proto_type_type->function.variadic; + } else { + /* §6.9.1.7: A K&R style parameter list does NOT act as a function + * prototype */ + new_type->function.unspecified_parameters = true; + } + + bool need_incompatible_warning = false; parameter = entity->function.parameters.entities; - for (; parameter != NULL; parameter = parameter->base.next) { + for (; parameter != NULL; parameter = parameter->base.next, + proto_parameter = + proto_parameter == NULL ? NULL : proto_parameter->next) { if (parameter->kind != ENTITY_PARAMETER) continue; @@ -4843,25 +4735,42 @@ decl_list_end: semantic_parameter_incomplete(parameter); - /* - * we need the default promoted types for the function type - */ - parameter_type = get_default_promoted_type(parameter_type); - - function_parameter_t *const parameter = - allocate_parameter(parameter_type); + /* we need the default promoted types for the function type */ + type_t *not_promoted = parameter_type; + parameter_type = get_default_promoted_type(parameter_type); + + /* gcc special: if the type of the prototype matches the unpromoted + * type don't promote */ + if (!strict_mode && proto_parameter != NULL) { + type_t *proto_p_type = skip_typeref(proto_parameter->type); + type_t *promo_skip = skip_typeref(parameter_type); + type_t *param_skip = skip_typeref(not_promoted); + if (!types_compatible(proto_p_type, promo_skip) + && types_compatible(proto_p_type, param_skip)) { + /* don't promote */ + need_incompatible_warning = true; + parameter_type = not_promoted; + } + } + function_parameter_t *const parameter + = allocate_parameter(parameter_type); *anchor = parameter; anchor = ¶meter->next; } - /* §6.9.1.7: A K&R style parameter list does NOT act as a function - * prototype */ - new_type->function.parameters = parameters; - new_type->function.unspecified_parameters = true; - + new_type->function.parameters = parameters; new_type = identify_new_type(new_type); + if (warning.other && need_incompatible_warning) { + type_t *proto_type_type = proto_type->declaration.type; + warningf(HERE, + "declaration '%#T' is incompatible with '%#T' (declared %P)", + proto_type_type, proto_type->base.symbol, + new_type, entity->base.symbol, + &proto_type->base.source_position); + } + entity->declaration.type = new_type; rem_anchor_token('{'); @@ -4989,8 +4898,8 @@ static void check_declarations(void) static int determine_truth(expression_t const* const cond) { return - !is_constant_expression(cond) ? 0 : - fold_constant_to_bool(cond) ? 1 : + is_constant_expression(cond) != EXPR_CLASS_CONSTANT ? 0 : + fold_constant_to_bool(cond) ? 1 : -1; } @@ -5022,9 +4931,7 @@ static bool expression_returns(expression_t const *const expr) case EXPR_REFERENCE: case EXPR_REFERENCE_ENUM_VALUE: - case EXPR_CONST: - case EXPR_CHARACTER_CONSTANT: - case EXPR_WIDE_CHARACTER_CONSTANT: + EXPR_LITERAL_CASES case EXPR_STRING_LITERAL: case EXPR_WIDE_STRING_LITERAL: case EXPR_COMPOUND_LITERAL: // TODO descend into initialisers @@ -5202,7 +5109,7 @@ static void check_reachable(statement_t *const stmt) if (!expression_returns(expr)) return; - if (is_constant_expression(expr)) { + if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) { long const val = fold_constant_to_int(expr); case_label_statement_t * defaults = NULL; for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) { @@ -5248,9 +5155,8 @@ static void check_reachable(statement_t *const stmt) break; } - case STATEMENT_CONTINUE: { - statement_t *parent = stmt; - for (;;) { + case STATEMENT_CONTINUE: + for (statement_t *parent = stmt;;) { parent = parent->base.parent; if (parent == NULL) /* continue not within loop */ return; @@ -5264,11 +5170,9 @@ static void check_reachable(statement_t *const stmt) default: break; } } - } - case STATEMENT_BREAK: { - statement_t *parent = stmt; - for (;;) { + case STATEMENT_BREAK: + for (statement_t *parent = stmt;;) { parent = parent->base.parent; if (parent == NULL) /* break not within loop/switch */ return; @@ -5287,7 +5191,6 @@ static void check_reachable(statement_t *const stmt) } found_break_parent: break; - } case STATEMENT_GOTO: if (stmt->gotos.expression) { @@ -5683,8 +5586,7 @@ static void parse_external_declaration(void) /* §6.7.5.3:14 a function definition with () means no * parameters (and not unspecified parameters) */ if (type->function.unspecified_parameters && - type->function.parameters == NULL && - !type->function.kr_style_parameters) { + type->function.parameters == NULL) { type_t *copy = duplicate_type(type); copy->function.unspecified_parameters = false; type = identify_new_type(copy); @@ -5729,7 +5631,9 @@ static void parse_external_declaration(void) /* parse function body */ int label_stack_top = label_top(); function_t *old_current_function = current_function; + entity_t *old_current_entity = current_entity; current_function = function; + current_entity = (entity_t*) function; current_parent = NULL; goto_first = NULL; @@ -5761,6 +5665,8 @@ static void parse_external_declaration(void) assert(current_parent == NULL); assert(current_function == function); + assert(current_entity == (entity_t*) function); + current_entity = old_current_entity; current_function = old_current_function; label_pop_to(label_stack_top); } @@ -5783,13 +5689,13 @@ static type_t *make_bitfield_type(type_t *base_type, expression_t *size, type_t *skipped_type = skip_typeref(base_type); if (!is_type_integer(skipped_type)) { errorf(HERE, "bitfield base type '%T' is not an integer type", - base_type); + base_type); bit_size = 0; } else { bit_size = get_type_size(base_type) * 8; } - if (is_constant_expression(size)) { + if (is_constant_expression(size) == EXPR_CLASS_CONSTANT) { long v = fold_constant_to_int(size); const symbol_t *user_symbol = symbol == NULL ? sym_anonymous : symbol; @@ -5929,7 +5835,7 @@ static expression_t *find_create_select(const source_position_t *pos, static void parse_compound_declarators(compound_t *compound, const declaration_specifiers_t *specifiers) { - while (true) { + do { entity_t *entity; if (token.type == ':') { @@ -5942,15 +5848,11 @@ static void parse_compound_declarators(compound_t *compound, type_t *type = make_bitfield_type(base_type, size, &source_position, NULL); - attribute_t *attributes = parse_attributes(NULL); - if (attributes != NULL) { - attribute_t *last = attributes; - while (last->next != NULL) - last = last->next; - last->next = specifiers->attributes; - } else { - attributes = specifiers->attributes; - } + attribute_t *attributes = parse_attributes(NULL); + attribute_t **anchor = &attributes; + while (*anchor != NULL) + anchor = &(*anchor)->next; + *anchor = specifiers->attributes; entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER); entity->base.namespc = NAMESPACE_NORMAL; @@ -6001,7 +5903,7 @@ static void parse_compound_declarators(compound_t *compound, 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'", + "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 */ @@ -6009,7 +5911,7 @@ static void parse_compound_declarators(compound_t *compound, token.type != ';' || look_ahead(1)->type != '}') { errorf(&entity->base.source_position, - "compound member '%Y' has incomplete type '%T'", + "compound member '%Y' has incomplete type '%T'", entity->base.symbol, orig_type); } } @@ -6018,11 +5920,7 @@ static void parse_compound_declarators(compound_t *compound, append_entity(&compound->members, entity); } } - - if (token.type != ',') - break; - next_token(); - } + } while (next_if(',')); expect(';', end_error); end_error: @@ -6057,12 +5955,12 @@ static type_t *parse_typename(void) declaration_specifiers_t specifiers; memset(&specifiers, 0, sizeof(specifiers)); parse_declaration_specifiers(&specifiers); - if (specifiers.storage_class != STORAGE_CLASS_NONE || - specifiers.thread_local) { + if (specifiers.storage_class != STORAGE_CLASS_NONE + || specifiers.thread_local) { /* TODO: improve error message, user does probably not know what a * storage class is... */ - errorf(HERE, "typename may not have a storage class"); + errorf(HERE, "typename must not have a storage class"); } type_t *result = parse_abstract_declarator(specifiers.type); @@ -6099,82 +5997,184 @@ static expression_t *expected_expression_error(void) return create_invalid_expression(); } +static type_t *get_string_type(void) +{ + return warning.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; +} + /** * Parse a string constant. */ -static expression_t *parse_string_const(void) +static expression_t *parse_string_literal(void) { - wide_string_t wres; - if (token.type == T_STRING_LITERAL) { - string_t res = token.v.string; + source_position_t begin = token.source_position; + string_t res = token.literal; + bool is_wide = (token.type == T_WIDE_STRING_LITERAL); + + next_token(); + while (token.type == T_STRING_LITERAL + || token.type == T_WIDE_STRING_LITERAL) { + warn_string_concat(&token.source_position); + res = concat_strings(&res, &token.literal); next_token(); - while (token.type == T_STRING_LITERAL) { - res = concat_strings(&res, &token.v.string); - next_token(); - } - if (token.type != T_WIDE_STRING_LITERAL) { - expression_t *const cnst = allocate_expression_zero(EXPR_STRING_LITERAL); - /* note: that we use type_char_ptr here, which is already the - * automatic converted type. revert_automatic_type_conversion - * will construct the array type */ - cnst->base.type = warning.write_strings ? type_const_char_ptr : type_char_ptr; - cnst->string.value = res; - return cnst; - } + is_wide |= token.type == T_WIDE_STRING_LITERAL; + } - wres = concat_string_wide_string(&res, &token.v.wide_string); + expression_t *literal; + if (is_wide) { + literal = allocate_expression_zero(EXPR_WIDE_STRING_LITERAL); + literal->base.type = get_wide_string_type(); } else { - wres = token.v.wide_string; + literal = allocate_expression_zero(EXPR_STRING_LITERAL); + literal->base.type = get_string_type(); } + literal->base.source_position = begin; + literal->literal.value = res; + + return literal; +} + +/** + * Parse a boolean constant. + */ +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; + next_token(); + return literal; +} - for (;;) { - switch (token.type) { - case T_WIDE_STRING_LITERAL: - wres = concat_wide_strings(&wres, &token.v.wide_string); - break; +static void warn_traditional_suffix(void) +{ + if (!warning.traditional) + return; + warningf(&token.source_position, "traditional C rejects the '%Y' suffix", + token.symbol); +} - case T_STRING_LITERAL: - wres = concat_wide_string_string(&wres, &token.v.string); - break; +static void check_integer_suffix(void) +{ + symbol_t *suffix = token.symbol; + if (suffix == NULL) + return; - default: { - expression_t *const cnst = allocate_expression_zero(EXPR_WIDE_STRING_LITERAL); - cnst->base.type = warning.write_strings ? type_const_wchar_t_ptr : type_wchar_t_ptr; - cnst->wide_string.value = wres; - return cnst; + bool not_traditional = false; + const char *c = suffix->string; + if (*c == 'l' || *c == 'L') { + ++c; + if (*c == *(c-1)) { + not_traditional = true; + ++c; + if (*c == 'u' || *c == 'U') { + ++c; + } + } else if (*c == 'u' || *c == 'U') { + not_traditional = true; + ++c; + } + } else if (*c == 'u' || *c == 'U') { + not_traditional = true; + ++c; + if (*c == 'l' || *c == 'L') { + ++c; + if (*c == *(c-1)) { + ++c; } } - next_token(); + } + if (*c != '\0') { + errorf(&token.source_position, + "invalid suffix '%s' on integer constant", suffix->string); + } else if (not_traditional) { + warn_traditional_suffix(); } } -/** - * Parse a boolean constant. - */ -static expression_t *parse_bool_const(bool value) +static type_t *check_floatingpoint_suffix(void) { - expression_t *cnst = allocate_expression_zero(EXPR_CONST); - cnst->base.type = type_bool; - cnst->conste.v.int_value = value; + symbol_t *suffix = token.symbol; + type_t *type = type_double; + if (suffix == NULL) + return type; - next_token(); + bool not_traditional = false; + const char *c = suffix->string; + if (*c == 'f' || *c == 'F') { + ++c; + type = type_float; + } else if (*c == 'l' || *c == 'L') { + ++c; + type = type_long_double; + } + if (*c != '\0') { + errorf(&token.source_position, + "invalid suffix '%s' on floatingpoint constant", suffix->string); + } else if (not_traditional) { + warn_traditional_suffix(); + } - return cnst; + return type; } /** * Parse an integer constant. */ -static expression_t *parse_int_const(void) +static expression_t *parse_number_literal(void) { - expression_t *cnst = allocate_expression_zero(EXPR_CONST); - cnst->base.type = token.datatype; - cnst->conste.v.int_value = token.v.intvalue; + expression_kind_t kind; + type_t *type; + + switch (token.type) { + case T_INTEGER: + kind = EXPR_LITERAL_INTEGER; + check_integer_suffix(); + type = type_int; + break; + case T_INTEGER_OCTAL: + kind = EXPR_LITERAL_INTEGER_OCTAL; + check_integer_suffix(); + type = type_int; + break; + case T_INTEGER_HEXADECIMAL: + kind = EXPR_LITERAL_INTEGER_HEXADECIMAL; + check_integer_suffix(); + type = type_int; + break; + case T_FLOATINGPOINT: + kind = EXPR_LITERAL_FLOATINGPOINT; + type = check_floatingpoint_suffix(); + break; + case T_FLOATINGPOINT_HEXADECIMAL: + kind = EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL; + type = check_floatingpoint_suffix(); + break; + default: + panic("unexpected token type in parse_number_literal"); + } + 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; next_token(); - return cnst; + /* integer type depends on the size of the number and the size + * representable by the types. The backend/codegeneration has to determine + * that + */ + determine_literal_type(&literal->literal); + return literal; } /** @@ -6182,20 +6182,23 @@ static expression_t *parse_int_const(void) */ static expression_t *parse_character_constant(void) { - expression_t *cnst = allocate_expression_zero(EXPR_CHARACTER_CONSTANT); - cnst->base.type = token.datatype; - cnst->conste.v.character = token.v.string; + 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; - if (cnst->conste.v.character.size != 1) { - if (!GNU_MODE) { + 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) { + literal->base.type = type_int; warningf(HERE, "multi-character character constant"); } } - next_token(); - return cnst; + next_token(); + return literal; } /** @@ -6203,34 +6206,18 @@ static expression_t *parse_character_constant(void) */ static expression_t *parse_wide_character_constant(void) { - expression_t *cnst = allocate_expression_zero(EXPR_WIDE_CHARACTER_CONSTANT); - cnst->base.type = token.datatype; - cnst->conste.v.wide_character = token.v.wide_string; + 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; - if (cnst->conste.v.wide_character.size != 1) { - if (!GNU_MODE) { - errorf(HERE, "more than 1 character in character constant"); - } else if (warning.multichar) { - warningf(HERE, "multi-character character constant"); - } + size_t len = wstrlen(&literal->literal.value); + if (len != 1) { + warningf(HERE, "multi-character character constant"); } - next_token(); - - return cnst; -} - -/** - * Parse a float constant. - */ -static expression_t *parse_float_const(void) -{ - expression_t *cnst = allocate_expression_zero(EXPR_CONST); - cnst->base.type = token.datatype; - cnst->conste.v.float_value = token.v.floatvalue; next_token(); - - return cnst; + return literal; } static entity_t *create_implicit_function(symbol_t *symbol, @@ -6243,92 +6230,22 @@ static entity_t *create_implicit_function(symbol_t *symbol, type_t *type = identify_new_type(ntype); entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION); - entity->declaration.storage_class = STORAGE_CLASS_EXTERN; - entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN; - entity->declaration.type = type; - entity->declaration.implicit = true; - entity->base.symbol = symbol; - entity->base.source_position = *source_position; - - bool strict_prototypes_old = warning.strict_prototypes; - warning.strict_prototypes = false; - record_entity(entity, false); - warning.strict_prototypes = strict_prototypes_old; - - return entity; -} - -/** - * Creates a return_type (func)(argument_type) function type if not - * already exists. - */ -static type_t *make_function_2_type(type_t *return_type, type_t *argument_type1, - type_t *argument_type2) -{ - function_parameter_t *const parameter2 = allocate_parameter(argument_type2); - function_parameter_t *const parameter1 = allocate_parameter(argument_type1); - parameter1->next = parameter2; - - type_t *type = allocate_type_zero(TYPE_FUNCTION); - type->function.return_type = return_type; - type->function.parameters = parameter1; - - return identify_new_type(type); -} - -/** - * Creates a return_type (func)(argument_type) function type if not - * already exists. - * - * @param return_type the return type - * @param argument_type the argument type - */ -static type_t *make_function_1_type(type_t *return_type, type_t *argument_type) -{ - function_parameter_t *const parameter = allocate_parameter(argument_type); - - type_t *type = allocate_type_zero(TYPE_FUNCTION); - type->function.return_type = return_type; - type->function.parameters = parameter; - - return identify_new_type(type); -} - -static type_t *make_function_1_type_variadic(type_t *return_type, type_t *argument_type) -{ - type_t *res = make_function_1_type(return_type, argument_type); - res->function.variadic = 1; - return res; -} - -/** - * Creates a return_type (func)(void) function type if not - * already exists. - * - * @param return_type the return type - */ -static type_t *make_function_0_type(type_t *return_type) -{ - type_t *type = allocate_type_zero(TYPE_FUNCTION); - type->function.return_type = return_type; - type->function.parameters = NULL; + entity->declaration.storage_class = STORAGE_CLASS_EXTERN; + entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN; + entity->declaration.type = type; + entity->declaration.implicit = true; + entity->base.namespc = NAMESPACE_NORMAL; + entity->base.symbol = symbol; + entity->base.source_position = *source_position; - return identify_new_type(type); -} + if (current_scope != NULL) { + bool strict_prototypes_old = warning.strict_prototypes; + warning.strict_prototypes = false; + record_entity(entity, false); + warning.strict_prototypes = strict_prototypes_old; + } -/** - * Creates a NO_RETURN return_type (func)(void) function type if not - * already exists. - * - * @param return_type the return type - */ -static type_t *make_function_0_type_noreturn(type_t *return_type) -{ - type_t *type = allocate_type_zero(TYPE_FUNCTION); - type->function.return_type = return_type; - type->function.parameters = NULL; - type->function.modifiers |= DM_NORETURN; - return identify_new_type(type); + return entity; } /** @@ -6361,83 +6278,154 @@ static type_t *automatic_type_conversion(type_t *orig_type) type_t *revert_automatic_type_conversion(const expression_t *expression) { switch (expression->kind) { - case EXPR_REFERENCE: { - entity_t *entity = expression->reference.entity; - if (is_declaration(entity)) { - return entity->declaration.type; - } else if (entity->kind == ENTITY_ENUM_VALUE) { - return entity->enum_value.enum_type; - } else { - panic("no declaration or enum in reference"); - } + case EXPR_REFERENCE: { + entity_t *entity = expression->reference.entity; + if (is_declaration(entity)) { + return entity->declaration.type; + } else if (entity->kind == ENTITY_ENUM_VALUE) { + return entity->enum_value.enum_type; + } else { + panic("no declaration or enum in reference"); } + } - case EXPR_SELECT: { - entity_t *entity = expression->select.compound_entry; - assert(is_declaration(entity)); - type_t *type = entity->declaration.type; - return get_qualified_type(type, - expression->base.type->base.qualifiers); - } + case EXPR_SELECT: { + entity_t *entity = expression->select.compound_entry; + assert(is_declaration(entity)); + type_t *type = entity->declaration.type; + return get_qualified_type(type, + expression->base.type->base.qualifiers); + } - case EXPR_UNARY_DEREFERENCE: { - const expression_t *const value = expression->unary.value; - type_t *const type = skip_typeref(value->base.type); - if (!is_type_pointer(type)) - return type_error_type; - return type->pointer.points_to; - } + case EXPR_UNARY_DEREFERENCE: { + const expression_t *const value = expression->unary.value; + type_t *const type = skip_typeref(value->base.type); + if (!is_type_pointer(type)) + return type_error_type; + return type->pointer.points_to; + } - case EXPR_ARRAY_ACCESS: { - const expression_t *array_ref = expression->array_access.array_ref; - type_t *type_left = skip_typeref(array_ref->base.type); - if (!is_type_pointer(type_left)) - return type_error_type; - return type_left->pointer.points_to; - } + case EXPR_ARRAY_ACCESS: { + const expression_t *array_ref = expression->array_access.array_ref; + type_t *type_left = skip_typeref(array_ref->base.type); + if (!is_type_pointer(type_left)) + return type_error_type; + return type_left->pointer.points_to; + } - case EXPR_STRING_LITERAL: { - size_t size = expression->string.value.size; - return make_array_type(type_char, size, TYPE_QUALIFIER_NONE); - } + case EXPR_STRING_LITERAL: { + size_t size = expression->string_literal.value.size; + return make_array_type(type_char, size, TYPE_QUALIFIER_NONE); + } - case EXPR_WIDE_STRING_LITERAL: { - size_t size = expression->wide_string.value.size; - return make_array_type(type_wchar_t, size, TYPE_QUALIFIER_NONE); - } + case EXPR_WIDE_STRING_LITERAL: { + size_t size = wstrlen(&expression->string_literal.value); + return make_array_type(type_wchar_t, size, TYPE_QUALIFIER_NONE); + } - case EXPR_COMPOUND_LITERAL: - return expression->compound_literal.type; + case EXPR_COMPOUND_LITERAL: + return expression->compound_literal.type; - default: - return expression->base.type; + default: + break; } + return expression->base.type; } -static expression_t *parse_reference(void) +/** + * Find an entity matching a symbol in a scope. + * Uses current scope if scope is NULL + */ +static entity_t *lookup_entity(const scope_t *scope, symbol_t *symbol, + namespace_tag_t namespc) { - symbol_t *const symbol = token.v.symbol; + if (scope == NULL) { + return get_entity(symbol, namespc); + } - entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL); + /* we should optimize here, if scope grows above a certain size we should + construct a hashmap here... */ + entity_t *entity = scope->entities; + for ( ; entity != NULL; entity = entity->base.next) { + if (entity->base.symbol == symbol && entity->base.namespc == namespc) + break; + } + + return entity; +} + +static entity_t *parse_qualified_identifier(void) +{ + /* namespace containing the symbol */ + symbol_t *symbol; + source_position_t pos; + const scope_t *lookup_scope = NULL; + + if (next_if(T_COLONCOLON)) + lookup_scope = &unit->scope; + + entity_t *entity; + while (true) { + if (token.type != T_IDENTIFIER) { + parse_error_expected("while parsing identifier", T_IDENTIFIER, NULL); + return create_error_entity(sym_anonymous, ENTITY_VARIABLE); + } + symbol = token.symbol; + pos = *HERE; + next_token(); + + /* lookup entity */ + entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL); + + if (!next_if(T_COLONCOLON)) + break; + + switch (entity->kind) { + case ENTITY_NAMESPACE: + lookup_scope = &entity->namespacee.members; + break; + case ENTITY_STRUCT: + case ENTITY_UNION: + case ENTITY_CLASS: + lookup_scope = &entity->compound.members; + break; + 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; + } + } if (entity == NULL) { - if (!strict_mode && look_ahead(1)->type == '(') { + if (!strict_mode && token.type == '(') { /* an implicitly declared function */ if (warning.error_implicit_function_declaration) { - errorf(HERE, "implicit declaration of function '%Y'", symbol); + errorf(&pos, "implicit declaration of function '%Y'", symbol); } else if (warning.implicit_function_declaration) { - warningf(HERE, "implicit declaration of function '%Y'", symbol); + warningf(&pos, "implicit declaration of function '%Y'", symbol); } - entity = create_implicit_function(symbol, HERE); + entity = create_implicit_function(symbol, &pos); } else { - errorf(HERE, "unknown identifier '%Y' found.", symbol); + errorf(&pos, "unknown identifier '%Y' found.", symbol); entity = create_error_entity(symbol, ENTITY_VARIABLE); } } - type_t *orig_type; + return entity; + +end_error: + /* skip further qualifications */ + while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {} + + return create_error_entity(sym_anonymous, ENTITY_VARIABLE); +} + +static expression_t *parse_reference(void) +{ + entity_t *entity = parse_qualified_identifier(); + type_t *orig_type; if (is_declaration(entity)) { orig_type = entity->declaration.type; } else if (entity->kind == ENTITY_ENUM_VALUE) { @@ -6464,8 +6452,9 @@ static expression_t *parse_reference(void) } if (entity->base.parent_scope != file_scope - && (current_function != NULL && entity->base.parent_scope->depth < current_function->parameters.depth) - && is_type_valid(orig_type) && !is_type_function(orig_type)) { + && (current_function != NULL + && entity->base.parent_scope->depth < current_function->parameters.depth) + && (entity->kind == ENTITY_VARIABLE || entity->kind == ENTITY_PARAMETER)) { if (entity->kind == ENTITY_VARIABLE) { /* access of a variable from an outer function */ entity->variable.address_taken = true; @@ -6484,7 +6473,6 @@ static expression_t *parse_reference(void) entity->declaration.type, entity->base.symbol); } - next_token(); return expression; } @@ -6575,7 +6563,7 @@ static expression_t *parse_cast(void) expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST); cast->base.source_position = source_position; - expression_t *value = parse_sub_expression(PREC_CAST); + expression_t *value = parse_subexpression(PREC_CAST); cast->base.type = type; cast->unary.value = value; @@ -6639,7 +6627,7 @@ static expression_t *parse_parenthesized_expression(void) TYPE_SPECIFIERS return parse_cast(); case T_IDENTIFIER: - if (is_typedef_symbol(token.v.symbol)) { + if (is_typedef_symbol(token.symbol)) { return parse_cast(); } } @@ -6726,13 +6714,12 @@ static designator_t *parse_designator(void) T_IDENTIFIER, NULL); return NULL; } - result->symbol = token.v.symbol; + result->symbol = token.symbol; next_token(); designator_t *last_designator = result; while (true) { - if (token.type == '.') { - next_token(); + if (next_if('.')) { if (token.type != T_IDENTIFIER) { parse_error_expected("while parsing member designator", T_IDENTIFIER, NULL); @@ -6740,15 +6727,14 @@ static designator_t *parse_designator(void) } designator_t *designator = allocate_ast_zero(sizeof(result[0])); designator->source_position = *HERE; - designator->symbol = token.v.symbol; + designator->symbol = token.symbol; next_token(); last_designator->next = designator; last_designator = designator; continue; } - if (token.type == '[') { - next_token(); + if (next_if('[')) { add_anchor_token(']'); designator_t *designator = allocate_ast_zero(sizeof(result[0])); designator->source_position = *HERE; @@ -6829,9 +6815,12 @@ static expression_t *parse_va_start(void) expression_t *const expr = parse_assignment_expression(); if (expr->kind == EXPR_REFERENCE) { entity_t *const entity = expr->reference.entity; - if (entity->base.parent_scope != ¤t_function->parameters - || entity->base.next != NULL - || entity->kind != ENTITY_PARAMETER) { + if (!current_function->base.type->function.variadic) { + errorf(&expr->base.source_position, + "'va_start' used in non-variadic function"); + } else if (entity->base.parent_scope != ¤t_function->parameters || + entity->base.next != NULL || + entity->kind != ENTITY_PARAMETER) { errorf(&expr->base.source_position, "second argument of 'va_start' must be last parameter of the current function"); } else { @@ -7001,31 +6990,6 @@ end_error: return create_invalid_expression(); } -#if 0 -/** - * Parses a __builtin_expect(, end_error) expression. - */ -static expression_t *parse_builtin_expect(void, end_error) -{ - expression_t *expression - = allocate_expression_zero(EXPR_BINARY_BUILTIN_EXPECT); - - eat(T___builtin_expect); - - expect('(', end_error); - expression->binary.left = parse_assignment_expression(); - expect(',', end_error); - expression->binary.right = parse_constant_expression(); - expect(')', end_error); - - expression->base.type = expression->binary.left->base.type; - - return expression; -end_error: - return create_invalid_expression(); -} -#endif - /** * Parses a MS assume() expression. */ @@ -7096,7 +7060,7 @@ static expression_t *parse_label_address(void) parse_error_expected("while parsing label address", T_IDENTIFIER, NULL); goto end_error; } - symbol_t *symbol = token.v.symbol; + symbol_t *symbol = token.symbol; next_token(); label_t *label = get_label(symbol); @@ -7120,10 +7084,11 @@ end_error: static expression_t *parse_noop_expression(void) { /* the result is a (int)0 */ - expression_t *cnst = allocate_expression_zero(EXPR_CONST); - cnst->base.type = type_int; - cnst->conste.v.int_value = 0; - cnst->conste.is_ms_noop = true; + 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; eat(T___noop); @@ -7133,21 +7098,16 @@ static expression_t *parse_noop_expression(void) add_anchor_token(')'); add_anchor_token(','); - if (token.type != ')') { - while (true) { - (void)parse_assignment_expression(); - if (token.type != ',') - break; - next_token(); - } - } + if (token.type != ')') do { + (void)parse_assignment_expression(); + } while (next_if(',')); } rem_anchor_token(','); rem_anchor_token(')'); expect(')', end_error); end_error: - return cnst; + return literal; } /** @@ -7156,55 +7116,61 @@ end_error: static expression_t *parse_primary_expression(void) { switch (token.type) { - case T_false: return parse_bool_const(false); - case T_true: return parse_bool_const(true); - case T_INTEGER: return parse_int_const(); - case T_CHARACTER_CONSTANT: return parse_character_constant(); - case T_WIDE_CHARACTER_CONSTANT: return parse_wide_character_constant(); - case T_FLOATINGPOINT: return parse_float_const(); - case T_STRING_LITERAL: - case T_WIDE_STRING_LITERAL: return parse_string_const(); - case T___FUNCTION__: - case T___func__: return parse_function_keyword(); - case T___PRETTY_FUNCTION__: return parse_pretty_function_keyword(); - case T___FUNCSIG__: return parse_funcsig_keyword(); - case T___FUNCDNAME__: return parse_funcdname_keyword(); - case T___builtin_offsetof: return parse_offsetof(); - case T___builtin_va_start: return parse_va_start(); - case T___builtin_va_arg: return parse_va_arg(); - case T___builtin_va_copy: return parse_va_copy(); - case T___builtin_isgreater: - case T___builtin_isgreaterequal: - case T___builtin_isless: - case T___builtin_islessequal: - case T___builtin_islessgreater: - case T___builtin_isunordered: return parse_compare_builtin(); - case T___builtin_constant_p: return parse_builtin_constant(); - case T___builtin_types_compatible_p: return parse_builtin_types_compatible(); - case T__assume: return parse_assume(); - case T_ANDAND: - if (GNU_MODE) - return parse_label_address(); - break; + case T_false: return parse_boolean_literal(false); + case T_true: return parse_boolean_literal(true); + case T_INTEGER: + case T_INTEGER_OCTAL: + case T_INTEGER_HEXADECIMAL: + case T_FLOATINGPOINT: + case T_FLOATINGPOINT_HEXADECIMAL: return parse_number_literal(); + case T_CHARACTER_CONSTANT: return parse_character_constant(); + case T_WIDE_CHARACTER_CONSTANT: return parse_wide_character_constant(); + case T_STRING_LITERAL: + case T_WIDE_STRING_LITERAL: return parse_string_literal(); + case T___FUNCTION__: + case T___func__: return parse_function_keyword(); + case T___PRETTY_FUNCTION__: return parse_pretty_function_keyword(); + case T___FUNCSIG__: return parse_funcsig_keyword(); + case T___FUNCDNAME__: return parse_funcdname_keyword(); + case T___builtin_offsetof: return parse_offsetof(); + case T___builtin_va_start: return parse_va_start(); + case T___builtin_va_arg: return parse_va_arg(); + case T___builtin_va_copy: return parse_va_copy(); + case T___builtin_isgreater: + case T___builtin_isgreaterequal: + case T___builtin_isless: + case T___builtin_islessequal: + case T___builtin_islessgreater: + case T___builtin_isunordered: return parse_compare_builtin(); + case T___builtin_constant_p: return parse_builtin_constant(); + case T___builtin_types_compatible_p: return parse_builtin_types_compatible(); + case T__assume: return parse_assume(); + case T_ANDAND: + if (GNU_MODE) + return parse_label_address(); + break; - case '(': return parse_parenthesized_expression(); - case T___noop: return parse_noop_expression(); + case '(': return parse_parenthesized_expression(); + case T___noop: return parse_noop_expression(); - /* Gracefully handle type names while parsing expressions. */ - case T_IDENTIFIER: - if (!is_typedef_symbol(token.v.symbol)) { - return parse_reference(); - } - /* FALLTHROUGH */ - TYPENAME_START { - source_position_t const pos = *HERE; - type_t const *const type = parse_typename(); - errorf(&pos, "encountered type '%T' while parsing expression", type); - return create_invalid_expression(); - } + /* Gracefully handle type names while parsing expressions. */ + case T_COLONCOLON: + return parse_reference(); + case T_IDENTIFIER: + if (!is_typedef_symbol(token.symbol)) { + return parse_reference(); + } + /* FALLTHROUGH */ + TYPENAME_START { + source_position_t const pos = *HERE; + type_t const *const type = parse_typename(); + errorf(&pos, "encountered type '%T' while parsing expression", type); + return create_invalid_expression(); + } } errorf(HERE, "unexpected token %K, expected an expression", &token); + eat_until_anchor(); return create_invalid_expression(); } @@ -7297,7 +7263,7 @@ static expression_t *parse_typeprop(expression_kind_t const kind) goto typeprop_expression; } } else { - expression = parse_sub_expression(PREC_UNARY); + expression = parse_subexpression(PREC_UNARY); typeprop_expression: tp_expression->typeprop.tp_expression = expression; @@ -7308,12 +7274,28 @@ typeprop_expression: tp_expression->typeprop.type = orig_type; type_t const* const type = skip_typeref(orig_type); - char const* const wrong_type = - GNU_MODE && is_type_atomic(type, ATOMIC_TYPE_VOID) ? NULL : - is_type_incomplete(type) ? "incomplete" : - type->kind == TYPE_FUNCTION ? "function designator" : - type->kind == TYPE_BITFIELD ? "bitfield" : - NULL; + char const* wrong_type = NULL; + if (is_type_incomplete(type)) { + if (!is_type_atomic(type, ATOMIC_TYPE_VOID) || !GNU_MODE) + wrong_type = "incomplete"; + } 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); + } + } else { + wrong_type = "function"; + } + } else { + if (is_type_incomplete(type)) + wrong_type = "incomplete"; + } + if (type->kind == TYPE_BITFIELD) + wrong_type = "bitfield"; + if (wrong_type != NULL) { char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; errorf(&tp_expression->base.source_position, @@ -7340,13 +7322,14 @@ static expression_t *parse_select_expression(expression_t *addr) { assert(token.type == '.' || token.type == T_MINUSGREATER); bool select_left_arrow = (token.type == T_MINUSGREATER); + source_position_t const pos = *HERE; next_token(); if (token.type != T_IDENTIFIER) { parse_error_expected("while parsing select", T_IDENTIFIER, NULL); return create_invalid_expression(); } - symbol_t *symbol = token.v.symbol; + symbol_t *symbol = token.symbol; next_token(); type_t *const orig_type = addr->base.type; @@ -7356,7 +7339,7 @@ static expression_t *parse_select_expression(expression_t *addr) bool saw_error = false; if (is_type_pointer(type)) { if (!select_left_arrow) { - errorf(HERE, + errorf(&pos, "request for member '%Y' in something not a struct or union, but '%T'", symbol, orig_type); saw_error = true; @@ -7364,7 +7347,7 @@ static expression_t *parse_select_expression(expression_t *addr) type_left = skip_typeref(type->pointer.points_to); } else { if (select_left_arrow && is_type_valid(type)) { - errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type); + errorf(&pos, "left hand side of '->' is not a pointer, but '%T'", orig_type); saw_error = true; } type_left = type; @@ -7374,7 +7357,7 @@ static expression_t *parse_select_expression(expression_t *addr) type_left->kind != TYPE_COMPOUND_UNION) { if (is_type_valid(type_left) && !saw_error) { - errorf(HERE, + errorf(&pos, "request for member '%Y' in something not a struct or union, but '%T'", symbol, type_left); } @@ -7383,17 +7366,17 @@ static expression_t *parse_select_expression(expression_t *addr) compound_t *compound = type_left->compound.compound; if (!compound->complete) { - errorf(HERE, "request for member '%Y' in incomplete type '%T'", + errorf(&pos, "request for member '%Y' in incomplete type '%T'", symbol, type_left); return create_invalid_expression(); } type_qualifiers_t qualifiers = type_left->base.qualifiers; - expression_t *result - = find_create_select(HERE, addr, qualifiers, compound, symbol); + expression_t *result = + find_create_select(&pos, addr, qualifiers, compound, symbol); if (result == NULL) { - errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol); + errorf(&pos, "'%T' has no member named '%Y'", orig_type, symbol); return create_invalid_expression(); } @@ -7466,20 +7449,33 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) { /* argument must be constant */ call_argument_t *argument = call->arguments; - if (! is_constant_expression(argument->expression)) { + if (is_constant_expression(argument->expression) == EXPR_CLASS_VARIABLE) { errorf(&call->base.source_position, "argument of '%Y' must be a constant expression", call->function->reference.entity->base.symbol); } break; } - case bk_gnu_builtin_prefetch: { + case bk_gnu_builtin_object_size: + if (call->arguments == NULL) + break; + + call_argument_t *arg = call->arguments->next; + if (arg != NULL && is_constant_expression(arg->expression) == EXPR_CLASS_VARIABLE) { + errorf(&call->base.source_position, + "second argument of '%Y' must be a constant expression", + call->function->reference.entity->base.symbol); + } + break; + case bk_gnu_builtin_prefetch: /* second and third argument must be constant if existent */ + if (call->arguments == NULL) + break; call_argument_t *rw = call->arguments->next; call_argument_t *locality = NULL; if (rw != NULL) { - if (! is_constant_expression(rw->expression)) { + if (is_constant_expression(rw->expression) == EXPR_CLASS_VARIABLE) { errorf(&call->base.source_position, "second argument of '%Y' must be a constant expression", call->function->reference.entity->base.symbol); @@ -7487,7 +7483,7 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) { locality = rw->next; } if (locality != NULL) { - if (! is_constant_expression(locality->expression)) { + if (is_constant_expression(locality->expression) == EXPR_CLASS_VARIABLE) { errorf(&call->base.source_position, "third argument of '%Y' must be a constant expression", call->function->reference.entity->base.symbol); @@ -7495,7 +7491,6 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) { locality = rw->next; } break; - } default: break; } @@ -7538,17 +7533,13 @@ static expression_t *parse_call_expression(expression_t *expression) if (token.type != ')') { call_argument_t **anchor = &call->arguments; - for (;;) { + do { call_argument_t *argument = allocate_ast_zero(sizeof(*argument)); argument->expression = parse_assignment_expression(); *anchor = argument; anchor = &argument->next; - - if (token.type != ',') - break; - next_token(); - } + } while (next_if(',')); } rem_anchor_token(','); rem_anchor_token(')'); @@ -7576,6 +7567,10 @@ static expression_t *parse_call_expression(expression_t *expression) /* do default promotion for other arguments */ for (; argument != NULL; argument = argument->next) { type_t *type = argument->expression->base.type; + if (!is_type_object(skip_typeref(type))) { + errorf(&argument->expression->base.source_position, + "call argument '%E' must not be void", argument->expression); + } type = get_default_promoted_type(type); @@ -7708,7 +7703,7 @@ static expression_t *parse_conditional_expression(expression_t *expression) expect(':', end_error); end_error:; expression_t *false_expression = - parse_sub_expression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL); + parse_subexpression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL); type_t *const orig_true_type = true_expression->base.type; type_t *const orig_false_type = false_expression->base.type; @@ -7737,13 +7732,6 @@ end_error:; } else if (is_type_arithmetic(true_type) && is_type_arithmetic(false_type)) { result_type = semantic_arithmetic(true_type, false_type); - - true_expression = create_implicit_cast(true_expression, result_type); - false_expression = create_implicit_cast(false_expression, result_type); - - conditional->true_expression = true_expression; - conditional->false_expression = false_expression; - conditional->base.type = result_type; } else if (same_compound_type(true_type, false_type)) { /* just take 1 of the 2 types */ result_type = true_type; @@ -7795,7 +7783,7 @@ end_error:; result_type = pointer_type; } else { if (is_type_valid(other_type)) { - type_error_incompatible("while parsing conditional", + type_error_incompatible("while parsing conditional", &expression->base.source_position, true_type, false_type); } result_type = type_error_type; @@ -7826,7 +7814,7 @@ static expression_t *parse_extension(void) bool old_gcc_extension = in_gcc_extension; in_gcc_extension = true; - expression_t *expression = parse_sub_expression(PREC_UNARY); + expression_t *expression = parse_subexpression(PREC_UNARY); in_gcc_extension = old_gcc_extension; return expression; } @@ -7864,14 +7852,13 @@ static expression_t *parse_delete(void) eat(T_delete); - if (token.type == '[') { - next_token(); + if (next_if('[')) { result->kind = EXPR_UNARY_DELETE_ARRAY; expect(']', end_error); end_error:; } - expression_t *const value = parse_sub_expression(PREC_CAST); + expression_t *const value = parse_subexpression(PREC_CAST); result->unary.value = value; type_t *const type = skip_typeref(value->base.type); @@ -7973,14 +7960,14 @@ static bool is_lvalue(const expression_t *expression) return true; 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. */ - !is_type_valid(type); + 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. */ + !is_type_valid(type); } } } @@ -8135,7 +8122,7 @@ static expression_t *parse_##unexpression_type(void) \ expression_t *unary_expression \ = allocate_expression_zero(unexpression_type); \ eat(token_type); \ - unary_expression->unary.value = parse_sub_expression(PREC_UNARY); \ + unary_expression->unary.value = parse_subexpression(PREC_UNARY); \ \ sfunc(&unary_expression->unary); \ \ @@ -8279,8 +8266,8 @@ static void warn_div_by_zero(binary_expression_t const *const expression) expression_t const *const right = expression->right; /* The type of the right operand can be different for /= */ - if (is_type_integer(right->base.type) && - is_constant_expression(right) && + 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"); } @@ -8331,7 +8318,7 @@ static bool semantic_shift(binary_expression_t *expression) type_left = promote_integer(type_left); - if (is_constant_expression(right)) { + if (is_constant_expression(right) == EXPR_CLASS_CONSTANT) { long count = fold_constant_to_int(right); if (count < 0) { warningf(&right->base.source_position, @@ -8451,8 +8438,8 @@ static void warn_string_literal_address(expression_t const* expr) expr = expr->unary.value; } - if (expr->kind == EXPR_STRING_LITERAL || - expr->kind == EXPR_WIDE_STRING_LITERAL) { + 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"); } @@ -8479,9 +8466,11 @@ static void warn_comparison_in_comparison(const expression_t *const expr) static bool maybe_negative(expression_t const *const expr) { - return - !is_constant_expression(expr) || - fold_constant_to_int(expr) < 0; + switch (is_constant_expression(expr)) { + case EXPR_CLASS_ERROR: return false; + case EXPR_CLASS_CONSTANT: return fold_constant_to_int(expr) < 0; + default: return true; + } } /** @@ -8802,13 +8791,20 @@ static bool expression_has_effect(const expression_t *const expr) case EXPR_INVALID: return true; /* do NOT warn */ case EXPR_REFERENCE: return false; case EXPR_REFERENCE_ENUM_VALUE: return false; + case EXPR_LABEL_ADDRESS: return false; + /* suppress the warning for microsoft __noop operations */ - case EXPR_CONST: return expr->conste.is_ms_noop; - case EXPR_CHARACTER_CONSTANT: return false; - case EXPR_WIDE_CHARACTER_CONSTANT: return false; + case EXPR_LITERAL_MS_NOOP: return true; + case EXPR_LITERAL_BOOLEAN: + case EXPR_LITERAL_CHARACTER: + case EXPR_LITERAL_WIDE_CHARACTER: + case EXPR_LITERAL_INTEGER: + case EXPR_LITERAL_INTEGER_OCTAL: + case EXPR_LITERAL_INTEGER_HEXADECIMAL: + case EXPR_LITERAL_FLOATINGPOINT: + case EXPR_LITERAL_FLOATINGPOINT_HEXADECIMAL: return false; case EXPR_STRING_LITERAL: return false; case EXPR_WIDE_STRING_LITERAL: return false; - case EXPR_LABEL_ADDRESS: return false; case EXPR_CALL: { const call_expression_t *const call = &expr->call; @@ -8942,7 +8938,7 @@ static expression_t *parse_##binexpression_type(expression_t *left) \ binexpr->binary.left = left; \ eat(token_type); \ \ - expression_t *right = parse_sub_expression(prec_r); \ + expression_t *right = parse_subexpression(prec_r); \ \ binexpr->binary.right = right; \ sfunc(&binexpr->binary); \ @@ -8982,7 +8978,7 @@ CREATE_BINEXPR_PARSER(T_CARETEQUAL, EXPR_BINARY_BITWISE_XOR_ASSIGN, PR CREATE_BINEXPR_PARSER(',', EXPR_BINARY_COMMA, PREC_ASSIGNMENT, semantic_comma) -static expression_t *parse_sub_expression(precedence_t precedence) +static expression_t *parse_subexpression(precedence_t precedence) { if (token.type < 0) { return expected_expression_error(); @@ -9027,7 +9023,7 @@ static expression_t *parse_sub_expression(precedence_t precedence) */ static expression_t *parse_expression(void) { - return parse_sub_expression(PREC_EXPRESSION); + return parse_subexpression(PREC_EXPRESSION); } /** @@ -9142,14 +9138,13 @@ static asm_argument_t *parse_asm_arguments(bool is_out) asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0])); memset(argument, 0, sizeof(argument[0])); - if (token.type == '[') { - eat('['); + if (next_if('[')) { if (token.type != T_IDENTIFIER) { parse_error_expected("while parsing asm argument", T_IDENTIFIER, NULL); return NULL; } - argument->symbol = token.v.symbol; + argument->symbol = token.symbol; expect(']', end_error); } @@ -9209,7 +9204,9 @@ static asm_argument_t *parse_asm_arguments(bool is_out) "asm output argument is not an lvalue"); } - if (argument->constraints.begin[0] == '+') + if (argument->constraints.begin[0] == '=') + determine_lhs_ent(expression, NULL); + else mark_vars_read(expression, NULL); } else { mark_vars_read(expression, NULL); @@ -9222,9 +9219,8 @@ static asm_argument_t *parse_asm_arguments(bool is_out) *anchor = argument; anchor = &argument->next; - if (token.type != ',') + if (!next_if(',')) break; - eat(','); } return result; @@ -9237,23 +9233,18 @@ end_error: */ static asm_clobber_t *parse_asm_clobbers(void) { - asm_clobber_t *result = NULL; - asm_clobber_t *last = NULL; + asm_clobber_t *result = NULL; + asm_clobber_t **anchor = &result; while (token.type == T_STRING_LITERAL) { asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0])); clobber->clobber = parse_string_literals(); - if (last != NULL) { - last->next = clobber; - } else { - result = clobber; - } - last = clobber; + *anchor = clobber; + anchor = &clobber->next; - if (token.type != ',') + if (!next_if(',')) break; - eat(','); } return result; @@ -9269,36 +9260,35 @@ static statement_t *parse_asm_statement(void) eat(T_asm); - if (token.type == T_volatile) { - next_token(); + if (next_if(T_volatile)) asm_statement->is_volatile = true; - } expect('(', end_error); add_anchor_token(')'); - add_anchor_token(':'); + if (token.type != T_STRING_LITERAL) { + parse_error_expected("after asm(", T_STRING_LITERAL, NULL); + goto end_of_asm; + } asm_statement->asm_text = parse_string_literals(); - if (token.type != ':') { + add_anchor_token(':'); + if (!next_if(':')) { rem_anchor_token(':'); goto end_of_asm; } - eat(':'); asm_statement->outputs = parse_asm_arguments(true); - if (token.type != ':') { + if (!next_if(':')) { rem_anchor_token(':'); goto end_of_asm; } - eat(':'); asm_statement->inputs = parse_asm_arguments(false); - if (token.type != ':') { + if (!next_if(':')) { rem_anchor_token(':'); goto end_of_asm; } rem_anchor_token(':'); - eat(':'); asm_statement->clobbers = parse_asm_clobbers(); @@ -9318,6 +9308,36 @@ end_error: return create_invalid_statement(); } +static statement_t *parse_label_inner_statement(char const *const label, bool const eat_empty_stmt) +{ + statement_t *inner_stmt; + switch (token.type) { + case '}': + errorf(HERE, "%s at end of compound statement", label); + inner_stmt = create_invalid_statement(); + break; + + case ';': + if (eat_empty_stmt) { + /* Eat an empty statement here, to avoid the warning about an empty + * statement after a label. label:; is commonly used to have a label + * before a closing brace. */ + inner_stmt = create_empty_statement(); + next_token(); + break; + } + /* FALLTHROUGH */ + + default: + inner_stmt = parse_statement(); + if (inner_stmt->kind == STATEMENT_DECLARATION) { + errorf(&inner_stmt->base.source_position, "declaration after %s", label); + } + break; + } + return inner_stmt; +} + /** * Parse a case statement. */ @@ -9330,11 +9350,9 @@ static statement_t *parse_case_statement(void) expression_t *const expression = parse_expression(); statement->case_label.expression = expression; - if (!is_constant_expression(expression)) { - /* This check does not prevent the error message in all cases of an - * prior error while parsing the expression. At least it catches the - * common case of a mistyped enum entry. */ - if (is_type_valid(skip_typeref(expression->base.type))) { + expression_classification_t const expr_class = is_constant_expression(expression); + if (expr_class != EXPR_CLASS_CONSTANT) { + if (expr_class != EXPR_CLASS_ERROR) { errorf(pos, "case label does not reduce to an integer constant"); } statement->case_label.is_bad = true; @@ -9345,15 +9363,12 @@ static statement_t *parse_case_statement(void) } if (GNU_MODE) { - if (token.type == T_DOTDOTDOT) { - next_token(); + if (next_if(T_DOTDOTDOT)) { expression_t *const end_range = parse_expression(); statement->case_label.end_range = end_range; - if (!is_constant_expression(end_range)) { - /* This check does not prevent the error message in all cases of an - * prior error while parsing the expression. At least it catches the - * common case of a mistyped enum entry. */ - if (is_type_valid(skip_typeref(end_range->base.type))) { + expression_classification_t const end_class = is_constant_expression(end_range); + if (end_class != EXPR_CLASS_CONSTANT) { + if (end_class != EXPR_CLASS_ERROR) { errorf(pos, "case range does not reduce to an integer constant"); } statement->case_label.is_bad = true; @@ -9401,11 +9416,7 @@ end_error: errorf(pos, "case label not within a switch statement"); } - statement_t *const inner_stmt = parse_statement(); - statement->case_label.statement = inner_stmt; - if (inner_stmt->kind == STATEMENT_DECLARATION) { - errorf(&inner_stmt->base.source_position, "declaration after case label"); - } + statement->case_label.statement = parse_label_inner_statement("case label", false); POP_PARENT; return statement; @@ -9423,6 +9434,8 @@ static statement_t *parse_default_statement(void) PUSH_PARENT(statement); expect(':', end_error); +end_error: + if (current_switch != NULL) { const case_label_statement_t *def_label = current_switch->default_label; if (def_label != NULL) { @@ -9444,17 +9457,10 @@ static statement_t *parse_default_statement(void) "'default' label not within a switch statement"); } - statement_t *const inner_stmt = parse_statement(); - statement->case_label.statement = inner_stmt; - if (inner_stmt->kind == STATEMENT_DECLARATION) { - errorf(&inner_stmt->base.source_position, "declaration after default label"); - } + statement->case_label.statement = parse_label_inner_statement("default label", false); POP_PARENT; return statement; -end_error: - POP_PARENT; - return create_invalid_statement(); } /** @@ -9463,7 +9469,7 @@ end_error: static statement_t *parse_label_statement(void) { assert(token.type == T_IDENTIFIER); - symbol_t *symbol = token.v.symbol; + symbol_t *symbol = token.symbol; label_t *label = get_label(symbol); statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL); @@ -9486,28 +9492,7 @@ static statement_t *parse_label_statement(void) eat(':'); - if (token.type == '}') { - /* TODO only warn? */ - if (warning.other && false) { - warningf(HERE, "label at end of compound statement"); - statement->label.statement = create_empty_statement(); - } else { - errorf(HERE, "label at end of compound statement"); - statement->label.statement = create_invalid_statement(); - } - } else if (token.type == ';') { - /* Eat an empty statement here, to avoid the warning about an empty - * statement after a label. label:; is commonly used to have a label - * before a closing brace. */ - statement->label.statement = create_empty_statement(); - next_token(); - } else { - statement_t *const inner_stmt = parse_statement(); - statement->label.statement = inner_stmt; - if (inner_stmt->kind == STATEMENT_DECLARATION) { - errorf(&inner_stmt->base.source_position, "declaration after label"); - } - } + statement->label.statement = parse_label_inner_statement("label", true); /* remember the labels in a list for later checking */ *label_anchor = &statement->label; @@ -9549,8 +9534,7 @@ end_error: statement->ifs.true_statement = true_stmt; rem_anchor_token(T_else); - if (token.type == T_else) { - next_token(); + if (next_if(T_else)) { statement->ifs.false_statement = parse_statement(); } else if (warning.parentheses && true_stmt->kind == STATEMENT_IF && @@ -9753,13 +9737,11 @@ static statement_t *parse_for(void) scope_t *old_scope = scope_push(&statement->fors.scope); bool old_gcc_extension = in_gcc_extension; - while (token.type == T___extension__) { - next_token(); + while (next_if(T___extension__)) { in_gcc_extension = true; } - if (token.type == ';') { - next_token(); + if (next_if(';')) { } else if (is_declaration_specifier(&token, false)) { parse_declaration(record_entity, DECL_FLAGS_NONE); } else { @@ -9827,8 +9809,7 @@ static statement_t *parse_goto(void) statement_t *statement = allocate_statement_zero(STATEMENT_GOTO); eat(T_goto); - if (GNU_MODE && token.type == '*') { - next_token(); + if (GNU_MODE && next_if('*')) { expression_t *expression = parse_expression(); mark_vars_read(expression, NULL); @@ -9849,7 +9830,7 @@ static statement_t *parse_goto(void) statement->gotos.expression = expression; } else if (token.type == T_IDENTIFIER) { - symbol_t *symbol = token.v.symbol; + symbol_t *symbol = token.symbol; next_token(); statement->gotos.label = get_label(symbol); } else { @@ -9858,7 +9839,7 @@ static statement_t *parse_goto(void) else parse_error_expected("while parsing goto", T_IDENTIFIER, NULL); eat_until_anchor(); - goto end_error; + return create_invalid_statement(); } /* remember the goto's in a list for later checking */ @@ -9867,9 +9848,8 @@ static statement_t *parse_goto(void) expect(';', end_error); - return statement; end_error: - return create_invalid_statement(); + return statement; } /** @@ -10111,8 +10091,7 @@ static statement_t *parse_ms_try_statment(void) POP_PARENT; - if (token.type == T___except) { - eat(T___except); + if (next_if(T___except)) { expect('(', end_error); add_anchor_token(')'); expression_t *const expr = parse_expression(); @@ -10129,8 +10108,7 @@ static statement_t *parse_ms_try_statment(void) rem_anchor_token(')'); expect(')', end_error); statement->ms_try.final_statement = parse_compound_statement(false); - } else if (token.type == T__finally) { - eat(T___finally); + } else if (next_if(T__finally)) { statement->ms_try.final_statement = parse_compound_statement(false); } else { parse_error_expected("while parsing __try statement", T___except, T___finally, NULL); @@ -10157,15 +10135,16 @@ static statement_t *parse_local_label_declaration(void) eat(T___label__); - entity_t *begin = NULL, *end = NULL; - - while (true) { + entity_t *begin = NULL; + entity_t *end = NULL; + entity_t **anchor = &begin; + do { if (token.type != T_IDENTIFIER) { parse_error_expected("while parsing local label declaration", T_IDENTIFIER, NULL); goto end_error; } - symbol_t *symbol = token.v.symbol; + 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)", @@ -10178,21 +10157,15 @@ static statement_t *parse_local_label_declaration(void) entity->base.source_position = token.source_position; entity->base.symbol = symbol; - if (end != NULL) - end->base.next = entity; - end = entity; - if (begin == NULL) - begin = entity; + *anchor = entity; + anchor = &entity->base.next; + end = entity; environment_push(entity); } next_token(); - - if (token.type != ',') - break; - next_token(); - } - eat(';'); + } while (next_if(',')); + expect(';', end_error); end_error: statement->declaration.declarations_begin = begin; statement->declaration.declarations_end = end; @@ -10207,13 +10180,13 @@ static void parse_namespace_definition(void) symbol_t *symbol = NULL; if (token.type == T_IDENTIFIER) { - symbol = token.v.symbol; + symbol = token.symbol; next_token(); entity = get_entity(symbol, NAMESPACE_NORMAL); - if (entity != NULL && - entity->kind != ENTITY_NAMESPACE && - entity->base.parent_scope == current_scope) { + if (entity != NULL + && entity->kind != ENTITY_NAMESPACE + && entity->base.parent_scope == current_scope) { if (!is_error_entity(entity)) { error_redefined_as_different_kind(&token.source_position, entity, ENTITY_NAMESPACE); @@ -10241,12 +10214,17 @@ static void parse_namespace_definition(void) size_t const top = environment_top(); scope_t *old_scope = scope_push(&entity->namespacee.members); + entity_t *old_current_entity = current_entity; + current_entity = entity; + expect('{', end_error); parse_externals(); 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); } @@ -10267,7 +10245,7 @@ static statement_t *intern_parse_statement(void) token_type_t la1_type = (token_type_t)look_ahead(1)->type; if (la1_type == ':') { statement = parse_label_statement(); - } else if (is_typedef_symbol(token.v.symbol)) { + } else if (is_typedef_symbol(token.symbol)) { statement = parse_declaration_statement(); } else { /* it's an identifier, the grammar says this must be an @@ -10277,18 +10255,14 @@ static statement_t *intern_parse_statement(void) switch (la1_type) { case '&': case '*': - if (get_entity(token.v.symbol, NAMESPACE_NORMAL) != NULL) - goto expression_statment; - /* FALLTHROUGH */ - + if (get_entity(token.symbol, NAMESPACE_NORMAL) != NULL) { + default: + statement = parse_expression_statement(); + } else { DECLARATION_START case T_IDENTIFIER: - statement = parse_declaration_statement(); - break; - - default: -expression_statment: - statement = parse_expression_statement(); + statement = parse_declaration_statement(); + } break; } } @@ -10298,9 +10272,7 @@ expression_statment: 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. */ - do { - next_token(); - } while (token.type == T___extension__); + while (next_if(T___extension__)) {} bool old_gcc_extension = in_gcc_extension; in_gcc_extension = true; statement = intern_parse_statement(); @@ -10697,8 +10669,7 @@ static void parse_linkage_specification(void) } current_linkage = new_linkage; - if (token.type == '{') { - next_token(); + if (next_if('{')) { parse_externals(); expect('}', end_error); } else { @@ -10827,8 +10798,7 @@ void start_parsing(void) error_count = 0; warning_count = 0; - type_set_output(stderr); - ast_set_output(stderr); + print_to_file(stderr); assert(unit == NULL); unit = allocate_ast_zero(sizeof(unit[0])); @@ -10891,6 +10861,36 @@ static void complete_incomplete_arrays(void) } } +void prepare_main_collect2(entity_t *entity) +{ + // create call to __main + symbol_t *symbol = symbol_table_insert("__main"); + entity_t *subsubmain_ent + = create_implicit_function(symbol, &builtin_source_position); + + expression_t *ref = allocate_expression_zero(EXPR_REFERENCE); + type_t *ftype = subsubmain_ent->declaration.type; + ref->base.source_position = builtin_source_position; + ref->base.type = make_pointer_type(ftype, TYPE_QUALIFIER_NONE); + ref->reference.entity = subsubmain_ent; + + expression_t *call = allocate_expression_zero(EXPR_CALL); + call->base.source_position = builtin_source_position; + call->base.type = type_void; + call->call.function = ref; + + statement_t *expr_statement = allocate_statement_zero(STATEMENT_EXPRESSION); + expr_statement->base.source_position = builtin_source_position; + expr_statement->expression.expression = call; + + statement_t *statement = entity->function.statement; + assert(statement->kind == STATEMENT_COMPOUND); + compound_statement_t *compounds = &statement->compound; + + expr_statement->base.next = compounds->statements; + compounds->statements = expr_statement; +} + void parse(void) { lookahead_bufpos = 0; @@ -10905,104 +10905,6 @@ void parse(void) incomplete_arrays = NULL; } -/** - * create a builtin function. - */ -static entity_t *create_builtin_function(builtin_kind_t kind, const char *name, type_t *function_type) -{ - symbol_t *symbol = symbol_table_insert(name); - entity_t *entity = allocate_entity_zero(ENTITY_FUNCTION); - entity->declaration.storage_class = STORAGE_CLASS_EXTERN; - entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN; - entity->declaration.type = function_type; - entity->declaration.implicit = true; - entity->base.symbol = symbol; - entity->base.source_position = builtin_source_position; - - entity->function.btk = kind; - - record_entity(entity, /*is_definition=*/false); - return entity; -} - - -/** - * Create predefined gnu builtins. - */ -static void create_gnu_builtins(void) -{ -#define GNU_BUILTIN(a, b) create_builtin_function(bk_gnu_builtin_##a, "__builtin_" #a, b) - - GNU_BUILTIN(alloca, make_function_1_type(type_void_ptr, type_size_t)); - GNU_BUILTIN(huge_val, make_function_0_type(type_double)); - GNU_BUILTIN(inf, make_function_0_type(type_double)); - GNU_BUILTIN(inff, make_function_0_type(type_float)); - GNU_BUILTIN(infl, make_function_0_type(type_long_double)); - GNU_BUILTIN(nan, make_function_1_type(type_double, type_char_ptr)); - GNU_BUILTIN(nanf, make_function_1_type(type_float, type_char_ptr)); - GNU_BUILTIN(nanl, make_function_1_type(type_long_double, type_char_ptr)); - GNU_BUILTIN(va_end, make_function_1_type(type_void, type_valist)); - GNU_BUILTIN(expect, make_function_2_type(type_long, type_long, type_long)); - GNU_BUILTIN(return_address, make_function_1_type(type_void_ptr, type_unsigned_int)); - GNU_BUILTIN(frame_address, make_function_1_type(type_void_ptr, type_unsigned_int)); - GNU_BUILTIN(ffs, make_function_1_type(type_int, type_unsigned_int)); - GNU_BUILTIN(clz, make_function_1_type(type_int, type_unsigned_int)); - GNU_BUILTIN(ctz, make_function_1_type(type_int, type_unsigned_int)); - GNU_BUILTIN(popcount, make_function_1_type(type_int, type_unsigned_int)); - GNU_BUILTIN(parity, make_function_1_type(type_int, type_unsigned_int)); - GNU_BUILTIN(prefetch, make_function_1_type_variadic(type_float, type_void_ptr)); - GNU_BUILTIN(trap, make_function_0_type_noreturn(type_void)); - -#undef GNU_BUILTIN -} - -/** - * Create predefined MS intrinsics. - */ -static void create_microsoft_intrinsics(void) -{ -#define MS_BUILTIN(a, b) create_builtin_function(bk_ms##a, #a, b) - - /* intrinsics for all architectures */ - MS_BUILTIN(_rotl, make_function_2_type(type_unsigned_int, type_unsigned_int, type_int)); - MS_BUILTIN(_rotr, make_function_2_type(type_unsigned_int, type_unsigned_int, type_int)); - MS_BUILTIN(_rotl64, make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int)); - MS_BUILTIN(_rotr64, make_function_2_type(type_unsigned_int64, type_unsigned_int64, type_int)); - MS_BUILTIN(_byteswap_ushort, make_function_1_type(type_unsigned_short, type_unsigned_short)); - MS_BUILTIN(_byteswap_ulong, make_function_1_type(type_unsigned_long, type_unsigned_long)); - MS_BUILTIN(_byteswap_uint64, make_function_1_type(type_unsigned_int64, type_unsigned_int64)); - - MS_BUILTIN(__debugbreak, make_function_0_type(type_void)); - MS_BUILTIN(_ReturnAddress, make_function_0_type(type_void_ptr)); - MS_BUILTIN(_AddressOfReturnAddress, make_function_0_type(type_void_ptr)); - MS_BUILTIN(__popcount, make_function_1_type(type_unsigned_int, type_unsigned_int)); - - /* x86/x64 only */ - MS_BUILTIN(_enable, make_function_0_type(type_void)); - MS_BUILTIN(_disable, make_function_0_type(type_void)); - MS_BUILTIN(__inbyte, make_function_1_type(type_unsigned_char, type_unsigned_short)); - MS_BUILTIN(__inword, make_function_1_type(type_unsigned_short, type_unsigned_short)); - MS_BUILTIN(__indword, make_function_1_type(type_unsigned_long, type_unsigned_short)); - MS_BUILTIN(__outbyte, make_function_2_type(type_void, type_unsigned_short, type_unsigned_char)); - MS_BUILTIN(__outword, make_function_2_type(type_void, type_unsigned_short, type_unsigned_short)); - MS_BUILTIN(__outdword, make_function_2_type(type_void, type_unsigned_short, type_unsigned_long)); - MS_BUILTIN(__ud2, make_function_0_type_noreturn(type_void)); - MS_BUILTIN(_BitScanForward, make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long)); - MS_BUILTIN(_BitScanReverse, make_function_2_type(type_unsigned_char, type_unsigned_long_ptr, type_unsigned_long)); - MS_BUILTIN(_InterlockedExchange, make_function_2_type(type_long, type_long_ptr, type_long)); - MS_BUILTIN(_InterlockedExchange64, make_function_2_type(type_int64, type_int64_ptr, type_int64)); - - if (machine_size <= 32) { - MS_BUILTIN(__readeflags, make_function_0_type(type_unsigned_int)); - MS_BUILTIN(__writeeflags, make_function_1_type(type_void, type_unsigned_int)); - } else { - MS_BUILTIN(__readeflags, make_function_0_type(type_unsigned_int64)); - MS_BUILTIN(__writeeflags, make_function_1_type(type_void, type_unsigned_int64)); - } - -#undef MS_BUILTIN -} - /** * Initialize the parser. */