X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;ds=inline;f=parser.c;h=b637dd25e556220b5ed97be847590d566012c401;hb=779610287a11b207e958e31a29f0dd9ea5459e39;hp=2671b108aeba87f41c3ffa63fd99639997b0fd3e;hpb=0a880c90fd6d1ec23c4ec1956f3b92694ec0a139;p=cparser diff --git a/parser.c b/parser.c index 2671b10..b637dd2 100644 --- a/parser.c +++ b/parser.c @@ -1,46 +1,33 @@ /* * This file is part of cparser. - * 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 - * as published by the Free Software Foundation; either version 2 - * of the License, or (at your option) any later version. - * - * This program is distributed in the hope that it will be useful, - * but WITHOUT ANY WARRANTY; without even the implied warranty of - * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the - * GNU General Public License for more details. - * - * You should have received a copy of the GNU General Public License - * along with this program; if not, write to the Free Software - * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA - * 02111-1307, USA. + * Copyright (C) 2012 Matthias Braun */ #include #include +#include #include #include #include "adt/strutil.h" +#include "adt/util.h" #include "parser.h" #include "diagnostic.h" #include "format_check.h" -#include "lexer.h" +#include "preprocessor.h" #include "symbol_t.h" +#include "symbol_table.h" #include "token_t.h" #include "types.h" #include "type_t.h" #include "type_hash.h" #include "ast_t.h" -#include "entity_t.h" #include "attribute_t.h" #include "lang_features.h" #include "walk.h" #include "warning.h" #include "printer.h" -#include "adt/bitfiddle.h" +#include "ast2firm.h" #include "adt/error.h" #include "adt/array.h" @@ -55,13 +42,12 @@ typedef struct { typedef struct declaration_specifiers_t declaration_specifiers_t; struct declaration_specifiers_t { - source_position_t source_position; - storage_class_t storage_class; - unsigned char alignment; /**< Alignment, 0 if not set. */ - bool is_inline : 1; - bool thread_local : 1; /**< GCC __thread */ - attribute_t *attributes; /**< list of attributes */ - type_t *type; + position_t pos; + storage_class_t storage_class; + bool is_inline : 1; + bool thread_local : 1; + attribute_t *attributes; /**< list of attributes */ + type_t *type; }; /** @@ -131,21 +117,18 @@ static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT; #define PUSH_EXTENSION() \ (void)0; \ bool const old_gcc_extension = in_gcc_extension; \ - while (next_if(T___extension__)) { \ + while (accept(T___extension__)) { \ in_gcc_extension = true; \ } \ do {} while (0) #define POP_EXTENSION() \ ((void)(in_gcc_extension = old_gcc_extension)) -/** special symbol used for anonymous entities. */ -static symbol_t *sym_anonymous = NULL; - /** The token anchor set */ static unsigned short token_anchor_set[T_LAST_TOKEN]; /** The current source position. */ -#define HERE (&token.base.source_position) +#define HERE (&token.base.pos) /** true if we are in GCC mode. */ #define GNU_MODE ((c_mode & _GNUC) || in_gcc_extension) @@ -174,7 +157,8 @@ typedef enum declarator_flags_t { static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, declarator_flags_t flags); -static void semantic_comparison(binary_expression_t *expression); +static void semantic_comparison(binary_expression_t *expression, + bool is_relational); #define STORAGE_CLASSES \ STORAGE_CLASSES_NO_EXTERN \ @@ -185,7 +169,7 @@ static void semantic_comparison(binary_expression_t *expression); case T_static: \ case T_auto: \ case T_register: \ - case T___thread: + case T__Thread_local: #define TYPE_QUALIFIERS \ case T_const: \ @@ -247,15 +231,14 @@ static void semantic_comparison(binary_expression_t *expression); case '~': \ case T_ANDAND: \ case T_CHARACTER_CONSTANT: \ - case T_FLOATINGPOINT: \ - case T_INTEGER: \ + case T_NUMBER: \ case T_MINUSMINUS: \ case T_PLUSPLUS: \ case T_STRING_LITERAL: \ + case T__Alignof: \ case T___FUNCDNAME__: \ case T___FUNCSIG__: \ case T___PRETTY_FUNCTION__: \ - case T___alignof__: \ case T___builtin_classify_type: \ case T___builtin_constant_p: \ case T___builtin_isgreater: \ @@ -275,7 +258,9 @@ static void semantic_comparison(binary_expression_t *expression); case T_false: \ case T_sizeof: \ case T_throw: \ - case T_true: + case T_true: \ + case T___imag__: \ + case T___real__: /** * Returns the size of a statement node. @@ -299,7 +284,6 @@ static size_t get_statement_struct_size(statement_kind_t kind) [STATEMENT_GOTO] = sizeof(goto_statement_t), [STATEMENT_LABEL] = sizeof(label_statement_t), [STATEMENT_CASE_LABEL] = sizeof(case_label_statement_t), - [STATEMENT_WHILE] = sizeof(while_statement_t), [STATEMENT_DO_WHILE] = sizeof(do_while_statement_t), [STATEMENT_FOR] = sizeof(for_statement_t), [STATEMENT_ASM] = sizeof(asm_statement_t), @@ -326,6 +310,7 @@ static size_t get_expression_struct_size(expression_kind_t kind) [EXPR_LITERAL_INTEGER] = sizeof(literal_expression_t), [EXPR_LITERAL_FLOATINGPOINT] = sizeof(literal_expression_t), [EXPR_LITERAL_CHARACTER] = sizeof(string_literal_expression_t), + [EXPR_LITERAL_MS_NOOP] = sizeof(literal_expression_t), [EXPR_STRING_LITERAL] = sizeof(string_literal_expression_t), [EXPR_COMPOUND_LITERAL] = sizeof(compound_literal_expression_t), [EXPR_CALL] = sizeof(call_expression_t), @@ -368,9 +353,9 @@ static statement_t *allocate_statement_zero(statement_kind_t kind) size_t size = get_statement_struct_size(kind); statement_t *res = allocate_ast_zero(size); - res->base.kind = kind; - res->base.parent = current_parent; - res->base.source_position = *HERE; + res->base.kind = kind; + res->base.parent = current_parent; + res->base.pos = *HERE; return res; } @@ -385,9 +370,9 @@ static expression_t *allocate_expression_zero(expression_kind_t kind) size_t size = get_expression_struct_size(kind); expression_t *res = allocate_ast_zero(size); - res->base.kind = kind; - res->base.type = type_error_type; - res->base.source_position = *HERE; + res->base.kind = kind; + res->base.type = type_error_type; + res->base.pos = *HERE; return res; } @@ -427,8 +412,7 @@ static size_t get_initializer_size(initializer_kind_t kind) { static const size_t sizes[] = { [INITIALIZER_VALUE] = sizeof(initializer_value_t), - [INITIALIZER_STRING] = sizeof(initializer_string_t), - [INITIALIZER_WIDE_STRING] = sizeof(initializer_wide_string_t), + [INITIALIZER_STRING] = sizeof(initializer_value_t), [INITIALIZER_LIST] = sizeof(initializer_list_t), [INITIALIZER_DESIGNATOR] = sizeof(initializer_designator_t) }; @@ -471,8 +455,8 @@ static size_t label_top(void) static inline void next_token(void) { token = lookahead_buffer[lookahead_bufpos]; - lookahead_buffer[lookahead_bufpos] = lexer_token; - lexer_next_token(); + lookahead_buffer[lookahead_bufpos] = pp_token; + next_preprocessing_token(); lookahead_bufpos = (lookahead_bufpos + 1) % MAX_LOOKAHEAD; @@ -482,12 +466,23 @@ static inline void next_token(void) #endif } -#define eat(token_kind) (assert(token.kind == (token_kind)), next_token()) +static inline void eat(token_kind_t const kind) +{ + assert(token.kind == kind); + (void)kind; + next_token(); +} -static inline bool next_if(token_kind_t const type) +/** + * Consume the current token, if it is of the expected kind. + * + * @param kind The kind of token to consume. + * @return Whether the token was consumed. + */ +static inline bool accept(token_kind_t const kind) { - if (token.kind == type) { - eat(type); + if (token.kind == kind) { + eat(kind); return true; } else { return false; @@ -595,7 +590,7 @@ static void eat_until_anchor(void) static void eat_block(void) { eat_until_matching_token('{'); - next_if('}'); + accept('}'); } /** @@ -620,10 +615,9 @@ void parse_error_expected(const char *message, ...) * Report an incompatible type. */ static void type_error_incompatible(const char *msg, - const source_position_t *source_position, type_t *type1, type_t *type2) + const position_t *pos, type_t *type1, type_t *type2) { - errorf(source_position, "%s, incompatible types: '%T' - '%T'", - msg, type1, type2); + errorf(pos, "%s, incompatible types: '%T' - '%T'", msg, type1, type2); } static bool skip_till(token_kind_t const expected, char const *const context) @@ -649,7 +643,8 @@ static void expect(token_kind_t const expected) eat(expected); } -static symbol_t *expect_identifier(char const *const context, source_position_t *const pos) +static symbol_t *expect_identifier(char const *const context, + position_t *const pos) { if (!skip_till(T_IDENTIFIER, context)) return NULL; @@ -707,7 +702,7 @@ static entity_t *get_tag(symbol_t const *const symbol, if (entity != NULL && (entity_kind_tag_t)entity->kind != kind) { errorf(HERE, "'%Y' defined as wrong kind of tag (previous definition %P)", - symbol, &entity->base.source_position); + symbol, &entity->base.pos); entity = NULL; } return entity; @@ -752,7 +747,7 @@ static void stack_push(stack_entry_t **stack_ptr, entity_t *entity) */ static void environment_push(entity_t *entity) { - assert(entity->base.source_position.input_name != NULL); + assert(entity->base.pos.input_name != NULL); assert(entity->base.parent_scope != NULL); stack_push(&environment_stack, entity); } @@ -835,13 +830,6 @@ static void label_pop_to(size_t new_top) stack_pop_to(&label_stack, new_top); } -static atomic_type_kind_t get_akind(const type_t *type) -{ - assert(type->kind == TYPE_ATOMIC || type->kind == TYPE_COMPLEX - || type->kind == TYPE_IMAGINARY || type->kind == TYPE_ENUM); - return type->atomic.akind; -} - /** * §6.3.1.1:2 Do integer promotion for a given type. * @@ -850,7 +838,8 @@ static atomic_type_kind_t get_akind(const type_t *type) */ static type_t *promote_integer(type_t *type) { - if (get_akind_rank(get_akind(type)) < get_akind_rank(ATOMIC_TYPE_INT)) + atomic_type_kind_t akind = get_arithmetic_akind(type); + if (get_akind_rank(akind) < get_akind_rank(ATOMIC_TYPE_INT)) type = type_int; return type; @@ -866,18 +855,17 @@ static bool is_null_pointer_constant(const expression_t *expression) /* skip void* cast */ if (expression->kind == EXPR_UNARY_CAST) { type_t *const type = skip_typeref(expression->base.type); - if (types_compatible(type, type_void_ptr)) + if (type == type_void_ptr) expression = expression->unary.value; } - type_t *const type = skip_typeref(expression->base.type); - 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; + case EXPR_CLASS_VARIABLE: return false; + case EXPR_CLASS_ERROR: return true; + case EXPR_CLASS_CONSTANT: return false; + case EXPR_CLASS_INTEGER_CONSTANT: return !fold_constant_to_bool(expression); } + panic("invalid expression classification"); } /** @@ -889,9 +877,8 @@ static bool is_null_pointer_constant(const expression_t *expression) static expression_t *create_implicit_cast(expression_t *expression, type_t *dest_type) { - type_t *const source_type = expression->base.type; - - if (source_type == dest_type) + type_t *const source_type = skip_typeref(expression->base.type); + if (source_type == skip_typeref(dest_type)) return expression; expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST); @@ -911,7 +898,7 @@ typedef enum assign_error_t { ASSIGN_WARNING_INT_FROM_POINTER } assign_error_t; -static void report_assign_error(assign_error_t error, type_t *orig_type_left, expression_t const *const right, char const *const context, source_position_t const *const pos) +static void report_assign_error(assign_error_t error, type_t *orig_type_left, expression_t const *const right, char const *const context, position_t const *const pos) { type_t *const orig_type_right = right->base.type; type_t *const type_left = skip_typeref(orig_type_left); @@ -1020,8 +1007,7 @@ static expression_t *parse_constant_expression(void) expression_t *result = parse_subexpression(PREC_CONDITIONAL); if (is_constant_expression(result) == EXPR_CLASS_VARIABLE) { - errorf(&result->base.source_position, - "expression '%E' is not constant", result); + errorf(&result->base.pos, "expression '%E' is not constant", result); } return result; @@ -1039,52 +1025,55 @@ static void append_string(string_t const *const s) obstack_grow(&ast_obstack, s->begin, s->size); } -static string_t finish_string(void) +static string_t finish_string(string_encoding_t const enc) { obstack_1grow(&ast_obstack, '\0'); size_t const size = obstack_object_size(&ast_obstack) - 1; char const *const string = obstack_finish(&ast_obstack); - return (string_t){ string, size }; + return (string_t){ string, size, enc }; } -static string_t concat_string_literals(string_encoding_t *const out_enc) +static string_t concat_string_literals(void) { assert(token.kind == T_STRING_LITERAL); - string_t result; - string_encoding_t enc = token.string.encoding; + string_t result; if (look_ahead(1)->kind == T_STRING_LITERAL) { - append_string(&token.string.string); + append_string(&token.literal.string); eat(T_STRING_LITERAL); warningf(WARN_TRADITIONAL, HERE, "traditional C rejects string constant concatenation"); + string_encoding_t enc = token.literal.string.encoding; do { - if (token.string.encoding != STRING_ENCODING_CHAR) { - enc = token.string.encoding; + string_encoding_t const new_enc = token.literal.string.encoding; + if (new_enc != enc && new_enc != STRING_ENCODING_CHAR) { + if (enc == STRING_ENCODING_CHAR) { + enc = new_enc; + } else { + errorf(HERE, "concatenating string literals with encodings %s and %s", get_string_encoding_prefix(enc), get_string_encoding_prefix(new_enc)); + } } - append_string(&token.string.string); + append_string(&token.literal.string); eat(T_STRING_LITERAL); } while (token.kind == T_STRING_LITERAL); - result = finish_string(); + result = finish_string(enc); } else { - result = token.string.string; + result = token.literal.string; eat(T_STRING_LITERAL); } - *out_enc = enc; return result; } static string_t parse_string_literals(char const *const context) { if (!skip_till(T_STRING_LITERAL, context)) - return (string_t){ "", 0 }; + return (string_t){ "", 0, STRING_ENCODING_CHAR }; - string_encoding_t enc; - source_position_t const pos = *HERE; - string_t const res = concat_string_literals(&enc); + position_t const pos = *HERE; + string_t const res = concat_string_literals(); - if (enc != STRING_ENCODING_CHAR) { - errorf(&pos, "expected plain string literal, got wide string literal"); + if (res.encoding != STRING_ENCODING_CHAR) { + errorf(&pos, "expected plain string literal, got %s string literal", get_string_encoding_prefix(res.encoding)); } return res; @@ -1093,8 +1082,8 @@ static string_t parse_string_literals(char const *const context) static attribute_t *allocate_attribute_zero(attribute_kind_t kind) { attribute_t *attribute = allocate_ast_zero(sizeof(*attribute)); - attribute->kind = kind; - attribute->source_position = *HERE; + attribute->kind = kind; + attribute->pos = *HERE; return attribute; } @@ -1150,7 +1139,7 @@ static attribute_argument_t *parse_attribute_arguments(void) /* append argument */ *anchor = argument; anchor = &argument->next; - } while (next_if(',')); + } while (accept(',')); expect(')'); return first; } @@ -1177,6 +1166,12 @@ static attribute_t *parse_attribute_gnu_single(void) char const *const name = symbol->string; for (kind = ATTRIBUTE_GNU_FIRST;; ++kind) { if (kind > ATTRIBUTE_GNU_LAST) { + /* special case for "__const" */ + if (token.kind == T_const) { + kind = ATTRIBUTE_GNU_CONST; + break; + } + warningf(WARN_ATTRIBUTE, HERE, "unknown attribute '%s' ignored", name); /* TODO: we should still save the attribute in the list... */ kind = ATTRIBUTE_UNKNOWN; @@ -1192,7 +1187,7 @@ static attribute_t *parse_attribute_gnu_single(void) next_token(); /* parse arguments */ - if (next_if('(')) + if (accept('(')) attribute->a.arguments = parse_attribute_arguments(); return attribute; @@ -1215,7 +1210,7 @@ static attribute_t *parse_attribute_gnu(void) *anchor = attribute; anchor = &attribute->next; } - } while (next_if(',')); + } while (accept(',')); rem_anchor_token(','); rem_anchor_token(')'); @@ -1424,7 +1419,7 @@ static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent) case EXPR_UNARY_NEGATE: case EXPR_UNARY_PLUS: - case EXPR_UNARY_BITWISE_NEGATE: + case EXPR_UNARY_COMPLEMENT: case EXPR_UNARY_NOT: case EXPR_UNARY_TAKE_ADDRESS: case EXPR_UNARY_POSTFIX_INCREMENT: @@ -1432,6 +1427,8 @@ static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent) case EXPR_UNARY_PREFIX_INCREMENT: case EXPR_UNARY_PREFIX_DECREMENT: case EXPR_UNARY_ASSUME: + case EXPR_UNARY_IMAG: + case EXPR_UNARY_REAL: unary: mark_vars_read(expr->unary.value, lhs_ent); return; @@ -1517,17 +1514,23 @@ static designator_t *parse_designation(void) designator_t *designator; switch (token.kind) { case '[': - designator = allocate_ast_zero(sizeof(designator[0])); - designator->source_position = *HERE; + designator = allocate_ast_zero(sizeof(designator[0])); + designator->pos = *HERE; eat('['); add_anchor_token(']'); + add_anchor_token(T_DOTDOTDOT); designator->array_index = parse_constant_expression(); + if (accept(T_DOTDOTDOT)) { + designator->range_last = parse_constant_expression(); + errorf(&designator->pos, "range initializer not supported"); + } + rem_anchor_token(T_DOTDOTDOT); rem_anchor_token(']'); expect(']'); break; case '.': - designator = allocate_ast_zero(sizeof(designator[0])); - designator->source_position = *HERE; + designator = allocate_ast_zero(sizeof(designator[0])); + designator->pos = *HERE; eat('.'); designator->symbol = expect_identifier("while parsing designator", NULL); if (!designator->symbol) @@ -1544,31 +1547,6 @@ static designator_t *parse_designation(void) } } -static initializer_t *initializer_from_string(array_type_t *const type, - const string_t *const string) -{ - /* TODO: check len vs. size of array type */ - (void) type; - - initializer_t *initializer = allocate_initializer_zero(INITIALIZER_STRING); - initializer->string.string = *string; - - return initializer; -} - -static initializer_t *initializer_from_wide_string(array_type_t *const type, - const string_t *const string) -{ - /* TODO: check len vs. size of array type */ - (void) type; - - initializer_t *const initializer = - allocate_initializer_zero(INITIALIZER_WIDE_STRING); - initializer->wide_string.string = *string; - - return initializer; -} - /** * Build an initializer from a given expression. */ @@ -1577,37 +1555,36 @@ static initializer_t *initializer_from_expression(type_t *orig_type, { /* TODO check that expression is a constant expression */ - /* §6.7.8.14/15 char array may be initialized by string literals */ - type_t *type = skip_typeref(orig_type); - type_t *expr_type_orig = expression->base.type; - type_t *expr_type = skip_typeref(expr_type_orig); + type_t *const type = skip_typeref(orig_type); - if (is_type_array(type) && expr_type->kind == TYPE_POINTER) { + /* §6.7.8.14/15 char array may be initialized by string literals */ + if (expression->kind == EXPR_STRING_LITERAL && is_type_array(type)) { array_type_t *const array_type = &type->array; type_t *const element_type = skip_typeref(array_type->element_type); - - if (element_type->kind == TYPE_ATOMIC && expression->kind == EXPR_STRING_LITERAL) { - switch (expression->string_literal.encoding) { - case STRING_ENCODING_CHAR: { - atomic_type_kind_t const akind = element_type->atomic.akind; - if (akind == ATOMIC_TYPE_CHAR - || akind == ATOMIC_TYPE_SCHAR - || akind == ATOMIC_TYPE_UCHAR) { - return initializer_from_string(array_type, - &expression->string_literal.value); - } - break; + switch (expression->string_literal.value.encoding) { + case STRING_ENCODING_CHAR: + case STRING_ENCODING_UTF8: { + if (is_type_atomic(element_type, ATOMIC_TYPE_CHAR) || + is_type_atomic(element_type, ATOMIC_TYPE_SCHAR) || + is_type_atomic(element_type, ATOMIC_TYPE_UCHAR)) { + goto make_string_init; } + break; + } - case STRING_ENCODING_WIDE: { - 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; - } + case STRING_ENCODING_CHAR16: + case STRING_ENCODING_CHAR32: + case STRING_ENCODING_WIDE: { + assert(is_type_pointer(expression->base.type)); + type_t *const init_type = get_unqualified_type(expression->base.type->pointer.points_to); + if (types_compatible(get_unqualified_type(element_type), init_type)) { +make_string_init:; + initializer_t *const init = allocate_initializer_zero(INITIALIZER_STRING); + init->value.value = expression; + return init; } + break; + } } } @@ -1615,7 +1592,7 @@ static initializer_t *initializer_from_expression(type_t *orig_type, if (error == ASSIGN_ERROR_INCOMPATIBLE) return NULL; report_assign_error(error, type, expression, "initializer", - &expression->base.source_position); + &expression->base.pos); initializer_t *const result = allocate_initializer_zero(INITIALIZER_VALUE); result->value.value = create_implicit_cast(expression, type); @@ -1644,7 +1621,7 @@ static initializer_t *parse_scalar_initializer(type_t *type, expression_t *expression = parse_assignment_expression(); mark_vars_read(expression, NULL); if (must_be_constant && !is_linker_constant(expression)) { - errorf(&expression->base.source_position, + errorf(&expression->base.pos, "initialisation expression '%E' is not constant", expression); } @@ -1652,7 +1629,7 @@ static initializer_t *parse_scalar_initializer(type_t *type, initializer_t *initializer = initializer_from_expression(type, expression); if (initializer == NULL) { - errorf(&expression->base.source_position, + errorf(&expression->base.pos, "expression '%E' (type '%T') doesn't match expected type '%T'", expression, expression->base.type, type); /* TODO */ @@ -1661,7 +1638,7 @@ static initializer_t *parse_scalar_initializer(type_t *type, bool additional_warning_displayed = false; while (braces > 0) { - next_if(','); + accept(','); if (token.kind != '}') { if (!additional_warning_displayed) { warningf(WARN_OTHER, HERE, "additional elements in scalar initializer"); @@ -1731,7 +1708,7 @@ static __attribute__((unused)) void debug_print_type_path( } /** - * Return the top type path entry, ie. in a path + * Return the top type path entry, i.e. in a path * (type).a.b returns the b. */ static type_path_entry_t *get_type_path_top(const type_path_t *path) @@ -1784,7 +1761,7 @@ static void descend_into_subtype(type_path_t *path) } /** - * Pop an entry from the given type path, ie. returning from + * Pop an entry from the given type path, i.e. returning from * (type).a.b to (type).a */ static void ascend_from_subtype(type_path_t *path) @@ -1824,7 +1801,7 @@ static bool walk_designator(type_path_t *path, const designator_t *designator, symbol_t *symbol = designator->symbol; if (!is_type_compound(type)) { if (is_type_valid(type)) { - errorf(&designator->source_position, + errorf(&designator->pos, "'.%Y' designator used for non-compound type '%T'", symbol, orig_type); } @@ -1841,13 +1818,13 @@ static bool walk_designator(type_path_t *path, const designator_t *designator, } } if (iter == NULL) { - errorf(&designator->source_position, + errorf(&designator->pos, "'%T' has no member named '%Y'", orig_type, symbol); return false; } assert(iter->kind == ENTITY_COMPOUND_MEMBER); if (used_in_offsetof && iter->compound_member.bitfield) { - errorf(&designator->source_position, + errorf(&designator->pos, "offsetof designator '%Y' must not specify bitfield", symbol); return false; @@ -1859,12 +1836,12 @@ static bool walk_designator(type_path_t *path, const designator_t *designator, } } else { expression_t *array_index = designator->array_index; - if (is_constant_expression(array_index) != EXPR_CLASS_CONSTANT) + if (is_constant_expression(array_index) < EXPR_CLASS_CONSTANT) return true; if (!is_type_array(type)) { if (is_type_valid(type)) { - errorf(&designator->source_position, + errorf(&designator->pos, "[%E] designator used for non-array type '%T'", array_index, orig_type); } @@ -1874,12 +1851,12 @@ static bool walk_designator(type_path_t *path, const designator_t *designator, long index = fold_constant_to_int(array_index); if (!used_in_offsetof) { if (index < 0) { - errorf(&designator->source_position, + errorf(&designator->pos, "array index [%E] must be positive", array_index); } else if (type->array.size_constant) { long array_size = type->array.size; if (index >= array_size) { - errorf(&designator->source_position, + errorf(&designator->pos, "designator [%E] (%d) exceeds array size %d", array_index, index, array_size); } @@ -1953,7 +1930,7 @@ static void advance_current_object(type_path_t *path, size_t top_path_level) */ static void skip_initializers(void) { - next_if('{'); + accept('{'); while (token.kind != '}') { if (token.kind == T_EOF) @@ -1985,6 +1962,8 @@ static initializer_t *parse_sub_initializer(type_path_t *path, return create_empty_initializer(); } + initializer_t *result = NULL; + type_t *orig_type = path->top_type; type_t *type = NULL; @@ -2003,9 +1982,9 @@ static initializer_t *parse_sub_initializer(type_path_t *path, goto finish_designator; } else if (token.kind == T_IDENTIFIER && look_ahead(1)->kind == ':') { /* GNU-style designator ("identifier: value") */ - designator = allocate_ast_zero(sizeof(designator[0])); - designator->source_position = *HERE; - designator->symbol = token.base.symbol; + designator = allocate_ast_zero(sizeof(designator[0])); + designator->pos = *HERE; + designator->symbol = token.base.symbol; eat(T_IDENTIFIER); eat(':'); @@ -2062,7 +2041,7 @@ finish_designator: mark_vars_read(expression, NULL); if (env->must_be_constant && !is_linker_constant(expression)) { - errorf(&expression->base.source_position, + errorf(&expression->base.pos, "Initialisation expression '%E' is not constant", expression); } @@ -2077,7 +2056,7 @@ finish_designator: goto error_parse_next; } - source_position_t const* const pos = &expression->base.source_position; + position_t const* const pos = &expression->base.pos; if (env->entity != NULL) { warningf(WARN_OTHER, pos, "excess elements in initializer for '%N'", env->entity); } else { @@ -2088,14 +2067,14 @@ finish_designator: /* handle { "string" } special case */ if (expression->kind == EXPR_STRING_LITERAL && outer_type != NULL) { - sub = initializer_from_expression(outer_type, expression); - if (sub != NULL) { - next_if(','); + result = initializer_from_expression(outer_type, expression); + if (result != NULL) { + accept(','); if (token.kind != '}') { - warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", orig_type); + warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", outer_type); } /* TODO: eat , ... */ - return sub; + goto out; } } @@ -2112,7 +2091,7 @@ finish_designator: goto end_error; } if (is_type_scalar(type)) { - errorf(&expression->base.source_position, + errorf(&expression->base.pos, "expression '%E' doesn't match expected type '%T'", expression, orig_type); goto end_error; @@ -2127,21 +2106,15 @@ finish_designator: type_t *first_type = first->type; first_type = skip_typeref(first_type); if (is_type_array(first_type)) { - size_t index = first->v.index; - if (index > path->max_index) - path->max_index = index; + path->max_index = MAX(path->max_index, first->v.index); } /* append to initializers list */ ARR_APP1(initializer_t*, initializers, sub); error_parse_next: - if (token.kind == '}') { + if (!accept(',')) break; - } - add_anchor_token('}'); - expect(','); - rem_anchor_token('}'); if (token.kind == '}') { break; } @@ -2159,22 +2132,19 @@ error_parse_next: size_t len = ARR_LEN(initializers); size_t size = sizeof(initializer_list_t) + len * sizeof(initializers[0]); - initializer_t *result = allocate_ast_zero(size); - result->kind = INITIALIZER_LIST; - result->list.len = len; + result = allocate_ast_zero(size); + result->kind = INITIALIZER_LIST; + result->list.len = len; memcpy(&result->list.initializers, initializers, len * sizeof(initializers[0])); - - DEL_ARR_F(initializers); - ascend_to(path, top_path_level+1); - - return result; + goto out; end_error: skip_initializers(); +out: DEL_ARR_F(initializers); ascend_to(path, top_path_level+1); - return NULL; + return result; } static expression_t *make_size_literal(size_t value) @@ -2236,13 +2206,10 @@ static initializer_t *parse_initializer(parse_initializer_env_t *env) size = max_index + 1; break; - case INITIALIZER_STRING: - size = result->string.string.size + 1; - break; - - case INITIALIZER_WIDE_STRING: - size = result->wide_string.string.size; + case INITIALIZER_STRING: { + size = get_string_len(&get_init_string(result)->value) + 1; break; + } case INITIALIZER_DESIGNATOR: case INITIALIZER_VALUE: @@ -2280,7 +2247,7 @@ static void append_entity(scope_t *scope, entity_t *entity) static compound_t *parse_compound_type_specifier(bool is_struct) { - source_position_t const pos = *HERE; + position_t const pos = *HERE; eat(is_struct ? T_struct : T_union); symbol_t *symbol = NULL; @@ -2305,7 +2272,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct) * existing definition in outer scope */ entity = NULL; } else if (entity->compound.complete && token.kind == '{') { - source_position_t const *const ppos = &entity->base.source_position; + position_t const *const ppos = &entity->base.pos; errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos); /* clear members in the hope to avoid further errors */ entity->compound.members.entities = NULL; @@ -2341,6 +2308,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct) } if (attributes != NULL) { + entity->compound.attributes = attributes; handle_entity_attributes(attributes, entity); } @@ -2361,13 +2329,13 @@ static void parse_enum_entries(type_t *const enum_type) add_anchor_token(','); do { add_anchor_token('='); - source_position_t pos; + position_t pos; symbol_t *const symbol = expect_identifier("while parsing enum entry", &pos); entity_t *const entity = allocate_entity_zero(ENTITY_ENUM_VALUE, NAMESPACE_NORMAL, symbol, &pos); entity->enum_value.enum_type = enum_type; rem_anchor_token('='); - if (next_if('=')) { + if (accept('=')) { expression_t *value = parse_constant_expression(); value = create_implicit_cast(value, enum_type); @@ -2377,7 +2345,7 @@ static void parse_enum_entries(type_t *const enum_type) } record_entity(entity, false); - } while (next_if(',') && token.kind != '}'); + } while (accept(',') && token.kind != '}'); rem_anchor_token(','); rem_anchor_token('}'); @@ -2386,9 +2354,9 @@ static void parse_enum_entries(type_t *const enum_type) static type_t *parse_enum_specifier(void) { - source_position_t const pos = *HERE; - entity_t *entity; - symbol_t *symbol; + position_t const pos = *HERE; + entity_t *entity; + symbol_t *symbol; eat(T_enum); switch (token.kind) { @@ -2404,7 +2372,7 @@ static type_t *parse_enum_specifier(void) * existing definition in outer scope */ entity = NULL; } else if (entity->enume.complete && token.kind == '{') { - source_position_t const *const ppos = &entity->base.source_position; + position_t const *const ppos = &entity->base.pos; errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos); } } @@ -2496,6 +2464,7 @@ static type_t *parse_typeof(void) } typedef enum specifiers_t { + SPECIFIER_NONE = 0, SPECIFIER_SIGNED = 1 << 0, SPECIFIER_UNSIGNED = 1 << 1, SPECIFIER_LONG = 1 << 2, @@ -2539,7 +2508,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute) do { add_anchor_token('='); - source_position_t pos; + position_t pos; symbol_t *const prop_sym = expect_identifier("while parsing property declspec", &pos); rem_anchor_token('='); @@ -2561,7 +2530,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute) symbol_t *const sym = expect_identifier("while parsing property declspec", NULL); if (prop != NULL) *prop = sym ? sym : sym_anonymous; - } while (next_if(',')); + } while (accept(',')); rem_anchor_token(','); rem_anchor_token(')'); @@ -2574,7 +2543,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute) static attribute_t *parse_microsoft_extended_decl_modifier_single(void) { attribute_kind_t kind = ATTRIBUTE_UNKNOWN; - if (next_if(T_restrict)) { + if (accept(T_restrict)) { kind = ATTRIBUTE_MS_RESTRICT; } else if (token.kind == T_IDENTIFIER) { char const *const name = token.base.symbol->string; @@ -2603,7 +2572,7 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void) } /* parse arguments */ - if (next_if('(')) + if (accept('(')) attribute->a.arguments = parse_attribute_arguments(); return attribute; @@ -2628,7 +2597,7 @@ static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first) *anchor = attribute; anchor = &attribute->next; - } while (next_if(',')); + } while (accept(',')); } rem_anchor_token(')'); expect(')'); @@ -2659,7 +2628,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) bool saw_error = false; memset(specifiers, 0, sizeof(*specifiers)); - specifiers->source_position = *HERE; + specifiers->pos = *HERE; while (true) { specifiers->attributes = parse_attributes(specifiers->attributes); @@ -2688,9 +2657,9 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers) = parse_microsoft_extended_decl_modifier(specifiers->attributes); break; - case T___thread: + case T__Thread_local: if (specifiers->thread_local) { - errorf(HERE, "duplicate '__thread'"); + errorf(HERE, "duplicate %K", &token); } else { specifiers->thread_local = true; check_thread_storage_class: @@ -2705,7 +2674,7 @@ check_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); + errorf(HERE, "%K used with '%s'", &token, wrong); break; } } @@ -2878,11 +2847,19 @@ finish_specifiers: specifiers->attributes = parse_attributes(specifiers->attributes); if (type == NULL || (saw_error && type_specifiers != 0)) { + position_t const* const pos = &specifiers->pos; atomic_type_kind_t atomic_type; /* match valid basic types */ - switch (type_specifiers) { + switch (type_specifiers & ~(SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY)) { case SPECIFIER_VOID: + if (type_specifiers & (SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY)) { + if (type_specifiers & SPECIFIER_COMPLEX) + errorf(pos, "_Complex specifier is invalid for void"); + if (type_specifiers & SPECIFIER_IMAGINARY) + errorf(pos, "_Imaginary specifier is invalid for void"); + type_specifiers &= ~(SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY); + } atomic_type = ATOMIC_TYPE_VOID; break; case SPECIFIER_WCHAR_T: @@ -2940,7 +2917,7 @@ finish_specifiers: | SPECIFIER_INT: atomic_type = ATOMIC_TYPE_ULONGLONG; warn_about_long_long: - warningf(WARN_LONG_LONG, &specifiers->source_position, "ISO C90 does not support 'long long'"); + warningf(WARN_LONG_LONG, &specifiers->pos, "ISO C90 does not support 'long long'"); break; case SPECIFIER_UNSIGNED | SPECIFIER_INT8: @@ -2998,23 +2975,17 @@ warn_about_long_long: atomic_type = ATOMIC_TYPE_LONG_DOUBLE; break; case SPECIFIER_BOOL: + if (type_specifiers & (SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY)) { + if (type_specifiers & SPECIFIER_COMPLEX) + errorf(pos, "_Complex specifier is invalid for _Bool"); + if (type_specifiers & SPECIFIER_IMAGINARY) + errorf(pos, "_Imaginary specifier is invalid for _Bool"); + type_specifiers &= ~(SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY); + } atomic_type = ATOMIC_TYPE_BOOL; break; - case SPECIFIER_FLOAT | SPECIFIER_COMPLEX: - case SPECIFIER_FLOAT | SPECIFIER_IMAGINARY: - atomic_type = ATOMIC_TYPE_FLOAT; - break; - case SPECIFIER_DOUBLE | SPECIFIER_COMPLEX: - case SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY: - atomic_type = ATOMIC_TYPE_DOUBLE; - break; - case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_COMPLEX: - case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY: - atomic_type = ATOMIC_TYPE_LONG_DOUBLE; - break; default: { /* invalid specifier combination, give an error message */ - source_position_t const* const pos = &specifiers->source_position; if (type_specifiers == 0) { if (!saw_error) { /* ISO/IEC 14882:1998(E) §C.1.5:4 */ @@ -3026,6 +2997,10 @@ warn_about_long_long: errorf(pos, "no type specifiers given in declaration"); } } + } else if (type_specifiers == SPECIFIER_COMPLEX) { + warningf(WARN_OTHER, pos, "_Complex requires a type specifier; assuming '_Complex double'"); + atomic_type = ATOMIC_TYPE_DOUBLE; + break; } else if ((type_specifiers & SPECIFIER_SIGNED) && (type_specifiers & SPECIFIER_UNSIGNED)) { errorf(pos, "signed and unsigned specifiers given"); @@ -3034,7 +3009,8 @@ warn_about_long_long: } else { errorf(pos, "multiple datatypes in declaration"); } - goto end_error; + specifiers->type = type_error_type; + return; } } @@ -3048,7 +3024,7 @@ warn_about_long_long: type->atomic.akind = atomic_type; newtype = true; } else if (type_specifiers != 0) { - errorf(&specifiers->source_position, "multiple datatypes in declaration"); + errorf(&specifiers->pos, "multiple datatypes in declaration"); } /* FIXME: check type qualifiers here */ @@ -3063,10 +3039,6 @@ warn_about_long_long: if (specifiers->attributes != NULL) type = handle_type_attributes(specifiers->attributes, type); specifiers->type = type; - return; - -end_error: - specifiers->type = type_error_type; } static type_qualifiers_t parse_type_qualifiers(void) @@ -3105,7 +3077,7 @@ static void parse_identifier_list(scope_t *scope) if (scope != NULL) append_entity(scope, entity); - } while (next_if(',') && token.kind == T_IDENTIFIER); + } while (accept(',') && token.kind == T_IDENTIFIER); } static entity_t *parse_parameter(void) @@ -3129,7 +3101,7 @@ static void semantic_parameter_incomplete(const entity_t *entity) * incomplete type. */ type_t *type = skip_typeref(entity->declaration.type); if (is_type_incomplete(type)) { - errorf(&entity->base.source_position, "'%N' has incomplete type", entity); + errorf(&entity->base.pos, "'%N' has incomplete type", entity); } } @@ -3195,7 +3167,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope) { entity_t *entity = parse_parameter(); if (entity->kind == ENTITY_TYPEDEF) { - errorf(&entity->base.source_position, + errorf(&entity->base.pos, "typedef not allowed as function parameter"); break; } @@ -3218,7 +3190,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope) default: goto parameters_finished; } - } while (next_if(',')); + } while (accept(',')); parameters_finished: rem_anchor_token(','); } @@ -3237,9 +3209,9 @@ typedef enum construct_type_kind_t { typedef union construct_type_t construct_type_t; typedef struct construct_type_base_t { - construct_type_kind_t kind; - source_position_t pos; - construct_type_t *next; + construct_type_kind_t kind; + position_t pos; + construct_type_t *next; } construct_type_base_t; typedef struct parsed_pointer_t { @@ -3315,12 +3287,12 @@ static construct_type_t *parse_array_declarator(void) eat('['); add_anchor_token(']'); - bool is_static = next_if(T_static); + bool is_static = accept(T_static); type_qualifiers_t type_qualifiers = parse_type_qualifiers(); if (!is_static) - is_static = next_if(T_static); + is_static = accept(T_static); array->type_qualifiers = type_qualifiers; array->is_static = is_static; @@ -3336,7 +3308,7 @@ static construct_type_t *parse_array_declarator(void) type_t *const orig_type = size->base.type; type_t *const type = skip_typeref(orig_type); if (!is_type_integer(type) && is_type_valid(type)) { - errorf(&size->base.source_position, + errorf(&size->base.pos, "array size '%E' must have integer type but has type '%T'", size, orig_type); } @@ -3372,13 +3344,13 @@ static construct_type_t *parse_function_declarator(scope_t *scope) } typedef struct parse_declarator_env_t { - bool may_be_abstract : 1; - bool must_be_abstract : 1; - decl_modifiers_t modifiers; - symbol_t *symbol; - source_position_t source_position; - scope_t parameters; - attribute_t *attributes; + bool may_be_abstract : 1; + bool must_be_abstract : 1; + decl_modifiers_t modifiers; + symbol_t *symbol; + position_t pos; + scope_t parameters; + attribute_t *attributes; } parse_declarator_env_t; /* §6.7.5 */ @@ -3427,8 +3399,8 @@ ptr_operator_end: ; if (env->must_be_abstract) { errorf(HERE, "no identifier expected in typename"); } else { - env->symbol = token.base.symbol; - env->source_position = *HERE; + env->symbol = token.base.symbol; + env->pos = *HERE; } eat(T_IDENTIFIER); break; @@ -3519,7 +3491,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, { construct_type_t *iter = construct_list; for (; iter != NULL; iter = iter->base.next) { - source_position_t const* const pos = &iter->base.pos; + position_t const* const pos = &iter->base.pos; switch (iter->kind) { case CONSTRUCT_FUNCTION: { construct_function_type_t *function = &iter->function; @@ -3582,22 +3554,23 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, if (size_expression != NULL) { switch (is_constant_expression(size_expression)) { - case EXPR_CLASS_CONSTANT: { + case EXPR_CLASS_INTEGER_CONSTANT: { long const size = fold_constant_to_int(size_expression); array_type->array.size = size; array_type->array.size_constant = true; /* §6.7.5.2:1 If the expression is a constant expression, * it shall have a value greater than zero. */ if (size < 0) { - errorf(&size_expression->base.source_position, + errorf(&size_expression->base.pos, "size of array must be greater than zero"); } else if (size == 0 && !GNU_MODE) { - errorf(&size_expression->base.source_position, + errorf(&size_expression->base.pos, "size of array must be greater than zero (zero length arrays are a GCC extension)"); } break; } + case EXPR_CLASS_CONSTANT: case EXPR_CLASS_VARIABLE: array_type->array.is_vla = true; break; @@ -3626,8 +3599,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list, static type_t *automatic_type_conversion(type_t *orig_type); -static type_t *semantic_parameter(const source_position_t *pos, - type_t *type, +static type_t *semantic_parameter(const position_t *pos, type_t *type, const declaration_specifiers_t *specifiers, entity_t const *const param) { @@ -3685,7 +3657,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, entity_t *entity; if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) { - entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol, &env.source_position); + entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol, &env.pos); entity->typedefe.type = orig_type; if (anonymous_entity != NULL) { @@ -3704,23 +3676,23 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, } } else { /* create a declaration type entity */ - source_position_t const *const pos = env.symbol ? &env.source_position : &specifiers->source_position; + position_t const *const pos = env.symbol ? &env.pos : &specifiers->pos; if (flags & DECL_CREATE_COMPOUND_MEMBER) { entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, env.symbol, pos); if (env.symbol != NULL) { if (specifiers->is_inline && is_type_valid(type)) { - errorf(&env.source_position, "'%N' declared 'inline'", entity); + errorf(&env.pos, "'%N' declared 'inline'", entity); } if (specifiers->thread_local || specifiers->storage_class != STORAGE_CLASS_NONE) { - errorf(&env.source_position, "'%N' must have no storage class", entity); + errorf(&env.pos, "'%N' must have no storage class", entity); } } } else if (flags & DECL_IS_PARAMETER) { entity = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, env.symbol, pos); - orig_type = semantic_parameter(&env.source_position, orig_type, specifiers, entity); + orig_type = semantic_parameter(&env.pos, orig_type, specifiers, entity); } else if (is_type_function(type)) { entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, env.symbol, pos); entity->function.is_inline = specifiers->is_inline; @@ -3736,7 +3708,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, specifiers->storage_class != STORAGE_CLASS_NONE && (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC) )) { - errorf(&env.source_position, "invalid storage class for '%N'", entity); + errorf(&env.pos, "invalid storage class for '%N'", entity); } } } else { @@ -3746,7 +3718,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, if (env.symbol != NULL) { if (specifiers->is_inline && is_type_valid(type)) { - errorf(&env.source_position, "'%N' declared 'inline'", entity); + errorf(&env.pos, "'%N' declared 'inline'", entity); } bool invalid_storage_class = false; @@ -3763,7 +3735,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers, } } if (invalid_storage_class) { - errorf(&env.source_position, "invalid storage class for '%N'", entity); + errorf(&env.pos, "invalid storage class for '%N'", entity); } } } @@ -3822,7 +3794,7 @@ static type_t *parse_abstract_declarator(type_t *base_type) */ static void check_main(const entity_t *entity) { - const source_position_t *pos = &entity->base.source_position; + const position_t *pos = &entity->base.pos; if (entity->kind != ENTITY_FUNCTION) { warningf(WARN_MAIN, pos, "'main' is not a function"); return; @@ -3874,11 +3846,11 @@ warn_arg_count: } } -static void error_redefined_as_different_kind(const source_position_t *pos, +static void error_redefined_as_different_kind(const position_t *pos, const entity_t *old, entity_kind_t new_kind) { - char const *const what = get_entity_kind_name(new_kind); - source_position_t const *const ppos = &old->base.source_position; + char const *const what = get_entity_kind_name(new_kind); + position_t const *const ppos = &old->base.pos; errorf(pos, "redeclaration of '%N' as %s (declared %P)", old, what, ppos); } @@ -3902,7 +3874,7 @@ static bool contains_attribute(const attribute_t *list, const attribute_t *attr) } /** - * test wether new_list contains any attributes not included in old_list + * Tests whether 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) @@ -3941,9 +3913,9 @@ static bool is_main(entity_t*); */ 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; - const source_position_t *pos = &entity->base.source_position; + const symbol_t *const symbol = entity->base.symbol; + const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc; + const position_t *pos = &entity->base.pos; /* can happen in error cases */ if (symbol == NULL) @@ -3981,7 +3953,7 @@ entity_t *record_entity(entity_t *entity, const bool is_definition) } if (previous_entity != NULL) { - source_position_t const *const ppos = &previous_entity->base.source_position; + position_t const *const ppos = &previous_entity->base.pos; if (previous_entity->base.parent_scope == ¤t_function->parameters && previous_entity->base.parent_scope->depth + 1 == current_scope->depth) { @@ -4096,9 +4068,7 @@ warn_redundant_declaration: ; decl->attributes); if (has_new_attrs) { merge_in_attributes(decl, prev_decl->attributes); - } else if (!is_definition && - is_type_valid(prev_type) && - !pos->is_system_header) { + } else if (!is_definition && is_type_valid(prev_type)) { warningf(WARN_REDUNDANT_DECLS, pos, "redundant declaration for '%N' (declared %P)", entity, ppos); } } else if (current_function == NULL) { @@ -4151,10 +4121,11 @@ error_redeclaration: } } else if (entity->kind == ENTITY_VARIABLE) { if (current_scope == file_scope && - entity->declaration.storage_class == STORAGE_CLASS_NONE && - !entity->declaration.implicit) { + entity->declaration.storage_class == STORAGE_CLASS_NONE && + !entity->declaration.implicit) { warn_missing_declaration: - warningf(WARN_MISSING_DECLARATIONS, pos, "no previous declaration for '%#N'", entity); + if (is_type_valid(skip_typeref(entity->declaration.type))) + warningf(WARN_MISSING_DECLARATIONS, pos, "no previous declaration for '%#N'", entity); } } @@ -4166,18 +4137,18 @@ finish: } static void parser_error_multiple_definition(entity_t *entity, - const source_position_t *source_position) + const position_t *pos) { - errorf(source_position, "redefinition of '%N' (declared %P)", entity, &entity->base.source_position); + errorf(pos, "redefinition of '%N' (declared %P)", entity, &entity->base.pos); } -static bool is_declaration_specifier(const token_t *token) +static bool is_declaration_specifier(token_t const *const tk) { - switch (token->kind) { + switch (tk->kind) { DECLARATION_START return true; case T_IDENTIFIER: - return is_typedef_symbol(token->base.symbol); + return is_typedef_symbol(tk->base.symbol); default: return false; @@ -4189,7 +4160,7 @@ static void parse_init_declarator_rest(entity_t *entity) type_t *orig_type = type_error_type; if (entity->base.kind == ENTITY_TYPEDEF) { - source_position_t const *const pos = &entity->base.source_position; + position_t const *const pos = &entity->base.pos; errorf(pos, "'%N' is initialized (use __typeof__ instead)", entity); } else { assert(is_declaration(entity)); @@ -4212,7 +4183,7 @@ static void parse_init_declarator_rest(entity_t *entity) } if (is_type_function(type)) { - source_position_t const *const pos = &entity->base.source_position; + position_t const *const pos = &entity->base.pos; errorf(pos, "'%N' is initialized like a variable", entity); orig_type = type_error_type; } @@ -4239,7 +4210,7 @@ static void parse_anonymous_declaration_rest( eat(';'); anonymous_entity = NULL; - source_position_t const *const pos = &specifiers->source_position; + position_t const *const pos = &specifiers->pos; if (specifiers->storage_class != STORAGE_CLASS_NONE || specifiers->thread_local) { warningf(WARN_OTHER, pos, "useless storage class in empty declaration"); @@ -4287,7 +4258,7 @@ static void check_variable_type_complete(entity_t *ent) return; } - errorf(&ent->base.source_position, "variable '%#N' has incomplete type", ent); + errorf(&ent->base.pos, "variable '%#N' has incomplete type", ent); } @@ -4309,14 +4280,14 @@ static void parse_declaration_rest(entity_t *ndeclaration, declaration_t *decl = &entity->declaration; if (decl->storage_class != STORAGE_CLASS_EXTERN && is_type_reference(skip_typeref(decl->type))) { - source_position_t const *const pos = &entity->base.source_position; + position_t const *const pos = &entity->base.pos; errorf(pos, "reference '%#N' must be initialized", entity); } } check_variable_type_complete(entity); - if (!next_if(',')) + if (!accept(',')) break; add_anchor_token('='); @@ -4340,7 +4311,7 @@ static entity_t *finished_kr_declaration(entity_t *entity, bool is_definition) entity_t *previous_entity = get_entity(symbol, NAMESPACE_NORMAL); if (previous_entity == NULL || previous_entity->base.parent_scope != current_scope) { - errorf(&entity->base.source_position, "expected declaration of a function parameter, found '%Y'", + errorf(&entity->base.pos, "expected declaration of a function parameter, found '%Y'", symbol); return entity; } @@ -4457,7 +4428,7 @@ decl_list_end: type_t *parameter_type = parameter->declaration.type; if (parameter_type == NULL) { - source_position_t const* const pos = ¶meter->base.source_position; + position_t const* const pos = ¶meter->base.pos; if (strict_mode) { errorf(pos, "no type specified for function '%N'", parameter); parameter_type = type_error_type; @@ -4498,9 +4469,9 @@ decl_list_end: new_type = identify_new_type(new_type); if (need_incompatible_warning) { - symbol_t const *const sym = entity->base.symbol; - source_position_t const *const pos = &entity->base.source_position; - source_position_t const *const ppos = &proto_type->base.source_position; + symbol_t const *const sym = entity->base.symbol; + position_t const *const pos = &entity->base.pos; + position_t const *const ppos = &proto_type->base.pos; warningf(WARN_OTHER, pos, "declaration '%#N' is incompatible with '%#T' (declared %P)", proto_type, new_type, sym, ppos); } entity->declaration.type = new_type; @@ -4518,7 +4489,7 @@ static void print_in_function(void) { if (first_err) { first_err = false; - char const *const file = current_function->base.base.source_position.input_name; + char const *const file = current_function->base.base.pos.input_name; diagnosticf("%s: In '%N':\n", file, (entity_t const*)current_function); } } @@ -4533,9 +4504,9 @@ static void check_labels(void) goto_statement != NULL; goto_statement = goto_statement->next) { label_t *label = goto_statement->label; - if (label->base.source_position.input_name == NULL) { + if (label->base.pos.input_name == NULL) { print_in_function(); - source_position_t const *const pos = &goto_statement->base.source_position; + position_t const *const pos = &goto_statement->base.pos; errorf(pos, "'%N' used but not defined", (entity_t const*)label); } } @@ -4548,7 +4519,7 @@ static void check_labels(void) if (! label->used) { print_in_function(); - source_position_t const *const pos = &label_statement->base.source_position; + position_t const *const pos = &label_statement->base.pos; warningf(WARN_UNUSED_LABEL, pos, "'%N' defined but not used", (entity_t const*)label); } } @@ -4568,10 +4539,10 @@ static void warn_unused_entity(warning_t const why, entity_t *entity, entity_t * if (!declaration->used) { print_in_function(); - warningf(why, &entity->base.source_position, "'%N' is unused", entity); + warningf(why, &entity->base.pos, "'%N' is unused", entity); } else if (entity->kind == ENTITY_VARIABLE && !entity->variable.read) { print_in_function(); - warningf(why, &entity->base.source_position, "'%N' is never read", entity); + warningf(why, &entity->base.pos, "'%N' is never read", entity); } } } @@ -4606,16 +4577,15 @@ static void check_declarations(void) warn_unused_entity(WARN_UNUSED_PARAMETER, scope->entities, NULL); } if (is_warn_on(WARN_UNUSED_VARIABLE)) { - walk_statements(current_function->statement, check_unused_variables, - NULL); + walk_statements(current_function->body, check_unused_variables, NULL); } } static int determine_truth(expression_t const* const cond) { return - is_constant_expression(cond) != EXPR_CLASS_CONSTANT ? 0 : - fold_constant_to_bool(cond) ? 1 : + is_constant_expression(cond) < EXPR_CLASS_CONSTANT ? 0 : + fold_constant_to_bool(cond) ? 1 : -1; } @@ -4736,7 +4706,6 @@ static bool initializer_returns(initializer_t const *const init) } case INITIALIZER_STRING: - case INITIALIZER_WIDE_STRING: case INITIALIZER_DESIGNATOR: // designators have no payload return true; } @@ -4824,8 +4793,8 @@ static void check_reachable(statement_t *const stmt) if (!expression_returns(expr)) return; - if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) { - long const val = fold_constant_to_int(expr); + if (is_constant_expression(expr) >= EXPR_CLASS_CONSTANT) { + ir_tarval *const val = fold_constant_to_tarval(expr); case_label_statement_t * defaults = NULL; for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) { if (i->expression == NULL) { @@ -4833,7 +4802,9 @@ static void check_reachable(statement_t *const stmt) continue; } - if (i->first_case <= val && val <= i->last_case) { + if (i->first_case == val || i->last_case == val || + ((tarval_cmp(i->first_case, val) & ir_relation_less_equal) + && (tarval_cmp(val, i->last_case) & ir_relation_less_equal))) { check_reachable((statement_t*)i); return; } @@ -4878,7 +4849,6 @@ static void check_reachable(statement_t *const stmt) next = parent; switch (parent->kind) { - case STATEMENT_WHILE: goto continue_while; case STATEMENT_DO_WHILE: goto continue_do_while; case STATEMENT_FOR: goto continue_for; @@ -4894,7 +4864,6 @@ static void check_reachable(statement_t *const stmt) switch (parent->kind) { case STATEMENT_SWITCH: - case STATEMENT_WHILE: case STATEMENT_DO_WHILE: case STATEMENT_FOR: last = parent; @@ -4932,25 +4901,6 @@ found_break_parent: next = stmt->case_label.statement; break; - case STATEMENT_WHILE: { - while_statement_t const *const whiles = &stmt->whiles; - expression_t const *const cond = whiles->condition; - - if (!expression_returns(cond)) - return; - - int const val = determine_truth(cond); - - if (val >= 0) - check_reachable(whiles->body); - - if (val > 0) - return; - - next = stmt->base.next; - break; - } - case STATEMENT_DO_WHILE: next = stmt->do_while.body; break; @@ -5021,7 +4971,7 @@ found_break_parent: if (!is_type_void(ret) && is_type_valid(ret) && !is_main(current_entity)) { - source_position_t const *const pos = &stmt->base.source_position; + position_t const *const pos = &stmt->base.pos; warningf(WARN_RETURN_TYPE, pos, "control reaches end of non-void function"); } return; @@ -5055,31 +5005,6 @@ found_break_parent: next = next->base.next; break; - case STATEMENT_WHILE: { -continue_while: - if (next->base.reachable) - return; - next->base.reachable = true; - - while_statement_t const *const whiles = &next->whiles; - expression_t const *const cond = whiles->condition; - - if (!expression_returns(cond)) - return; - - int const val = determine_truth(cond); - - if (val >= 0) - check_reachable(whiles->body); - - if (val > 0) - return; - - last = next; - next = next->base.next; - break; - } - case STATEMENT_DO_WHILE: { continue_do_while: if (next->base.reachable) @@ -5156,7 +5081,7 @@ static void check_unreachable(statement_t* const stmt, void *const env) if (!stmt->base.reachable) { expression_t const *const cond = stmt->do_while.condition; if (determine_truth(cond) >= 0) { - source_position_t const *const pos = &cond->base.source_position; + position_t const *const pos = &cond->base.pos; warningf(WARN_UNREACHABLE_CODE, pos, "condition of do-while-loop is unreachable"); } } @@ -5170,17 +5095,17 @@ static void check_unreachable(statement_t* const stmt, void *const env) goto warn_unreachable; } else { if (!stmt->base.reachable && fors->initialisation != NULL) { - source_position_t const *const pos = &fors->initialisation->base.source_position; + position_t const *const pos = &fors->initialisation->base.pos; warningf(WARN_UNREACHABLE_CODE, pos, "initialisation of for-statement is unreachable"); } if (!fors->condition_reachable && fors->condition != NULL) { - source_position_t const *const pos = &fors->condition->base.source_position; + position_t const *const pos = &fors->condition->base.pos; warningf(WARN_UNREACHABLE_CODE, pos, "condition of for-statement is unreachable"); } if (!fors->step_reachable && fors->step != NULL) { - source_position_t const *const pos = &fors->step->base.source_position; + position_t const *const pos = &fors->step->base.pos; warningf(WARN_UNREACHABLE_CODE, pos, "step of for-statement is unreachable"); } } @@ -5213,7 +5138,7 @@ static void check_unreachable(statement_t* const stmt, void *const env) default: warn_unreachable: if (!stmt->base.reachable) { - source_position_t const *const pos = &stmt->base.source_position; + position_t const *const pos = &stmt->base.pos; warningf(WARN_UNREACHABLE_CODE, pos, "statement is unreachable"); } return; @@ -5285,42 +5210,42 @@ static void parse_external_declaration(void) return; } - assert(is_declaration(ndeclaration)); - type_t *const orig_type = ndeclaration->declaration.type; - type_t * type = skip_typeref(orig_type); + { + assert(is_declaration(ndeclaration)); + type_t *const orig_type = ndeclaration->declaration.type; + type_t *const type = skip_typeref(orig_type); - if (!is_type_function(type)) { - if (is_type_valid(type)) { - errorf(HERE, "declarator '%#N' has a body but is not a function type", ndeclaration); + if (!is_type_function(type)) { + if (is_type_valid(type)) { + errorf(HERE, "declarator '%#N' has a body but is not a function type", ndeclaration); + } + eat_block(); + return; } - eat_block(); - return; - } - - source_position_t const *const pos = &ndeclaration->base.source_position; - if (is_typeref(orig_type)) { - /* §6.9.1:2 */ - errorf(pos, "type of function definition '%#N' is a typedef", ndeclaration); - } - if (is_type_compound(skip_typeref(type->function.return_type))) { - warningf(WARN_AGGREGATE_RETURN, pos, "'%N' returns an aggregate", ndeclaration); - } - if (type->function.unspecified_parameters) { - warningf(WARN_OLD_STYLE_DEFINITION, pos, "old-style definition of '%N'", ndeclaration); - } else { - warningf(WARN_TRADITIONAL, pos, "traditional C rejects ISO C style definition of '%N'", ndeclaration); - } + position_t const *const pos = &ndeclaration->base.pos; + if (is_typeref(orig_type)) { + /* §6.9.1:2 */ + errorf(pos, "type of function definition '%#N' is a typedef", ndeclaration); + } - /* §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_t *copy = duplicate_type(type); - copy->function.unspecified_parameters = false; - type = identify_new_type(copy); + if (is_type_compound(skip_typeref(type->function.return_type))) { + warningf(WARN_AGGREGATE_RETURN, pos, "'%N' returns an aggregate", ndeclaration); + } + if (type->function.unspecified_parameters) { + warningf(WARN_OLD_STYLE_DEFINITION, pos, "old-style definition of '%N'", ndeclaration); + } else { + warningf(WARN_TRADITIONAL, pos, "traditional C rejects ISO C style definition of '%N'", ndeclaration); + } - ndeclaration->declaration.type = type; + /* §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_t *copy = duplicate_type(type); + copy->function.unspecified_parameters = false; + ndeclaration->declaration.type = identify_new_type(copy); + } } entity_t *const entity = record_entity(ndeclaration, true); @@ -5343,13 +5268,13 @@ static void parse_external_declaration(void) || parameter->base.parent_scope == current_scope); parameter->base.parent_scope = current_scope; if (parameter->base.symbol == NULL) { - errorf(¶meter->base.source_position, "parameter name omitted"); + errorf(¶meter->base.pos, "parameter name omitted"); continue; } environment_push(parameter); } - if (function->statement != NULL) { + if (function->body != NULL) { parser_error_multiple_definition(entity, HERE); eat_block(); } else { @@ -5366,7 +5291,7 @@ static void parse_external_declaration(void) label_anchor = &label_first; statement_t *const body = parse_compound_statement(false); - function->statement = body; + function->body = body; first_err = true; check_labels(); check_declarations(); @@ -5379,8 +5304,7 @@ static void parse_external_declaration(void) walk_statements(body, check_unreachable, NULL); if (noreturn_candidate && !(function->base.modifiers & DM_NORETURN)) { - source_position_t const *const pos = &body->base.source_position; - warningf(WARN_MISSING_NORETURN, pos, "function '%#N' is candidate for attribute 'noreturn'", entity); + warningf(WARN_MISSING_NORETURN, &body->base.pos, "function '%#N' is candidate for attribute 'noreturn'", entity); } } @@ -5432,26 +5356,24 @@ static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol) return NULL; } -static void check_deprecated(const source_position_t *source_position, - const entity_t *entity) +static void check_deprecated(const position_t *pos, const entity_t *entity) { if (!is_declaration(entity)) return; if ((entity->declaration.modifiers & DM_DEPRECATED) == 0) return; - source_position_t const *const epos = &entity->base.source_position; - char const *const msg = get_deprecated_string(entity->declaration.attributes); + position_t const *const epos = &entity->base.pos; + char const *const msg = get_deprecated_string(entity->declaration.attributes); if (msg != NULL) { - warningf(WARN_DEPRECATED_DECLARATIONS, source_position, "'%N' is deprecated (declared %P): \"%s\"", entity, epos, msg); + warningf(WARN_DEPRECATED_DECLARATIONS, pos, "'%N' is deprecated (declared %P): \"%s\"", entity, epos, msg); } else { - warningf(WARN_DEPRECATED_DECLARATIONS, source_position, "'%N' is deprecated (declared %P)", entity, epos); + warningf(WARN_DEPRECATED_DECLARATIONS, pos, "'%N' is deprecated (declared %P)", entity, epos); } } -static expression_t *create_select(const source_position_t *pos, - expression_t *addr, +static expression_t *create_select(const position_t *pos, expression_t *addr, type_qualifiers_t qualifiers, entity_t *entry) { @@ -5460,6 +5382,7 @@ static expression_t *create_select(const source_position_t *pos, check_deprecated(pos, entry); expression_t *select = allocate_expression_zero(EXPR_SELECT); + select->base.pos = *pos; select->select.compound = addr; select->select.compound_entry = entry; @@ -5488,7 +5411,7 @@ static expression_t *create_select(const source_position_t *pos, * creates implicit select expressions for them. * Returns the adress for the innermost compound. */ -static expression_t *find_create_select(const source_position_t *pos, +static expression_t *find_create_select(const position_t *pos, expression_t *addr, type_qualifiers_t qualifiers, compound_t *compound, symbol_t *symbol) @@ -5501,8 +5424,7 @@ static expression_t *find_create_select(const source_position_t *pos, symbol_t *iter_symbol = iter->base.symbol; if (iter_symbol == NULL) { type_t *type = iter->declaration.type; - if (type->kind != TYPE_COMPOUND_STRUCT - && type->kind != TYPE_COMPOUND_UNION) + if (!is_type_compound(type)) continue; compound_t *sub_compound = type->compound.compound; @@ -5511,8 +5433,7 @@ static expression_t *find_create_select(const source_position_t *pos, continue; expression_t *sub_addr = create_select(pos, addr, qualifiers, iter); - sub_addr->base.source_position = *pos; - sub_addr->base.implicit = true; + sub_addr->base.implicit = true; return find_create_select(pos, sub_addr, qualifiers, sub_compound, symbol); } @@ -5539,7 +5460,7 @@ static void parse_bitfield_member(entity_t *entity) type); } - if (is_constant_expression(size) != EXPR_CLASS_CONSTANT) { + if (is_constant_expression(size) < EXPR_CLASS_CONSTANT) { /* error already reported by parse_constant_expression */ size_long = get_type_size(type) * 8; } else { @@ -5574,74 +5495,49 @@ static void parse_compound_declarators(compound_t *compound, add_anchor_token(';'); add_anchor_token(','); do { - entity_t *entity; + entity_t *const entity = parse_declarator(specifiers, DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER); + position_t const *const pos = &entity->base.pos; + if (entity->kind == ENTITY_TYPEDEF) { + errorf(pos, "typedef not allowed as compound member"); + continue; + } - if (token.kind == ':') { - /* anonymous bitfield */ - type_t *type = specifiers->type; - entity_t *const entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, NULL, HERE); - entity->declaration.declared_storage_class = STORAGE_CLASS_NONE; - entity->declaration.storage_class = STORAGE_CLASS_NONE; - entity->declaration.type = type; + assert(entity->kind == ENTITY_COMPOUND_MEMBER); - parse_bitfield_member(entity); - - attribute_t *attributes = parse_attributes(NULL); - attribute_t **anchor = &attributes; - while (*anchor != NULL) - anchor = &(*anchor)->next; - *anchor = specifiers->attributes; - if (attributes != NULL) { - handle_entity_attributes(attributes, entity); + /* make sure we don't define a symbol multiple times */ + symbol_t *symbol = entity->base.symbol; + if (symbol != NULL) { + entity_t *prev = find_compound_entry(compound, symbol); + if (prev != NULL) { + position_t const *const ppos = &prev->base.pos; + errorf(pos, "multiple declarations of '%N' (declared %P)", entity, ppos); } - entity->declaration.attributes = attributes; - - append_entity(&compound->members, entity); - } else { - entity = parse_declarator(specifiers, - DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER); - source_position_t const *const pos = &entity->base.source_position; - if (entity->kind == ENTITY_TYPEDEF) { - errorf(pos, "typedef not allowed as compound member"); - } else { - assert(entity->kind == ENTITY_COMPOUND_MEMBER); - - /* make sure we don't define a symbol multiple times */ - symbol_t *symbol = entity->base.symbol; - if (symbol != NULL) { - entity_t *prev = find_compound_entry(compound, symbol); - if (prev != NULL) { - source_position_t const *const ppos = &prev->base.source_position; - errorf(pos, "multiple declarations of '%N' (declared %P)", entity, ppos); - } - } + } - if (token.kind == ':') { - parse_bitfield_member(entity); + if (token.kind == ':') { + parse_bitfield_member(entity); - attribute_t *attributes = parse_attributes(NULL); - handle_entity_attributes(attributes, entity); - } else { - type_t *orig_type = entity->declaration.type; - type_t *type = skip_typeref(orig_type); - if (is_type_function(type)) { - errorf(pos, "'%N' must not have function type '%T'", entity, orig_type); - } else if (is_type_incomplete(type)) { - /* §6.7.2.1:16 flexible array member */ - if (!is_type_array(type) || - token.kind != ';' || - look_ahead(1)->kind != '}') { - errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type); - } else if (compound->members.entities == NULL) { - errorf(pos, "flexible array member in otherwise empty struct"); - } - } + attribute_t *attributes = parse_attributes(NULL); + handle_entity_attributes(attributes, entity); + } else { + type_t *orig_type = entity->declaration.type; + type_t *type = skip_typeref(orig_type); + if (is_type_function(type)) { + errorf(pos, "'%N' must not have function type '%T'", entity, orig_type); + } else if (is_type_incomplete(type)) { + /* §6.7.2.1:16 flexible array member */ + if (!is_type_array(type) || + token.kind != ';' || + look_ahead(1)->kind != '}') { + errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type); + } else if (compound->members.entities == NULL) { + errorf(pos, "flexible array member in otherwise empty struct"); } - - append_entity(&compound->members, entity); } } - } while (next_if(',')); + + append_entity(&compound->members, entity); + } while (accept(',')); rem_anchor_token(','); rem_anchor_token(';'); expect(';'); @@ -5686,7 +5582,7 @@ static type_t *parse_typename(void) /* TODO: improve error message, user does probably not know what a * storage class is... */ - errorf(&specifiers.source_position, "typename must not have a storage class"); + errorf(&specifiers.pos, "typename must not have a storage class"); } type_t *result = parse_abstract_declarator(specifiers.type); @@ -5713,8 +5609,11 @@ static type_t *get_string_type(string_encoding_t const enc) { bool const warn = is_warn_on(WARN_WRITE_STRINGS); switch (enc) { - case STRING_ENCODING_CHAR: return warn ? type_const_char_ptr : type_char_ptr; - case STRING_ENCODING_WIDE: return warn ? type_const_wchar_t_ptr : type_wchar_t_ptr; + case STRING_ENCODING_CHAR: + case STRING_ENCODING_UTF8: return warn ? type_const_char_ptr : type_char_ptr; + case STRING_ENCODING_CHAR16: return warn ? type_char16_t_const_ptr : type_char16_t_ptr; + case STRING_ENCODING_CHAR32: return warn ? type_char32_t_const_ptr : type_char32_t_ptr; + case STRING_ENCODING_WIDE: return warn ? type_const_wchar_t_ptr : type_wchar_t_ptr; } panic("invalid string encoding"); } @@ -5725,8 +5624,8 @@ static type_t *get_string_type(string_encoding_t const enc) static expression_t *parse_string_literal(void) { expression_t *const expr = allocate_expression_zero(EXPR_STRING_LITERAL); - expr->string_literal.value = concat_string_literals(&expr->string_literal.encoding); - expr->base.type = get_string_type(expr->string_literal.encoding); + expr->string_literal.value = concat_string_literals(); + expr->base.type = get_string_type(expr->string_literal.value.encoding); return expr; } @@ -5744,110 +5643,199 @@ static expression_t *parse_boolean_literal(bool value) return literal; } -static void warn_traditional_suffix(void) +static void check_number_suffix(expression_t *const expr, char const *const suffix, bool const is_float) { - warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%S' suffix", - &token.number.suffix); -} - -static void check_integer_suffix(void) -{ - const string_t *suffix = &token.number.suffix; - if (suffix->size == 0) - return; + unsigned spec = SPECIFIER_NONE; + for (char const *c = suffix; *c != '\0'; ++c) { + specifiers_t add; + switch (*c) { + case 'F': case 'f': + add = SPECIFIER_FLOAT; + break; - bool not_traditional = false; - const char *c = suffix->begin; - 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)) { + case 'L': case 'l': + add = SPECIFIER_LONG; + if (*c == c[1] && !is_float) { + add |= SPECIFIER_LONG_LONG; ++c; } + break; + + case 'U': case 'u': + add = SPECIFIER_UNSIGNED; + break; + + case 'I': case 'i': + case 'J': case 'j': + add = SPECIFIER_COMPLEX; + break; + + default: + goto error; } + if (spec & add) + goto error; + spec |= add; } - if (*c != '\0') { - errorf(HERE, "invalid suffix '%S' on integer constant", suffix); - } else if (not_traditional) { - warn_traditional_suffix(); - } -} -static type_t *check_floatingpoint_suffix(void) -{ - const string_t *suffix = &token.number.suffix; - type_t *type = type_double; - if (suffix->size == 0) - return type; + if (!(spec & SPECIFIER_FLOAT) && is_float) + spec |= SPECIFIER_DOUBLE; - bool not_traditional = false; - const char *c = suffix->begin; - if (*c == 'f' || *c == 'F') { - ++c; - type = type_float; - } else if (*c == 'l' || *c == 'L') { - ++c; - type = type_long_double; - } - if (*c != '\0') { - errorf(HERE, "invalid suffix '%S' on floatingpoint constant", suffix); - } else if (not_traditional) { - warn_traditional_suffix(); + if (!(spec & (SPECIFIER_FLOAT | SPECIFIER_DOUBLE)) == is_float) + goto error; + + type_t *type; + switch (spec & ~SPECIFIER_COMPLEX) { + case SPECIFIER_NONE: type = type_int; break; + case SPECIFIER_LONG: type = type_long; break; + case SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_long_long; break; + case SPECIFIER_UNSIGNED: type = type_unsigned_int; break; + case SPECIFIER_UNSIGNED | SPECIFIER_LONG: type = type_unsigned_long; break; + case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_unsigned_long_long; break; + case SPECIFIER_FLOAT: type = type_float; break; + case SPECIFIER_DOUBLE: type = type_double; break; + case SPECIFIER_DOUBLE | SPECIFIER_LONG: type = type_long_double; break; + + default: +error: + errorf(HERE, "invalid suffix '%s' on %s constant", suffix, is_float ? "floatingpoint" : "integer"); + return; } - return type; + if (spec != SPECIFIER_NONE && spec != SPECIFIER_LONG && spec != SPECIFIER_DOUBLE) + warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%s' suffix", suffix); + + if (spec & SPECIFIER_COMPLEX) + type = make_complex_type(get_arithmetic_akind(type), TYPE_QUALIFIER_NONE); + + expr->base.type = type; + if (!is_float) { + /* 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(&expr->literal); + } } -/** - * Parse an integer constant. - */ static expression_t *parse_number_literal(void) { - expression_kind_t kind; - type_t *type; + string_t const *const str = &token.literal.string; + char const * i = str->begin; + unsigned digits = 0; + bool is_float = false; - switch (token.kind) { - case T_INTEGER: - kind = EXPR_LITERAL_INTEGER; - check_integer_suffix(); - type = type_int; + /* Parse base prefix. */ + unsigned base; + if (*i == '0') { + switch (*++i) { + case 'B': case 'b': base = 2; ++i; break; + case 'X': case 'x': base = 16; ++i; break; + default: base = 8; digits |= 1U << 0; break; + } + } else { + base = 10; + } + + /* Parse mantissa. */ + for (;; ++i) { + unsigned digit; + switch (*i) { + case '.': + if (is_float) { + errorf(HERE, "multiple decimal points in %K", &token); + i = 0; + goto done; + } + is_float = true; + if (base == 8) + base = 10; + continue; + + case '0': digit = 0; break; + case '1': digit = 1; break; + case '2': digit = 2; break; + case '3': digit = 3; break; + case '4': digit = 4; break; + case '5': digit = 5; break; + case '6': digit = 6; break; + case '7': digit = 7; break; + case '8': digit = 8; break; + case '9': digit = 9; break; + case 'A': case 'a': digit = 10; break; + case 'B': case 'b': digit = 11; break; + case 'C': case 'c': digit = 12; break; + case 'D': case 'd': digit = 13; break; + case 'E': case 'e': digit = 14; break; + case 'F': case 'f': digit = 15; break; + + default: goto done_mantissa; + } + + if (digit >= 10 && base != 16) + goto done_mantissa; + + digits |= 1U << digit; + } +done_mantissa: + + /* Parse exponent. */ + switch (base) { + case 2: + if (is_float) + errorf(HERE, "binary floating %K not allowed", &token); break; - case T_FLOATINGPOINT: - kind = EXPR_LITERAL_FLOATINGPOINT; - type = check_floatingpoint_suffix(); + case 8: + case 10: + if (*i == 'E' || *i == 'e') { + base = 10; + goto parse_exponent; + } + break; + + case 16: + if (*i == 'P' || *i == 'p') { +parse_exponent: + ++i; + is_float = true; + + if (*i == '-' || *i == '+') + ++i; + + if (isdigit(*i)) { + do { + ++i; + } while (isdigit(*i)); + } else { + errorf(HERE, "exponent of %K has no digits", &token); + } + } else if (is_float) { + errorf(HERE, "hexadecimal floating %K requires an exponent", &token); + i = 0; + } break; default: - panic("unexpected token type in parse_number_literal"); + panic("invalid base"); } - expression_t *literal = allocate_expression_zero(kind); - literal->base.type = type; - literal->literal.value = token.number.number; - literal->literal.suffix = token.number.suffix; - next_token(); +done:; + expression_t *const expr = allocate_expression_zero(is_float ? EXPR_LITERAL_FLOATINGPOINT : EXPR_LITERAL_INTEGER); + expr->literal.value = *str; - /* 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; + if (i) { + if (digits == 0) { + errorf(HERE, "%K has no digits", &token); + } else if (digits & ~((1U << base) - 1)) { + errorf(HERE, "invalid digit in %K", &token); + } else { + expr->literal.suffix = i; + check_number_suffix(expr, i, is_float); + } + } + + eat(T_NUMBER); + return expr; } /** @@ -5856,13 +5844,14 @@ static expression_t *parse_number_literal(void) static expression_t *parse_character_constant(void) { expression_t *const literal = allocate_expression_zero(EXPR_LITERAL_CHARACTER); - literal->string_literal.encoding = token.string.encoding; - literal->string_literal.value = token.string.string; + literal->string_literal.value = token.literal.string; - switch (token.string.encoding) { + size_t const size = get_string_len(&token.literal.string); + switch (token.literal.string.encoding) { case STRING_ENCODING_CHAR: + case STRING_ENCODING_UTF8: literal->base.type = c_mode & _CXX ? type_char : type_int; - if (literal->string_literal.value.size > 1) { + if (size > 1) { if (!GNU_MODE && !(c_mode & _C99)) { errorf(HERE, "more than 1 character in character constant"); } else { @@ -5872,9 +5861,11 @@ static expression_t *parse_character_constant(void) } break; - case STRING_ENCODING_WIDE: - literal->base.type = type_int; - if (wstrlen(&literal->string_literal.value) > 1) { + case STRING_ENCODING_CHAR16: literal->base.type = type_char16_t; goto warn_multi; + case STRING_ENCODING_CHAR32: literal->base.type = type_char32_t; goto warn_multi; + case STRING_ENCODING_WIDE: literal->base.type = type_wchar_t; goto warn_multi; +warn_multi: + if (size > 1) { warningf(WARN_MULTICHAR, HERE, "multi-character character constant"); } break; @@ -5884,7 +5875,7 @@ static expression_t *parse_character_constant(void) return literal; } -static entity_t *create_implicit_function(symbol_t *symbol, source_position_t const *const pos) +static entity_t *create_implicit_function(symbol_t *symbol, position_t const *const pos) { type_t *ntype = allocate_type_zero(TYPE_FUNCTION); ntype->function.return_type = type_int; @@ -5969,7 +5960,7 @@ type_t *revert_automatic_type_conversion(const expression_t *expression) } case EXPR_STRING_LITERAL: { - size_t const size = expression->string_literal.value.size + 1; + size_t const size = get_string_len(&expression->string_literal.value) + 1; type_t *const elem = get_unqualified_type(expression->base.type->pointer.points_to); return make_array_type(elem, size, TYPE_QUALIFIER_NONE); } @@ -6009,11 +6000,11 @@ static entity_t *lookup_entity(const scope_t *scope, symbol_t *symbol, static entity_t *parse_qualified_identifier(void) { /* namespace containing the symbol */ - symbol_t *symbol; - source_position_t pos; - const scope_t *lookup_scope = NULL; + symbol_t *symbol; + position_t pos; + const scope_t *lookup_scope = NULL; - if (next_if(T_COLONCOLON)) + if (accept(T_COLONCOLON)) lookup_scope = &unit->scope; entity_t *entity; @@ -6025,7 +6016,7 @@ static entity_t *parse_qualified_identifier(void) /* lookup entity */ entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL); - if (!next_if(T_COLONCOLON)) + if (!accept(T_COLONCOLON)) break; switch (entity->kind) { @@ -6042,7 +6033,7 @@ static entity_t *parse_qualified_identifier(void) symbol, get_entity_kind_name(entity->kind)); /* skip further qualifications */ - while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {} + while (accept(T_IDENTIFIER) && accept(T_COLONCOLON)) {} return create_error_entity(sym_anonymous, ENTITY_VARIABLE); } @@ -6064,8 +6055,8 @@ static entity_t *parse_qualified_identifier(void) static expression_t *parse_reference(void) { - source_position_t const pos = *HERE; - entity_t *const entity = parse_qualified_identifier(); + position_t const pos = *HERE; + entity_t *const entity = parse_qualified_identifier(); type_t *orig_type; if (is_declaration(entity)) { @@ -6084,10 +6075,10 @@ static expression_t *parse_reference(void) if (entity->kind == ENTITY_ENUM_VALUE) kind = EXPR_ENUM_CONSTANT; - expression_t *expression = allocate_expression_zero(kind); - expression->base.source_position = pos; - expression->base.type = type; - expression->reference.entity = entity; + expression_t *expression = allocate_expression_zero(kind); + expression->base.pos = pos; + expression->base.type = type; + expression->reference.entity = entity; /* this declaration is used */ if (is_declaration(entity)) { @@ -6110,14 +6101,15 @@ static expression_t *parse_reference(void) static bool semantic_cast(expression_t *cast) { - expression_t *expression = cast->unary.value; - type_t *orig_dest_type = cast->base.type; - type_t *orig_type_right = expression->base.type; - type_t const *dst_type = skip_typeref(orig_dest_type); - type_t const *src_type = skip_typeref(orig_type_right); - source_position_t const *pos = &cast->base.source_position; + expression_t *expression = cast->unary.value; + type_t *orig_dest_type = cast->base.type; + type_t *orig_type_right = expression->base.type; + type_t const *dst_type = skip_typeref(orig_dest_type); + type_t const *src_type = skip_typeref(orig_type_right); + position_t const *pos = &cast->base.pos; - /* §6.5.4 A (void) cast is explicitly permitted, more for documentation than for utility. */ + /* §6.5.4 A (void) cast is explicitly permitted, more for documentation + * than for utility. */ if (is_type_void(dst_type)) return true; @@ -6152,21 +6144,52 @@ static bool semantic_cast(expression_t *cast) return true; } -static expression_t *parse_compound_literal(source_position_t const *const pos, type_t *type) +static void semantic_complex_extract(unary_expression_t *extract) +{ + type_t *orig_value_type = extract->value->base.type; + type_t *value_type = skip_typeref(orig_value_type); + if (!is_type_valid(value_type)) { + extract->base.type = type_error_type; + return; + } + + type_t *type = value_type; + if (!is_type_complex(type)) { + if (!is_type_arithmetic(type)) { + errorf(&extract->base.pos, + "%s requires an argument with complex or arithmetic type, got '%T'", + extract->base.kind == EXPR_UNARY_IMAG ? "__imag__" : "__real__", + orig_value_type); + extract->base.type = type_error_type; + return; + } + atomic_type_kind_t const akind = get_arithmetic_akind(type); + type = make_complex_type(akind, TYPE_QUALIFIER_NONE); + extract->value = create_implicit_cast(extract->value, type); + } + assert(type->kind == TYPE_COMPLEX); + type = make_atomic_type(type->atomic.akind, TYPE_QUALIFIER_NONE); + extract->base.type = type; +} + +static expression_t *parse_compound_literal(position_t const *const pos, + type_t *type) { expression_t *expression = allocate_expression_zero(EXPR_COMPOUND_LITERAL); - expression->base.source_position = *pos; + expression->base.pos = *pos; + bool global_scope = current_scope == file_scope; parse_initializer_env_t env; env.type = type; env.entity = NULL; - env.must_be_constant = false; + env.must_be_constant = global_scope; initializer_t *initializer = parse_initializer(&env); type = env.type; - expression->compound_literal.initializer = initializer; - expression->compound_literal.type = type; - expression->base.type = automatic_type_conversion(type); + expression->base.type = automatic_type_conversion(type); + expression->compound_literal.initializer = initializer; + expression->compound_literal.type = type; + expression->compound_literal.global_scope = global_scope; return expression; } @@ -6176,7 +6199,7 @@ static expression_t *parse_compound_literal(source_position_t const *const pos, */ static expression_t *parse_cast(void) { - source_position_t const pos = *HERE; + position_t const pos = *HERE; eat('('); add_anchor_token(')'); @@ -6191,19 +6214,29 @@ static expression_t *parse_cast(void) } expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST); - cast->base.source_position = pos; + cast->base.pos = pos; expression_t *value = parse_subexpression(PREC_CAST); cast->base.type = type; cast->unary.value = value; - if (! semantic_cast(cast)) { - /* TODO: record the error in the AST. else it is impossible to detect it */ + if (!semantic_cast(cast)) { + cast->base.type = type_error_type; } return cast; } +static expression_t *parse_complex_extract_expression(expression_kind_t const kind) +{ + expression_t *extract = allocate_expression_zero(kind); + next_token(); + + extract->unary.value = parse_subexpression(PREC_CAST); + semantic_complex_extract(&extract->unary); + return extract; +} + /** * Parse a statement expression. */ @@ -6229,7 +6262,7 @@ static expression_t *parse_statement_expression(void) type = stmt->expression.expression->base.type; } } else { - source_position_t const *const pos = &expression->base.source_position; + position_t const *const pos = &expression->base.pos; warningf(WARN_OTHER, pos, "empty statement expression ({})"); } expression->base.type = type; @@ -6270,7 +6303,7 @@ static expression_t *parse_parenthesized_expression(void) static expression_t *parse_function_keyword(funcname_kind_t const kind) { if (current_function == NULL) { - errorf(HERE, "'%K' used outside of a function", &token); + errorf(HERE, "%K used outside of a function", &token); } expression_t *expression = allocate_expression_zero(EXPR_FUNCNAME); @@ -6285,15 +6318,15 @@ static expression_t *parse_function_keyword(funcname_kind_t const kind) static designator_t *parse_designator(void) { designator_t *const result = allocate_ast_zero(sizeof(result[0])); - result->symbol = expect_identifier("while parsing member designator", &result->source_position); + result->symbol = expect_identifier("while parsing member designator", &result->pos); if (!result->symbol) return NULL; designator_t *last_designator = result; while (true) { - if (next_if('.')) { + if (accept('.')) { designator_t *const designator = allocate_ast_zero(sizeof(result[0])); - designator->symbol = expect_identifier("while parsing member designator", &designator->source_position); + designator->symbol = expect_identifier("while parsing member designator", &designator->pos); if (!designator->symbol) return NULL; @@ -6301,16 +6334,13 @@ static designator_t *parse_designator(void) last_designator = designator; continue; } - if (next_if('[')) { + if (accept('[')) { add_anchor_token(']'); - designator_t *designator = allocate_ast_zero(sizeof(result[0])); - designator->source_position = *HERE; - designator->array_index = parse_expression(); + designator_t *designator = allocate_ast_zero(sizeof(result[0])); + designator->pos = *HERE; + designator->array_index = parse_expression(); rem_anchor_token(']'); expect(']'); - if (designator->array_index == NULL) { - return NULL; - } last_designator->next = designator; last_designator = designator; @@ -6399,11 +6429,11 @@ static expression_t *parse_va_start(void) expect(')'); if (!current_function) { - errorf(&expression->base.source_position, "'va_start' used outside of function"); + errorf(&expression->base.pos, "'va_start' used outside of function"); } else if (!current_function->base.type->function.variadic) { - errorf(&expression->base.source_position, "'va_start' used in non-variadic function"); + errorf(&expression->base.pos, "'va_start' used in non-variadic function"); } else if (!is_last_parameter(param)) { - errorf(¶m->base.source_position, "second argument of 'va_start' must be last parameter of the current function"); + errorf(¶m->base.pos, "second argument of 'va_start' must be last parameter of the current function"); } return expression; @@ -6450,7 +6480,7 @@ static expression_t *parse_va_copy(void) expression_t *dst = parse_assignment_expression(); assign_error_t error = semantic_assign(type_valist, dst); report_assign_error(error, type_valist, dst, "call argument 1", - &dst->base.source_position); + &dst->base.pos); expression->va_copye.dst = dst; rem_anchor_token(','); @@ -6477,7 +6507,7 @@ static expression_t *parse_builtin_constant(void) add_anchor_token(')'); expect('('); - expression->builtin_constant.value = parse_assignment_expression(); + expression->builtin_constant.value = parse_expression(); rem_anchor_token(')'); expect(')'); expression->base.type = type_int; @@ -6544,10 +6574,10 @@ static expression_t *parse_compare_builtin(void) if (!is_type_float(type_left) && !is_type_float(type_right)) { if (is_type_valid(type_left) && is_type_valid(type_right)) { type_error_incompatible("invalid operands in comparison", - &expression->base.source_position, orig_type_left, orig_type_right); + &expression->base.pos, orig_type_left, orig_type_right); } } else { - semantic_comparison(&expression->binary); + semantic_comparison(&expression->binary, true); } return expression; @@ -6564,7 +6594,7 @@ static expression_t *parse_assume(void) add_anchor_token(')'); expect('('); - expression->unary.value = parse_assignment_expression(); + expression->unary.value = parse_expression(); rem_anchor_token(')'); expect(')'); @@ -6592,7 +6622,7 @@ static label_t *get_label(char const *const context) } } else if (label == NULL || label->base.parent_scope != ¤t_function->parameters) { /* There is no matching label in the same function, so create a new one. */ - source_position_t const nowhere = { NULL, 0, 0, false }; + position_t const nowhere = { NULL, 0, 0, false }; label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym, &nowhere); label_push(label); } @@ -6605,7 +6635,7 @@ static label_t *get_label(char const *const context) */ static expression_t *parse_label_address(void) { - source_position_t const source_position = *HERE; + position_t const pos = *HERE; eat(T_ANDAND); label_t *const label = get_label("while parsing label address"); @@ -6616,7 +6646,7 @@ static expression_t *parse_label_address(void) label->address_taken = true; expression_t *expression = allocate_expression_zero(EXPR_LABEL_ADDRESS); - expression->base.source_position = source_position; + expression->base.pos = pos; /* label address is treated as a void pointer */ expression->base.type = type_void_ptr; @@ -6645,7 +6675,7 @@ static expression_t *parse_noop_expression(void) if (token.kind != ')') do { (void)parse_assignment_expression(); - } while (next_if(',')); + } while (accept(',')); rem_anchor_token(','); rem_anchor_token(')'); @@ -6663,8 +6693,7 @@ static expression_t *parse_primary_expression(void) switch (token.kind) { case T_false: return parse_boolean_literal(false); case T_true: return parse_boolean_literal(true); - case T_INTEGER: - case T_FLOATINGPOINT: return parse_number_literal(); + case T_NUMBER: return parse_number_literal(); case T_CHARACTER_CONSTANT: return parse_character_constant(); case T_STRING_LITERAL: return parse_string_literal(); case T___func__: return parse_function_keyword(FUNCNAME_FUNCTION); @@ -6691,6 +6720,8 @@ static expression_t *parse_primary_expression(void) case '(': return parse_parenthesized_expression(); case T___noop: return parse_noop_expression(); + case T___imag__: return parse_complex_extract_expression(EXPR_UNARY_IMAG); + case T___real__: return parse_complex_extract_expression(EXPR_UNARY_REAL); /* Gracefully handle type names while parsing expressions. */ case T_COLONCOLON: @@ -6701,7 +6732,7 @@ static expression_t *parse_primary_expression(void) } /* FALLTHROUGH */ DECLARATION_START { - source_position_t const pos = *HERE; + position_t const pos = *HERE; declaration_specifiers_t specifiers; parse_declaration_specifiers(&specifiers); type_t const *const type = parse_abstract_declarator(specifiers.type); @@ -6750,14 +6781,15 @@ static expression_t *parse_array_expression(expression_t *left) check_idx: res_type = automatic_type_conversion(res_type); if (!is_type_integer(idx_type)) { - errorf(&idx->base.source_position, "array subscript must have integer type"); + if (is_type_valid(idx_type)) + errorf(&idx->base.pos, "array subscript must have integer type"); } else if (is_type_atomic(idx_type, ATOMIC_TYPE_CHAR)) { - source_position_t const *const pos = &idx->base.source_position; + position_t const *const pos = &idx->base.pos; warningf(WARN_CHAR_SUBSCRIPTS, pos, "array subscript has char type"); } } else { if (is_type_valid(type_left) && is_type_valid(type_inside)) { - errorf(&expr->base.source_position, "invalid types '%T[%T]' for array access", orig_type_left, orig_type_inside); + errorf(&expr->base.pos, "invalid types '%T[%T]' for array access", orig_type_left, orig_type_inside); } res_type = type_error_type; ref = left; @@ -6784,12 +6816,12 @@ static expression_t *parse_typeprop(expression_kind_t const kind) expression_t *tp_expression = allocate_expression_zero(kind); tp_expression->base.type = type_size_t; - eat(kind == EXPR_SIZEOF ? T_sizeof : T___alignof__); + eat(kind == EXPR_SIZEOF ? T_sizeof : T__Alignof); type_t *orig_type; expression_t *expression; if (token.kind == '(' && is_declaration_specifier(look_ahead(1))) { - source_position_t const pos = *HERE; + position_t const pos = *HERE; eat('('); add_anchor_token(')'); orig_type = parse_typename(); @@ -6808,7 +6840,7 @@ static expression_t *parse_typeprop(expression_kind_t const kind) typeprop_expression: if (is_bitfield(expression)) { char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; - errorf(&tp_expression->base.source_position, + errorf(&tp_expression->base.pos, "operand of %s expression must not be a bitfield", what); } @@ -6827,8 +6859,8 @@ typeprop_expression: } else if (type->kind == TYPE_FUNCTION) { if (GNU_MODE) { /* function types are allowed (and return 1) */ - source_position_t const *const pos = &tp_expression->base.source_position; - char const *const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; + position_t const *const pos = &tp_expression->base.pos; + char const *const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; warningf(WARN_OTHER, pos, "%s expression with function argument returns invalid result", what); } else { wrong_type = "function"; @@ -6837,7 +6869,7 @@ typeprop_expression: if (wrong_type != NULL) { char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof"; - errorf(&tp_expression->base.source_position, + errorf(&tp_expression->base.pos, "operand of %s expression must not be of %s type '%T'", what, wrong_type, orig_type); } @@ -6859,7 +6891,7 @@ static expression_t *parse_select_expression(expression_t *addr) { assert(token.kind == '.' || token.kind == T_MINUSGREATER); bool select_left_arrow = (token.kind == T_MINUSGREATER); - source_position_t const pos = *HERE; + position_t const pos = *HERE; next_token(); symbol_t *const symbol = expect_identifier("while parsing select", NULL); @@ -6887,9 +6919,7 @@ static expression_t *parse_select_expression(expression_t *addr) type_left = type; } - if (type_left->kind != TYPE_COMPOUND_STRUCT && - type_left->kind != TYPE_COMPOUND_UNION) { - + if (!is_type_compound(type_left)) { if (is_type_valid(type_left) && !saw_error) { errorf(&pos, "request for member '%Y' in something not a struct or union, but '%T'", @@ -6959,14 +6989,14 @@ static void check_call_argument(type_t *expected_type, char buf[64]; snprintf(buf, sizeof(buf), "call argument %u", pos); report_assign_error(error, expected_type, arg_expr, buf, - &arg_expr->base.source_position); + &arg_expr->base.pos); } else { type_t *const promoted_type = get_default_promoted_type(arg_type); if (!types_compatible(expected_type_skip, promoted_type) && !types_compatible(expected_type_skip, type_void_ptr) && !types_compatible(type_void_ptr, promoted_type)) { /* Deliberately show the skipped types in this warning */ - source_position_t const *const apos = &arg_expr->base.source_position; + position_t const *const apos = &arg_expr->base.pos; warningf(WARN_TRADITIONAL, apos, "passing call argument %u as '%T' rather than '%T' due to prototype", pos, expected_type_skip, promoted_type); } } @@ -6987,7 +7017,7 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) call_argument_t *argument = call->arguments; if (is_constant_expression(argument->expression) == EXPR_CLASS_VARIABLE) { - errorf(&call->base.source_position, + errorf(&call->base.pos, "argument of '%Y' must be a constant expression", call->function->reference.entity->base.symbol); } @@ -7002,7 +7032,7 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) if (rw != NULL) { if (is_constant_expression(rw->expression) == EXPR_CLASS_VARIABLE) { - errorf(&call->base.source_position, + errorf(&call->base.pos, "second argument of '%Y' must be a constant expression", call->function->reference.entity->base.symbol); } @@ -7010,11 +7040,10 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) } if (locality != NULL) { if (is_constant_expression(locality->expression) == EXPR_CLASS_VARIABLE) { - errorf(&call->base.source_position, + errorf(&call->base.pos, "third argument of '%Y' must be a constant expression", call->function->reference.entity->base.symbol); } - locality = rw->next; } break; default: @@ -7027,7 +7056,7 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) call_argument_t *arg = call->arguments->next; if (arg != NULL && is_constant_expression(arg->expression) == EXPR_CLASS_VARIABLE) { - errorf(&call->base.source_position, + errorf(&call->base.pos, "second argument of '%Y' must be a constant expression", call->function->reference.entity->base.symbol); } @@ -7038,7 +7067,7 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) } /** - * Parse a call expression, ie. expression '( ... )'. + * Parse a call expression, i.e. expression '( ... )'. * * @param expression the function address */ @@ -7080,7 +7109,7 @@ static expression_t *parse_call_expression(expression_t *expression) *anchor = argument; anchor = &argument->next; - } while (next_if(',')); + } while (accept(',')); } rem_anchor_token(','); rem_anchor_token(')'); @@ -7099,9 +7128,11 @@ static expression_t *parse_call_expression(expression_t *expression) } if (parameter != NULL) { - errorf(&expression->base.source_position, "too few arguments to function '%E'", expression); + errorf(&expression->base.pos, "too few arguments to function '%E'", + expression); } else if (argument != NULL && !function_type->variadic) { - errorf(&argument->expression->base.source_position, "too many arguments to function '%E'", expression); + errorf(&argument->expression->base.pos, + "too many arguments to function '%E'", expression); } } @@ -7109,7 +7140,7 @@ static expression_t *parse_call_expression(expression_t *expression) for (; argument != NULL; argument = argument->next) { type_t *argument_type = argument->expression->base.type; if (!is_type_object(skip_typeref(argument_type))) { - errorf(&argument->expression->base.source_position, + errorf(&argument->expression->base.pos, "call argument '%E' must not be void", argument->expression); } @@ -7122,7 +7153,7 @@ static expression_t *parse_call_expression(expression_t *expression) check_format(call); if (is_type_compound(skip_typeref(function_type->return_type))) { - source_position_t const *const pos = &expression->base.source_position; + position_t const *const pos = &expression->base.pos; warningf(WARN_AGGREGATE_RETURN, pos, "function call has aggregate value"); } @@ -7179,8 +7210,8 @@ static void warn_reference_address_as_bool(expression_t const* expr) { expr = get_reference_address(expr); if (expr != NULL) { - source_position_t const *const pos = &expr->base.source_position; - entity_t const *const ent = expr->reference.entity; + position_t const *const pos = &expr->base.pos; + entity_t const *const ent = expr->reference.entity; warningf(WARN_ADDRESS, pos, "the address of '%N' will always evaluate as 'true'", ent); } } @@ -7191,7 +7222,7 @@ static void warn_assignment_in_condition(const expression_t *const expr) return; if (expr->base.parenthesized) return; - source_position_t const *const pos = &expr->base.source_position; + position_t const *const pos = &expr->base.pos; warningf(WARN_PARENTHESES, pos, "suggest parentheses around assignment used as truth value"); } @@ -7203,13 +7234,12 @@ static void semantic_condition(expression_t const *const expr, warn_reference_address_as_bool(expr); warn_assignment_in_condition(expr); } else if (is_type_valid(type)) { - errorf(&expr->base.source_position, - "%s must have scalar type", context); + errorf(&expr->base.pos, "%s must have scalar type", context); } } /** - * Parse a conditional expression, ie. 'expression ? ... : ...'. + * Parse a conditional expression, i.e. 'expression ? ... : ...'. * * @param expression the conditional expression */ @@ -7244,8 +7274,8 @@ static expression_t *parse_conditional_expression(expression_t *expression) type_t *const false_type = skip_typeref(orig_false_type); /* 6.5.15.3 */ - source_position_t const *const pos = &conditional->base.source_position; - type_t *result_type; + position_t const *const pos = &conditional->base.pos; + type_t *result_type; if (is_type_void(true_type) || is_type_void(false_type)) { /* ISO/IEC 14882:1998(E) §5.16:2 */ if (true_expression->kind == EXPR_UNARY_THROW) { @@ -7363,7 +7393,7 @@ static expression_t *parse_delete(void) eat(T_delete); - if (next_if('[')) { + if (accept('[')) { result->kind = EXPR_UNARY_DELETE_ARRAY; expect(']'); } @@ -7374,11 +7404,11 @@ static expression_t *parse_delete(void) type_t *const type = skip_typeref(value->base.type); if (!is_type_pointer(type)) { if (is_type_valid(type)) { - errorf(&value->base.source_position, + errorf(&value->base.pos, "operand of delete must have pointer type"); } } else if (is_type_void(skip_typeref(type->pointer.points_to))) { - source_position_t const *const pos = &value->base.source_position; + position_t const *const pos = &value->base.pos; warningf(WARN_OTHER, pos, "deleting 'void*' is undefined"); } @@ -7404,12 +7434,12 @@ static expression_t *parse_throw(void) type_t *const orig_type = value->base.type; type_t *const type = skip_typeref(orig_type); if (is_type_incomplete(type)) { - errorf(&value->base.source_position, + errorf(&value->base.pos, "cannot throw object of incomplete type '%T'", orig_type); } else if (is_type_pointer(type)) { type_t *const points_to = skip_typeref(type->pointer.points_to); if (is_type_incomplete(points_to) && !is_type_void(points_to)) { - errorf(&value->base.source_position, + errorf(&value->base.pos, "cannot throw pointer to incomplete type '%T'", orig_type); } } @@ -7423,7 +7453,7 @@ static expression_t *parse_throw(void) return result; } -static bool check_pointer_arithmetic(const source_position_t *source_position, +static bool check_pointer_arithmetic(const position_t *pos, type_t *pointer_type, type_t *orig_pointer_type) { @@ -7432,21 +7462,23 @@ static bool check_pointer_arithmetic(const source_position_t *source_position, if (is_type_incomplete(points_to)) { if (!GNU_MODE || !is_type_void(points_to)) { - errorf(source_position, + errorf(pos, "arithmetic with pointer to incomplete type '%T' not allowed", orig_pointer_type); return false; } else { - warningf(WARN_POINTER_ARITH, source_position, "pointer of type '%T' used in arithmetic", orig_pointer_type); + warningf(WARN_POINTER_ARITH, pos, "pointer of type '%T' used in arithmetic", orig_pointer_type); } } else if (is_type_function(points_to)) { if (!GNU_MODE) { - errorf(source_position, + errorf(pos, "arithmetic with pointer to function type '%T' not allowed", orig_pointer_type); return false; } else { - warningf(WARN_POINTER_ARITH, source_position, "pointer to a function '%T' used in arithmetic", orig_pointer_type); + warningf(WARN_POINTER_ARITH, pos, + "pointer to a function '%T' used in arithmetic", + orig_pointer_type); } } return true; @@ -7478,29 +7510,38 @@ static bool is_lvalue(const expression_t *expression) static void semantic_incdec(unary_expression_t *expression) { - type_t *const orig_type = expression->value->base.type; - type_t *const type = skip_typeref(orig_type); + type_t *orig_type = expression->value->base.type; + type_t *type = skip_typeref(orig_type); if (is_type_pointer(type)) { - if (!check_pointer_arithmetic(&expression->base.source_position, - type, orig_type)) { + if (!check_pointer_arithmetic(&expression->base.pos, type, orig_type)) { return; } - } else if (!is_type_real(type) && is_type_valid(type)) { + } else if (!is_type_real(type) && + (!GNU_MODE || !is_type_complex(type)) && is_type_valid(type)) { /* TODO: improve error message */ - errorf(&expression->base.source_position, + errorf(&expression->base.pos, "operation needs an arithmetic or pointer type"); - return; + orig_type = type = type_error_type; } if (!is_lvalue(expression->value)) { /* TODO: improve error message */ - errorf(&expression->base.source_position, "lvalue required as operand"); + errorf(&expression->base.pos, "lvalue required as operand"); } expression->base.type = orig_type; } static void promote_unary_int_expr(unary_expression_t *const expr, type_t *const type) { - type_t *const res_type = promote_integer(type); + atomic_type_kind_t akind = get_arithmetic_akind(type); + type_t *res_type; + if (get_akind_rank(akind) < get_akind_rank(ATOMIC_TYPE_INT)) { + if (type->kind == TYPE_COMPLEX) + res_type = make_complex_type(ATOMIC_TYPE_INT, TYPE_QUALIFIER_NONE); + else + res_type = type_int; + } else { + res_type = type; + } expr->base.type = res_type; expr->value = create_implicit_cast(expr->value, res_type); } @@ -7511,9 +7552,8 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression) type_t *const type = skip_typeref(orig_type); if (!is_type_arithmetic(type)) { if (is_type_valid(type)) { - /* TODO: improve error message */ - errorf(&expression->base.source_position, - "operation needs an arithmetic type"); + position_t const *const pos = &expression->base.pos; + errorf(pos, "operand of unary expression must have arithmetic type, but is '%T'", orig_type); } return; } else if (is_type_integer(type)) { @@ -7526,7 +7566,7 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression) static void semantic_unexpr_plus(unary_expression_t *expression) { semantic_unexpr_arithmetic(expression); - source_position_t const *const pos = &expression->base.source_position; + position_t const *const pos = &expression->base.pos; warningf(WARN_TRADITIONAL, pos, "traditional C rejects the unary plus operator"); } @@ -7537,19 +7577,22 @@ static void semantic_not(unary_expression_t *expression) expression->base.type = c_mode & _CXX ? type_bool : type_int; } -static void semantic_unexpr_integer(unary_expression_t *expression) +static void semantic_complement(unary_expression_t *expression) { type_t *const orig_type = expression->value->base.type; type_t *const type = skip_typeref(orig_type); - if (!is_type_integer(type)) { + if (!is_type_integer(type) && (!GNU_MODE || !is_type_complex(type))) { if (is_type_valid(type)) { - errorf(&expression->base.source_position, - "operand of ~ must be of integer type"); + errorf(&expression->base.pos, "operand of ~ must be of integer type"); } return; } - promote_unary_int_expr(expression, type); + if (is_type_integer(type)) { + promote_unary_int_expr(expression, type); + } else { + expression->base.type = orig_type; + } } static void semantic_dereference(unary_expression_t *expression) @@ -7558,7 +7601,7 @@ static void semantic_dereference(unary_expression_t *expression) type_t *const type = skip_typeref(orig_type); if (!is_type_pointer(type)) { if (is_type_valid(type)) { - errorf(&expression->base.source_position, + errorf(&expression->base.pos, "Unary '*' needs pointer or array type, but type '%T' given", orig_type); } return; @@ -7587,7 +7630,7 @@ static void set_address_taken(expression_t *expression, bool may_be_register) if (entity->declaration.storage_class == STORAGE_CLASS_REGISTER && !may_be_register) { - source_position_t const *const pos = &expression->base.source_position; + position_t const *const pos = &expression->base.pos; errorf(pos, "address of register '%N' requested", entity); } @@ -7609,11 +7652,10 @@ static void semantic_take_addr(unary_expression_t *expression) /* §6.5.3.2 */ if (!is_lvalue(value)) { - errorf(&expression->base.source_position, "'&' requires an lvalue"); + errorf(&expression->base.pos, "'&' requires an lvalue"); } if (is_bitfield(value)) { - errorf(&expression->base.source_position, - "'&' not allowed on bitfield"); + errorf(&expression->base.pos, "'&' not allowed on bitfield"); } set_address_taken(value, false); @@ -7644,8 +7686,8 @@ CREATE_UNARY_EXPRESSION_PARSER('*', EXPR_UNARY_DEREFERENCE, semantic_dereference) CREATE_UNARY_EXPRESSION_PARSER('&', EXPR_UNARY_TAKE_ADDRESS, semantic_take_addr) -CREATE_UNARY_EXPRESSION_PARSER('~', EXPR_UNARY_BITWISE_NEGATE, - semantic_unexpr_integer) +CREATE_UNARY_EXPRESSION_PARSER('~', EXPR_UNARY_COMPLEMENT, + semantic_complement) CREATE_UNARY_EXPRESSION_PARSER(T_PLUSPLUS, EXPR_UNARY_PREFIX_INCREMENT, semantic_incdec) CREATE_UNARY_EXPRESSION_PARSER(T_MINUSMINUS, EXPR_UNARY_PREFIX_DECREMENT, @@ -7672,67 +7714,78 @@ CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(T_MINUSMINUS, EXPR_UNARY_POSTFIX_DECREMENT, semantic_incdec) -static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right) +static atomic_type_kind_t semantic_arithmetic_(atomic_type_kind_t kind_left, + atomic_type_kind_t kind_right) { - /* TODO: handle complex + imaginary types */ - - type_left = get_unqualified_type(type_left); - type_right = get_unqualified_type(type_right); - /* §6.3.1.8 Usual arithmetic conversions */ - if (type_left == type_long_double || type_right == type_long_double) { - return type_long_double; - } else if (type_left == type_double || type_right == type_double) { - return type_double; - } else if (type_left == type_float || type_right == type_float) { - return type_float; - } - - type_left = promote_integer(type_left); - type_right = promote_integer(type_right); - - if (type_left == type_right) - return type_left; - - bool const signed_left = is_type_signed(type_left); - bool const signed_right = is_type_signed(type_right); - unsigned const rank_left = get_akind_rank(get_akind(type_left)); - unsigned const rank_right = get_akind_rank(get_akind(type_right)); - + if (kind_left == ATOMIC_TYPE_LONG_DOUBLE + || kind_right == ATOMIC_TYPE_LONG_DOUBLE) { + return ATOMIC_TYPE_LONG_DOUBLE; + } else if (kind_left == ATOMIC_TYPE_DOUBLE + || kind_right == ATOMIC_TYPE_DOUBLE) { + return ATOMIC_TYPE_DOUBLE; + } else if (kind_left == ATOMIC_TYPE_FLOAT + || kind_right == ATOMIC_TYPE_FLOAT) { + return ATOMIC_TYPE_FLOAT; + } + + unsigned rank_left = get_akind_rank(kind_left); + unsigned rank_right = get_akind_rank(kind_right); + unsigned const rank_int = get_akind_rank(ATOMIC_TYPE_INT); + if (rank_left < rank_int) { + kind_left = ATOMIC_TYPE_INT; + rank_left = rank_int; + } + if (rank_right < rank_int) { + kind_right = ATOMIC_TYPE_INT; + rank_right = rank_int; + } + if (kind_left == kind_right) + return kind_left; + + bool const signed_left = is_akind_signed(kind_left); + bool const signed_right = is_akind_signed(kind_right); if (signed_left == signed_right) - return rank_left >= rank_right ? type_left : type_right; + return rank_left >= rank_right ? kind_left : kind_right; unsigned s_rank; unsigned u_rank; - atomic_type_kind_t s_akind; - atomic_type_kind_t u_akind; - type_t *s_type; - type_t *u_type; + atomic_type_kind_t s_kind; + atomic_type_kind_t u_kind; if (signed_left) { - s_type = type_left; - u_type = type_right; + s_kind = kind_left; + s_rank = rank_left; + u_kind = kind_right; + u_rank = rank_right; } else { - s_type = type_right; - u_type = type_left; + s_kind = kind_right; + s_rank = rank_right; + u_kind = kind_left; + u_rank = rank_left; } - s_akind = get_akind(s_type); - u_akind = get_akind(u_type); - s_rank = get_akind_rank(s_akind); - u_rank = get_akind_rank(u_akind); - if (u_rank >= s_rank) - return u_type; - - if (get_atomic_type_size(s_akind) > get_atomic_type_size(u_akind)) - return s_type; + return u_kind; + if (get_atomic_type_size(s_kind) > get_atomic_type_size(u_kind)) + return s_kind; + + switch (s_kind) { + case ATOMIC_TYPE_INT: return ATOMIC_TYPE_UINT; + case ATOMIC_TYPE_LONG: return ATOMIC_TYPE_ULONG; + case ATOMIC_TYPE_LONGLONG: return ATOMIC_TYPE_ULONGLONG; + default: panic("invalid atomic type"); + } +} - switch (s_akind) { - case ATOMIC_TYPE_INT: return type_unsigned_int; - case ATOMIC_TYPE_LONG: return type_unsigned_long; - case ATOMIC_TYPE_LONGLONG: return type_unsigned_long_long; +static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right) +{ + atomic_type_kind_t kind_left = get_arithmetic_akind(type_left); + atomic_type_kind_t kind_right = get_arithmetic_akind(type_right); + atomic_type_kind_t kind_res = semantic_arithmetic_(kind_left, kind_right); - default: panic("invalid atomic type"); + if (type_left->kind == TYPE_COMPLEX || type_right->kind == TYPE_COMPLEX) { + return make_complex_type(kind_res, TYPE_QUALIFIER_NONE); } + return make_atomic_type(kind_res, TYPE_QUALIFIER_NONE); } /** @@ -7748,10 +7801,9 @@ static void semantic_binexpr_arithmetic(binary_expression_t *expression) type_t *const type_right = skip_typeref(orig_type_right); if (!is_type_arithmetic(type_left) || !is_type_arithmetic(type_right)) { - /* TODO: improve error message */ if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(&expression->base.source_position, - "operation needs arithmetic types"); + position_t const *const pos = &expression->base.pos; + errorf(pos, "operands of binary expression must have arithmetic types, but are '%T' and '%T'", orig_type_left, orig_type_right); } return; } @@ -7771,11 +7823,11 @@ static void semantic_binexpr_integer(binary_expression_t *const expression) type_t *const type_left = skip_typeref(orig_type_left); type_t *const type_right = skip_typeref(orig_type_right); - if (!is_type_integer(type_left) || !is_type_integer(type_right)) { - /* TODO: improve error message */ + if (!is_type_integer(type_left) || !is_type_integer(type_right) + || is_type_complex(type_left) || is_type_complex(type_right)) { if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(&expression->base.source_position, - "operation needs integer types"); + position_t const *const pos = &expression->base.pos; + errorf(pos, "operands of binary expression must have integer types, but are '%T' and '%T'", orig_type_left, orig_type_right); } return; } @@ -7793,23 +7845,32 @@ 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) == EXPR_CLASS_CONSTANT && + if (is_type_integer(skip_typeref(right->base.type)) && + is_constant_expression(right) >= EXPR_CLASS_CONSTANT && !fold_constant_to_bool(right)) { - source_position_t const *const pos = &expression->base.source_position; + position_t const *const pos = &expression->base.pos; warningf(WARN_DIV_BY_ZERO, pos, "division by zero"); } } /** - * Check the semantic restrictions for a div/mod expression. + * Check the semantic restrictions for a div expression. */ -static void semantic_divmod_arithmetic(binary_expression_t *expression) +static void semantic_div(binary_expression_t *expression) { semantic_binexpr_arithmetic(expression); warn_div_by_zero(expression); } +/** + * Check the semantic restrictions for a mod expression. + */ +static void semantic_mod(binary_expression_t *expression) +{ + semantic_binexpr_integer(expression); + warn_div_by_zero(expression); +} + static void warn_addsub_in_shift(const expression_t *const expr) { if (expr->base.parenthesized) @@ -7822,7 +7883,7 @@ static void warn_addsub_in_shift(const expression_t *const expr) default: return; } - source_position_t const *const pos = &expr->base.source_position; + position_t const *const pos = &expr->base.pos; warningf(WARN_PARENTHESES, pos, "suggest parentheses around '%c' inside shift", op); } @@ -7836,19 +7897,18 @@ static bool semantic_shift(binary_expression_t *expression) type_t * type_right = skip_typeref(orig_type_right); if (!is_type_integer(type_left) || !is_type_integer(type_right)) { - /* TODO: improve error message */ if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(&expression->base.source_position, - "operands of shift operation must have integer types"); + position_t const *const pos = &expression->base.pos; + errorf(pos, "operands of shift expression must have integer types, but are '%T' and '%T'", orig_type_left, orig_type_right); } return false; } type_left = promote_integer(type_left); - if (is_constant_expression(right) == EXPR_CLASS_CONSTANT) { - source_position_t const *const pos = &right->base.source_position; - long const count = fold_constant_to_int(right); + if (is_constant_expression(right) >= EXPR_CLASS_CONSTANT) { + position_t const *const pos = &right->base.pos; + long const count = fold_constant_to_int(right); if (count < 0) { warningf(WARN_OTHER, pos, "shift count must be non-negative"); } else if ((unsigned long)count >= @@ -7898,15 +7958,15 @@ static void semantic_add(binary_expression_t *expression) expression->right = create_implicit_cast(right, arithmetic_type); expression->base.type = arithmetic_type; } else if (is_type_pointer(type_left) && is_type_integer(type_right)) { - check_pointer_arithmetic(&expression->base.source_position, - type_left, orig_type_left); + check_pointer_arithmetic(&expression->base.pos, type_left, + orig_type_left); expression->base.type = type_left; } else if (is_type_pointer(type_right) && is_type_integer(type_left)) { - check_pointer_arithmetic(&expression->base.source_position, - type_right, orig_type_right); + check_pointer_arithmetic(&expression->base.pos, type_right, + orig_type_right); expression->base.type = type_right; } else if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(&expression->base.source_position, + errorf(&expression->base.pos, "invalid operands to binary + ('%T', '%T')", orig_type_left, orig_type_right); } @@ -7914,13 +7974,13 @@ static void semantic_add(binary_expression_t *expression) static void semantic_sub(binary_expression_t *expression) { - expression_t *const left = expression->left; - expression_t *const right = expression->right; - type_t *const orig_type_left = left->base.type; - type_t *const orig_type_right = right->base.type; - type_t *const type_left = skip_typeref(orig_type_left); - type_t *const type_right = skip_typeref(orig_type_right); - source_position_t const *const pos = &expression->base.source_position; + expression_t *const left = expression->left; + expression_t *const right = expression->right; + type_t *const orig_type_left = left->base.type; + type_t *const orig_type_right = right->base.type; + type_t *const type_left = skip_typeref(orig_type_left); + type_t *const type_right = skip_typeref(orig_type_right); + position_t const *const pos = &expression->base.pos; /* §5.6.5 */ if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) { @@ -7929,8 +7989,8 @@ static void semantic_sub(binary_expression_t *expression) expression->right = create_implicit_cast(right, arithmetic_type); expression->base.type = arithmetic_type; } else if (is_type_pointer(type_left) && is_type_integer(type_right)) { - check_pointer_arithmetic(&expression->base.source_position, - type_left, orig_type_left); + check_pointer_arithmetic(&expression->base.pos, type_left, + orig_type_left); expression->base.type = type_left; } else if (is_type_pointer(type_left) && is_type_pointer(type_right)) { type_t *const unqual_left = get_unqualified_type(skip_typeref(type_left->pointer.points_to)); @@ -7964,7 +8024,7 @@ static void warn_string_literal_address(expression_t const* expr) } if (expr->kind == EXPR_STRING_LITERAL) { - source_position_t const *const pos = &expr->base.source_position; + position_t const *const pos = &expr->base.pos; warningf(WARN_ADDRESS, pos, "comparison with string literal results in unspecified behaviour"); } } @@ -7972,13 +8032,15 @@ static void warn_string_literal_address(expression_t const* expr) static bool maybe_negative(expression_t const *const expr) { switch (is_constant_expression(expr)) { - case EXPR_CLASS_ERROR: return false; - case EXPR_CLASS_CONSTANT: return constant_is_negative(expr); - default: return true; + case EXPR_CLASS_VARIABLE: return true; + case EXPR_CLASS_ERROR: return false; + case EXPR_CLASS_CONSTANT: + case EXPR_CLASS_INTEGER_CONSTANT: return constant_is_negative(expr); } + panic("invalid expression classification"); } -static void warn_comparison(source_position_t const *const pos, expression_t const *const expr, expression_t const *const other) +static void warn_comparison(position_t const *const pos, expression_t const *const expr, expression_t const *const other) { warn_string_literal_address(expr); @@ -8006,14 +8068,13 @@ static void warn_comparison(source_position_t const *const pos, expression_t con /** * Check the semantics of comparison expressions. - * - * @param expression The expression to check. */ -static void semantic_comparison(binary_expression_t *expression) +static void semantic_comparison(binary_expression_t *expression, + bool is_relational) { - source_position_t const *const pos = &expression->base.source_position; - expression_t *const left = expression->left; - expression_t *const right = expression->right; + position_t const *const pos = &expression->base.pos; + expression_t *const left = expression->left; + expression_t *const right = expression->right; warn_comparison(pos, left, right); warn_comparison(pos, right, left); @@ -8041,14 +8102,17 @@ static void semantic_comparison(binary_expression_t *expression) } } - expression->left = create_implicit_cast(left, arithmetic_type); - expression->right = create_implicit_cast(right, arithmetic_type); - expression->base.type = arithmetic_type; - if ((expression->base.kind == EXPR_BINARY_EQUAL || - expression->base.kind == EXPR_BINARY_NOTEQUAL) && - is_type_float(arithmetic_type)) { + expression->left = create_implicit_cast(left, arithmetic_type); + expression->right = create_implicit_cast(right, arithmetic_type); + expression->base.type = arithmetic_type; + if (!is_relational && is_type_float(arithmetic_type)) { warningf(WARN_FLOAT_EQUAL, pos, "comparing floating point with == or != is unsafe"); } + /* for relational ops we need real types, not just arithmetic */ + if (is_relational + && (!is_type_real(type_left) || !is_type_real(type_right))) { + type_error_incompatible("invalid operands for relational operator", pos, type_left, type_right); + } } else if (is_type_pointer(type_left) && is_type_pointer(type_right)) { /* TODO check compatibility */ } else if (is_type_pointer(type_left)) { @@ -8061,6 +8125,16 @@ static void semantic_comparison(binary_expression_t *expression) expression->base.type = c_mode & _CXX ? type_bool : type_int; } +static void semantic_relational(binary_expression_t *expression) +{ + semantic_comparison(expression, true); +} + +static void semantic_equality(binary_expression_t *expression) +{ + semantic_comparison(expression, false); +} + /** * Checks if a compound type has constant fields. */ @@ -8087,33 +8161,34 @@ static bool is_valid_assignment_lhs(expression_t const* const left) type_t *const type_left = skip_typeref(orig_type_left); if (!is_lvalue(left)) { - errorf(&left->base.source_position, "left hand side '%E' of assignment is not an lvalue", - left); + errorf(&left->base.pos, + "left hand side '%E' of assignment is not an lvalue", left); return false; } if (left->kind == EXPR_REFERENCE && left->reference.entity->kind == ENTITY_FUNCTION) { - errorf(&left->base.source_position, "cannot assign to function '%E'", left); + errorf(&left->base.pos, "cannot assign to function '%E'", left); return false; } if (is_type_array(type_left)) { - errorf(&left->base.source_position, "cannot assign to array '%E'", left); + errorf(&left->base.pos, "cannot assign to array '%E'", left); return false; } if (type_left->base.qualifiers & TYPE_QUALIFIER_CONST) { - errorf(&left->base.source_position, "assignment to read-only location '%E' (type '%T')", left, + errorf(&left->base.pos, + "assignment to read-only location '%E' (type '%T')", left, orig_type_left); return false; } if (is_type_incomplete(type_left)) { - errorf(&left->base.source_position, "left-hand side '%E' of assignment has incomplete type '%T'", + errorf(&left->base.pos, "left-hand side '%E' of assignment has incomplete type '%T'", left, orig_type_left); return false; } if (is_type_compound(type_left) && has_const_fields(&type_left->compound)) { - errorf(&left->base.source_position, "cannot assign to '%E' because compound type '%T' has read-only fields", + errorf(&left->base.pos, "cannot assign to '%E' because compound type '%T' has read-only fields", left, orig_type_left); return false; } @@ -8137,8 +8212,7 @@ static void semantic_arithmetic_assign(binary_expression_t *expression) if (!is_type_arithmetic(type_left) || !is_type_arithmetic(type_right)) { /* TODO: improve error message */ if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(&expression->base.source_position, - "operation needs arithmetic types"); + errorf(&expression->base.pos, "operation needs arithmetic types"); } return; } @@ -8179,11 +8253,11 @@ static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression) expression->right = create_implicit_cast(right, arithmetic_type); expression->base.type = type_left; } else if (is_type_pointer(type_left) && is_type_integer(type_right)) { - check_pointer_arithmetic(&expression->base.source_position, - type_left, orig_type_left); + check_pointer_arithmetic(&expression->base.pos, type_left, + orig_type_left); expression->base.type = type_left; } else if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(&expression->base.source_position, + errorf(&expression->base.pos, "incompatible types '%T' and '%T' in assignment", orig_type_left, orig_type_right); } @@ -8205,8 +8279,7 @@ static void semantic_integer_assign(binary_expression_t *expression) if (!is_type_integer(type_left) || !is_type_integer(type_right)) { /* TODO: improve error message */ if (is_type_valid(type_left) && is_type_valid(type_right)) { - errorf(&expression->base.source_position, - "operation needs integer types"); + errorf(&expression->base.pos, "operation needs integer types"); } return; } @@ -8239,7 +8312,7 @@ static void warn_logical_and_within_or(const expression_t *const expr) return; if (expr->base.parenthesized) return; - source_position_t const *const pos = &expr->base.source_position; + position_t const *const pos = &expr->base.pos; warningf(WARN_PARENTHESES, pos, "suggest parentheses around && within ||"); } @@ -8272,7 +8345,7 @@ static void semantic_binexpr_assign(binary_expression_t *expression) assign_error_t error = semantic_assign(orig_type_left, expression->right); report_assign_error(error, orig_type_left, expression->right, - "assignment", &left->base.source_position); + "assignment", &left->base.pos); expression->right = create_implicit_cast(expression->right, orig_type_left); expression->base.type = orig_type_left; } @@ -8344,10 +8417,12 @@ static bool expression_has_effect(const expression_t *const expr) case EXPR_UNARY_NEGATE: return false; case EXPR_UNARY_PLUS: return false; - case EXPR_UNARY_BITWISE_NEGATE: return false; + case EXPR_UNARY_COMPLEMENT: return false; case EXPR_UNARY_NOT: return false; case EXPR_UNARY_DEREFERENCE: return false; case EXPR_UNARY_TAKE_ADDRESS: return false; + case EXPR_UNARY_REAL: return false; + case EXPR_UNARY_IMAG: return false; case EXPR_UNARY_POSTFIX_INCREMENT: return true; case EXPR_UNARY_POSTFIX_DECREMENT: return true; case EXPR_UNARY_PREFIX_INCREMENT: return true; @@ -8418,7 +8493,7 @@ static void semantic_comma(binary_expression_t *expression) { const expression_t *const left = expression->left; if (!expression_has_effect(left)) { - source_position_t const *const pos = &left->base.source_position; + position_t const *const pos = &left->base.pos; warningf(WARN_UNUSED_VALUE, pos, "left-hand operand of comma expression has no effect"); } expression->base.type = expression->right->base.type; @@ -8443,18 +8518,18 @@ static expression_t *parse_##binexpression_type(expression_t *left) \ } CREATE_BINEXPR_PARSER('*', EXPR_BINARY_MUL, PREC_CAST, semantic_binexpr_arithmetic) -CREATE_BINEXPR_PARSER('/', EXPR_BINARY_DIV, PREC_CAST, semantic_divmod_arithmetic) -CREATE_BINEXPR_PARSER('%', EXPR_BINARY_MOD, PREC_CAST, semantic_divmod_arithmetic) +CREATE_BINEXPR_PARSER('/', EXPR_BINARY_DIV, PREC_CAST, semantic_div) +CREATE_BINEXPR_PARSER('%', EXPR_BINARY_MOD, PREC_CAST, semantic_mod) CREATE_BINEXPR_PARSER('+', EXPR_BINARY_ADD, PREC_MULTIPLICATIVE, semantic_add) CREATE_BINEXPR_PARSER('-', EXPR_BINARY_SUB, PREC_MULTIPLICATIVE, semantic_sub) CREATE_BINEXPR_PARSER(T_LESSLESS, EXPR_BINARY_SHIFTLEFT, PREC_ADDITIVE, semantic_shift_op) CREATE_BINEXPR_PARSER(T_GREATERGREATER, EXPR_BINARY_SHIFTRIGHT, PREC_ADDITIVE, semantic_shift_op) -CREATE_BINEXPR_PARSER('<', EXPR_BINARY_LESS, PREC_SHIFT, semantic_comparison) -CREATE_BINEXPR_PARSER('>', EXPR_BINARY_GREATER, PREC_SHIFT, semantic_comparison) -CREATE_BINEXPR_PARSER(T_LESSEQUAL, EXPR_BINARY_LESSEQUAL, PREC_SHIFT, semantic_comparison) -CREATE_BINEXPR_PARSER(T_GREATEREQUAL, EXPR_BINARY_GREATEREQUAL, PREC_SHIFT, semantic_comparison) -CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, EXPR_BINARY_NOTEQUAL, PREC_RELATIONAL, semantic_comparison) -CREATE_BINEXPR_PARSER(T_EQUALEQUAL, EXPR_BINARY_EQUAL, PREC_RELATIONAL, semantic_comparison) +CREATE_BINEXPR_PARSER('<', EXPR_BINARY_LESS, PREC_SHIFT, semantic_relational) +CREATE_BINEXPR_PARSER('>', EXPR_BINARY_GREATER, PREC_SHIFT, semantic_relational) +CREATE_BINEXPR_PARSER(T_LESSEQUAL, EXPR_BINARY_LESSEQUAL, PREC_SHIFT, semantic_relational) +CREATE_BINEXPR_PARSER(T_GREATEREQUAL, EXPR_BINARY_GREATEREQUAL, PREC_SHIFT, semantic_relational) +CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, EXPR_BINARY_NOTEQUAL, PREC_RELATIONAL, semantic_equality) +CREATE_BINEXPR_PARSER(T_EQUALEQUAL, EXPR_BINARY_EQUAL, PREC_RELATIONAL, semantic_equality) CREATE_BINEXPR_PARSER('&', EXPR_BINARY_BITWISE_AND, PREC_EQUALITY, semantic_binexpr_integer) CREATE_BINEXPR_PARSER('^', EXPR_BINARY_BITWISE_XOR, PREC_AND, semantic_binexpr_integer) CREATE_BINEXPR_PARSER('|', EXPR_BINARY_BITWISE_OR, PREC_XOR, semantic_binexpr_integer) @@ -8590,13 +8665,13 @@ static void init_expression_parsers(void) register_expression_parser(parse_EXPR_UNARY_NEGATE, '-'); register_expression_parser(parse_EXPR_UNARY_PLUS, '+'); register_expression_parser(parse_EXPR_UNARY_NOT, '!'); - register_expression_parser(parse_EXPR_UNARY_BITWISE_NEGATE, '~'); + register_expression_parser(parse_EXPR_UNARY_COMPLEMENT, '~'); register_expression_parser(parse_EXPR_UNARY_DEREFERENCE, '*'); register_expression_parser(parse_EXPR_UNARY_TAKE_ADDRESS, '&'); register_expression_parser(parse_EXPR_UNARY_PREFIX_INCREMENT, T_PLUSPLUS); register_expression_parser(parse_EXPR_UNARY_PREFIX_DECREMENT, T_MINUSMINUS); register_expression_parser(parse_sizeof, T_sizeof); - register_expression_parser(parse_alignof, T___alignof__); + register_expression_parser(parse_alignof, T__Alignof); register_expression_parser(parse_extension, T___extension__); register_expression_parser(parse_builtin_classify_type, T___builtin_classify_type); register_expression_parser(parse_delete, T_delete); @@ -8606,120 +8681,132 @@ static void init_expression_parsers(void) /** * Parse a asm statement arguments specification. */ -static asm_argument_t *parse_asm_arguments(bool is_out) +static void parse_asm_arguments(asm_argument_t **anchor, bool const is_out) { - asm_argument_t *result = NULL; - asm_argument_t **anchor = &result; + if (token.kind == T_STRING_LITERAL || token.kind == '[') { + add_anchor_token(','); + do { + asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0])); - while (token.kind == T_STRING_LITERAL || token.kind == '[') { - asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0])); + add_anchor_token(')'); + add_anchor_token('('); + add_anchor_token(T_STRING_LITERAL); - if (next_if('[')) { - add_anchor_token(']'); - argument->symbol = expect_identifier("while parsing asm argument", NULL); - rem_anchor_token(']'); - expect(']'); - if (!argument->symbol) - return NULL; - } - - argument->constraints = parse_string_literals("asm argument"); - add_anchor_token(')'); - expect('('); - expression_t *expression = parse_expression(); - rem_anchor_token(')'); - if (is_out) { - /* Ugly GCC stuff: Allow lvalue casts. Skip casts, when they do not - * change size or type representation (e.g. int -> long is ok, but - * int -> float is not) */ - if (expression->kind == EXPR_UNARY_CAST) { - type_t *const type = expression->base.type; - type_kind_t const kind = type->kind; - if (kind == TYPE_ATOMIC || kind == TYPE_POINTER) { - unsigned flags; - unsigned size; - if (kind == TYPE_ATOMIC) { - atomic_type_kind_t const akind = type->atomic.akind; - flags = get_atomic_type_flags(akind) & ~ATOMIC_TYPE_FLAG_SIGNED; - size = get_atomic_type_size(akind); - } else { - flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC; - size = get_type_size(type_void_ptr); - } + if (accept('[')) { + add_anchor_token(']'); + argument->symbol = expect_identifier("while parsing asm argument", NULL); + rem_anchor_token(']'); + expect(']'); + } - do { - expression_t *const value = expression->unary.value; - type_t *const value_type = value->base.type; - type_kind_t const value_kind = value_type->kind; - - unsigned value_flags; - unsigned value_size; - if (value_kind == TYPE_ATOMIC) { - atomic_type_kind_t const value_akind = value_type->atomic.akind; - value_flags = get_atomic_type_flags(value_akind) & ~ATOMIC_TYPE_FLAG_SIGNED; - value_size = get_atomic_type_size(value_akind); - } else if (value_kind == TYPE_POINTER) { - value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC; - value_size = get_type_size(type_void_ptr); + rem_anchor_token(T_STRING_LITERAL); + argument->constraints = parse_string_literals("asm argument"); + rem_anchor_token('('); + expect('('); + expression_t *expression = parse_expression(); + if (is_out) { + /* Ugly GCC stuff: Allow lvalue casts. Skip casts, when they do not + * change size or type representation (e.g. int -> long is ok, but + * int -> float is not) */ + if (expression->kind == EXPR_UNARY_CAST) { + type_t *const type = expression->base.type; + type_kind_t const kind = type->kind; + if (kind == TYPE_ATOMIC || kind == TYPE_POINTER) { + unsigned flags; + unsigned size; + if (kind == TYPE_ATOMIC) { + atomic_type_kind_t const akind = type->atomic.akind; + flags = get_atomic_type_flags(akind) & ~ATOMIC_TYPE_FLAG_SIGNED; + size = get_atomic_type_size(akind); } else { - break; + flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC; + size = get_type_size(type_void_ptr); } - if (value_flags != flags || value_size != size) - break; + do { + expression_t *const value = expression->unary.value; + type_t *const value_type = value->base.type; + type_kind_t const value_kind = value_type->kind; + + unsigned value_flags; + unsigned value_size; + if (value_kind == TYPE_ATOMIC) { + atomic_type_kind_t const value_akind = value_type->atomic.akind; + value_flags = get_atomic_type_flags(value_akind) & ~ATOMIC_TYPE_FLAG_SIGNED; + value_size = get_atomic_type_size(value_akind); + } else if (value_kind == TYPE_POINTER) { + value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC; + value_size = get_type_size(type_void_ptr); + } else { + break; + } - expression = value; - } while (expression->kind == EXPR_UNARY_CAST); + if (value_flags != flags || value_size != size) + break; + + expression = value; + } while (expression->kind == EXPR_UNARY_CAST); + } } - } - if (!is_lvalue(expression)) { - errorf(&expression->base.source_position, - "asm output argument is not an lvalue"); - } + if (!is_lvalue(expression)) + errorf(&expression->base.pos, + "asm output argument is not an lvalue"); - if (argument->constraints.begin[0] == '=') - determine_lhs_ent(expression, NULL); - else + if (argument->constraints.begin[0] == '=') + determine_lhs_ent(expression, NULL); + else + mark_vars_read(expression, NULL); + } else { mark_vars_read(expression, NULL); - } else { - mark_vars_read(expression, NULL); - } - argument->expression = expression; - expect(')'); + } + argument->expression = expression; + rem_anchor_token(')'); + expect(')'); - set_address_taken(expression, true); + set_address_taken(expression, true); - *anchor = argument; - anchor = &argument->next; - - if (!next_if(',')) - break; + *anchor = argument; + anchor = &argument->next; + } while (accept(',')); + rem_anchor_token(','); } - - return result; } /** * Parse a asm statement clobber specification. */ -static asm_clobber_t *parse_asm_clobbers(void) +static void parse_asm_clobbers(asm_clobber_t **anchor) { - asm_clobber_t *result = NULL; - asm_clobber_t **anchor = &result; + if (token.kind == T_STRING_LITERAL) { + add_anchor_token(','); + do { + asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0])); + clobber->clobber = parse_string_literals(NULL); - while (token.kind == T_STRING_LITERAL) { - asm_clobber_t *clobber = allocate_ast_zero(sizeof(clobber[0])); - clobber->clobber = parse_string_literals(NULL); + *anchor = clobber; + anchor = &clobber->next; + } while (accept(',')); + rem_anchor_token(','); + } +} - *anchor = clobber; - anchor = &clobber->next; +static void parse_asm_labels(asm_label_t **anchor) +{ + if (token.kind == T_IDENTIFIER) { + add_anchor_token(','); + do { + label_t *const label = get_label("while parsing 'asm goto' labels"); + if (label) { + asm_label_t *const asm_label = allocate_ast_zero(sizeof(*asm_label)); + asm_label->label = label; - if (!next_if(',')) - break; + *anchor = asm_label; + anchor = &asm_label->next; + } + } while (accept(',')); + rem_anchor_token(','); } - - return result; } /** @@ -8735,22 +8822,30 @@ static statement_t *parse_asm_statement(void) add_anchor_token(':'); add_anchor_token(T_STRING_LITERAL); - if (next_if(T_volatile)) + if (accept(T_volatile)) asm_statement->is_volatile = true; + bool const asm_goto = accept(T_goto); + expect('('); rem_anchor_token(T_STRING_LITERAL); asm_statement->asm_text = parse_string_literals("asm statement"); - if (next_if(':')) - asm_statement->outputs = parse_asm_arguments(true); - - if (next_if(':')) - asm_statement->inputs = parse_asm_arguments(false); + if (accept(':')) parse_asm_arguments(&asm_statement->outputs, true); + if (accept(':')) parse_asm_arguments(&asm_statement->inputs, false); + if (accept(':')) parse_asm_clobbers( &asm_statement->clobbers); rem_anchor_token(':'); - if (next_if(':')) - asm_statement->clobbers = parse_asm_clobbers(); + if (accept(':')) { + if (!asm_goto) + warningf(WARN_OTHER, &statement->base.pos, "assembler statement with labels should be 'asm goto'"); + parse_asm_labels(&asm_statement->labels); + if (asm_statement->labels) + errorf(&statement->base.pos, "'asm goto' not supported"); + } else { + if (asm_goto) + warningf(WARN_OTHER, &statement->base.pos, "'asm goto' without labels"); + } rem_anchor_token(')'); expect(')'); @@ -8770,7 +8865,7 @@ static statement_t *parse_label_inner_statement(statement_t const *const label, statement_t *inner_stmt; switch (token.kind) { case '}': - errorf(&label->base.source_position, "%s at end of compound statement", label_kind); + errorf(&label->base.pos, "%s at end of compound statement", label_kind); inner_stmt = create_error_statement(); break; @@ -8790,7 +8885,7 @@ static statement_t *parse_label_inner_statement(statement_t const *const label, /* ISO/IEC 9899:1999(E) §6.8:1/6.8.2:1 Declarations are no statements */ /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */ if (inner_stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) { - errorf(&inner_stmt->base.source_position, "declaration after %s", label_kind); + errorf(&inner_stmt->base.pos, "declaration after %s", label_kind); } break; } @@ -8802,8 +8897,8 @@ static statement_t *parse_label_inner_statement(statement_t const *const label, */ static statement_t *parse_case_statement(void) { - statement_t *const statement = allocate_statement_zero(STATEMENT_CASE_LABEL); - source_position_t *const pos = &statement->base.source_position; + statement_t *const statement = allocate_statement_zero(STATEMENT_CASE_LABEL); + position_t *const pos = &statement->base.pos; eat(T_case); add_anchor_token(':'); @@ -8819,26 +8914,26 @@ static statement_t *parse_case_statement(void) type_t *type = expression_type; if (current_switch != NULL) { type_t *switch_type = current_switch->expression->base.type; - if (is_type_valid(switch_type)) { + if (is_type_valid(skip_typeref(switch_type))) { expression = create_implicit_cast(expression, switch_type); } } statement->case_label.expression = expression; expression_classification_t const expr_class = is_constant_expression(expression); - if (expr_class != EXPR_CLASS_CONSTANT) { + 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; } else { - long const val = fold_constant_to_int(expression); + ir_tarval *val = fold_constant_to_tarval(expression); statement->case_label.first_case = val; statement->case_label.last_case = val; } if (GNU_MODE) { - if (next_if(T_DOTDOTDOT)) { + if (accept(T_DOTDOTDOT)) { expression_t *end_range = parse_expression(); expression_type = expression->base.type; skipped = skip_typeref(expression_type); @@ -8850,16 +8945,17 @@ static statement_t *parse_case_statement(void) end_range = create_implicit_cast(end_range, type); statement->case_label.end_range = end_range; expression_classification_t const end_class = is_constant_expression(end_range); - if (end_class != EXPR_CLASS_CONSTANT) { + 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; } else { - long const val = fold_constant_to_int(end_range); + ir_tarval *val = fold_constant_to_tarval(end_range); statement->case_label.last_case = val; - if (val < statement->case_label.first_case) { + if (tarval_cmp(val, statement->case_label.first_case) + == ir_relation_less) { statement->case_label.is_empty_range = true; warningf(WARN_OTHER, pos, "empty range specified"); } @@ -8884,7 +8980,7 @@ static statement_t *parse_case_statement(void) continue; errorf(pos, "duplicate case value (previously used %P)", - &l->base.source_position); + &l->base.pos); break; } } @@ -8921,7 +9017,7 @@ static statement_t *parse_default_statement(void) if (current_switch != NULL) { const case_label_statement_t *def_label = current_switch->default_label; if (def_label != NULL) { - errorf(&statement->base.source_position, "multiple default labels in one switch (previous declared %P)", &def_label->base.source_position); + errorf(&statement->base.pos, "multiple default labels in one switch (previous declared %P)", &def_label->base.pos); } else { current_switch->default_label = &statement->case_label; @@ -8934,8 +9030,8 @@ static statement_t *parse_default_statement(void) current_switch->last_case = &statement->case_label; } } else { - errorf(&statement->base.source_position, - "'default' label not within a switch statement"); + errorf(&statement->base.pos, + "'default' label not within a switch statement"); } statement->case_label.statement = parse_label_inner_statement(statement, "default label"); @@ -8958,12 +9054,13 @@ static statement_t *parse_label_statement(void) /* if statement is already set then the label is defined twice, * otherwise it was just mentioned in a goto/local label declaration so far */ - source_position_t const* const pos = &statement->base.source_position; + position_t const* const pos = &statement->base.pos; if (label->statement != NULL) { - errorf(pos, "duplicate '%N' (declared %P)", (entity_t const*)label, &label->base.source_position); + errorf(pos, "duplicate '%N' (declared %P)", (entity_t const*)label, &label->base.pos); } else { - label->base.source_position = *pos; - label->statement = statement; + label->base.pos = *pos; + label->statement = statement; + label->n_users += 1; } eat(':'); @@ -8988,7 +9085,7 @@ static statement_t *parse_inner_statement(void) /* ISO/IEC 9899:1999(E) §6.8:1/6.8.2:1 Declarations are no statements */ /* ISO/IEC 14882:1998(E) §6:1/§6.7 Declarations are statements */ if (stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) { - errorf(&stmt->base.source_position, "declaration as inner statement, use {}"); + errorf(&stmt->base.pos, "declaration as inner statement, use {}"); } return stmt; } @@ -9036,7 +9133,7 @@ static statement_t *parse_if(void) "suggest braces around empty body in an ‘if’ statement"); } - if (next_if(T_else)) { + if (accept(T_else)) { statement->ifs.false_statement = parse_inner_statement(); if (statement->ifs.false_statement->kind == STATEMENT_EMPTY) { @@ -9045,7 +9142,7 @@ static statement_t *parse_if(void) } } else if (true_stmt->kind == STATEMENT_IF && true_stmt->ifs.false_statement != NULL) { - source_position_t const *const pos = &true_stmt->base.source_position; + position_t const *const pos = &true_stmt->base.pos; warningf(WARN_PARENTHESES, pos, "suggest explicit braces to avoid ambiguous 'else'"); } @@ -9063,37 +9160,40 @@ static void check_enum_cases(const switch_statement_t *statement) { if (!is_warn_on(WARN_SWITCH_ENUM)) return; - const type_t *type = skip_typeref(statement->expression->base.type); + type_t *type = skip_typeref(statement->expression->base.type); if (! is_type_enum(type)) return; - const enum_type_t *enumt = &type->enumt; + enum_type_t *enumt = &type->enumt; /* if we have a default, no warnings */ if (statement->default_label != NULL) return; + determine_enum_values(enumt); + /* FIXME: calculation of value should be done while parsing */ /* TODO: quadratic algorithm here. Change to an n log n one */ - long last_value = -1; - const entity_t *entry = enumt->enume->base.next; + const entity_t *entry = enumt->enume->base.next; for (; entry != NULL && entry->kind == ENTITY_ENUM_VALUE; entry = entry->base.next) { - const expression_t *expression = entry->enum_value.value; - long value = expression != NULL ? fold_constant_to_int(expression) : last_value + 1; - bool found = false; - for (const case_label_statement_t *l = statement->first_case; l != NULL; l = l->next) { + ir_tarval *value = entry->enum_value.tv; + bool found = false; + for (const case_label_statement_t *l = statement->first_case; l != NULL; + l = l->next) { if (l->expression == NULL) continue; - if (l->first_case <= value && value <= l->last_case) { + if (l->first_case == l->last_case && l->first_case != value) + continue; + if ((tarval_cmp(l->first_case, value) & ir_relation_less_equal) + && (tarval_cmp(value, l->last_case) & ir_relation_less_equal)) { found = true; break; } } if (!found) { - source_position_t const *const pos = &statement->base.source_position; + position_t const *const pos = &statement->base.pos; warningf(WARN_SWITCH_ENUM, pos, "'%N' not handled in switch", entry); } - last_value = value; } } @@ -9113,12 +9213,14 @@ static statement_t *parse_switch(void) type_t * type = skip_typeref(expr->base.type); if (is_type_integer(type)) { type = promote_integer(type); - if (get_akind_rank(get_akind(type)) >= get_akind_rank(ATOMIC_TYPE_LONG)) { - warningf(WARN_TRADITIONAL, &expr->base.source_position, "'%T' switch expression not converted to '%T' in ISO C", type, type_int); + if (get_akind_rank(get_arithmetic_akind(type)) >= get_akind_rank(ATOMIC_TYPE_LONG)) { + warningf(WARN_TRADITIONAL, &expr->base.pos, + "'%T' switch expression not converted to '%T' in ISO C", + type, type_int); } } else if (is_type_valid(type)) { - errorf(&expr->base.source_position, - "switch quantity is not an integer, but '%T'", type); + errorf(&expr->base.pos, "switch quantity is not an integer, but '%T'", + type); type = type_error_type; } statement->switchs.expression = create_implicit_cast(expr, type); @@ -9129,7 +9231,7 @@ static statement_t *parse_switch(void) current_switch = rem; if (statement->switchs.default_label == NULL) { - warningf(WARN_SWITCH_DEFAULT, &statement->base.source_position, "switch has no default case"); + warningf(WARN_SWITCH_DEFAULT, &statement->base.pos, "switch has no default case"); } check_enum_cases(&statement->switchs); @@ -9154,20 +9256,20 @@ static statement_t *parse_loop_body(statement_t *const loop) */ static statement_t *parse_while(void) { - statement_t *statement = allocate_statement_zero(STATEMENT_WHILE); + statement_t *statement = allocate_statement_zero(STATEMENT_FOR); eat(T_while); PUSH_PARENT(statement); - PUSH_SCOPE_STATEMENT(&statement->whiles.scope); + PUSH_SCOPE_STATEMENT(&statement->fors.scope); expression_t *const cond = parse_condition(); - statement->whiles.condition = cond; + statement->fors.condition = cond; /* §6.8.5:2 The controlling expression of an iteration statement shall * have scalar type. */ semantic_condition(cond, "condition of 'while'-statement"); - statement->whiles.body = parse_loop_body(statement); + statement->fors.body = parse_loop_body(statement); POP_SCOPE(); POP_PARENT(); @@ -9220,7 +9322,7 @@ static statement_t *parse_for(void) PUSH_EXTENSION(); - if (next_if(';')) { + if (accept(';')) { } else if (is_declaration_specifier(&token)) { parse_declaration(record_entity, DECL_FLAGS_NONE); } else { @@ -9229,7 +9331,7 @@ static statement_t *parse_for(void) statement->fors.initialisation = init; mark_vars_read(init, ENT_ANY); if (!expression_has_effect(init)) { - warningf(WARN_UNUSED_VALUE, &init->base.source_position, "initialisation of 'for'-statement has no effect"); + warningf(WARN_UNUSED_VALUE, &init->base.pos, "initialisation of 'for'-statement has no effect"); } rem_anchor_token(';'); expect(';'); @@ -9253,7 +9355,7 @@ static statement_t *parse_for(void) statement->fors.step = step; mark_vars_read(step, ENT_ANY); if (!expression_has_effect(step)) { - warningf(WARN_UNUSED_VALUE, &step->base.source_position, "step of 'for'-statement has no effect"); + warningf(WARN_UNUSED_VALUE, &step->base.pos, "step of 'for'-statement has no effect"); } } rem_anchor_token(')'); @@ -9285,10 +9387,9 @@ static statement_t *parse_goto(void) if (type != type_error_type) { if (!is_type_pointer(type) && !is_type_integer(type)) { - errorf(&expression->base.source_position, - "cannot convert to a pointer type"); + errorf(&expression->base.pos, "cannot convert to a pointer type"); } else if (type != type_void_ptr) { - warningf(WARN_OTHER, &expression->base.source_position, "type of computed goto expression should be 'void*' not '%T'", type); + warningf(WARN_OTHER, &expression->base.pos, "type of computed goto expression should be 'void*' not '%T'", type); } expression = create_implicit_cast(expression, type_void_ptr); } @@ -9300,6 +9401,7 @@ static statement_t *parse_goto(void) label_t *const label = get_label("while parsing goto"); if (label) { + label->n_users += 1; label->used = true; statement->gotos.label = label; @@ -9307,7 +9409,7 @@ static statement_t *parse_goto(void) *goto_anchor = &statement->gotos; goto_anchor = &statement->gotos.next; } else { - statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous, &builtin_source_position)->label; + statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous, &builtin_position)->label; } } @@ -9398,7 +9500,7 @@ static bool expression_is_local_variable(const expression_t *expression) return is_local_variable(entity); } -static void err_or_warn(source_position_t const *const pos, char const *const msg) +static void err_or_warn(position_t const *const pos, char const *const msg) { if (c_mode & _CXX || strict_mode) { errorf(pos, msg); @@ -9425,7 +9527,7 @@ static statement_t *parse_return(void) assert(is_type_function(func_type)); type_t *const return_type = skip_typeref(func_type->function.return_type); - source_position_t const *const pos = &statement->base.source_position; + position_t const *const pos = &statement->base.pos; if (return_value != NULL) { type_t *return_value_type = skip_typeref(return_value->base.type); @@ -9485,7 +9587,7 @@ static statement_t *parse_declaration_statement(void) } /** - * Parse an expression statement, ie. expr ';'. + * Parse an expression statement, i.e. expr ';'. */ static statement_t *parse_expression_statement(void) { @@ -9517,18 +9619,18 @@ static statement_t *parse_ms_try_statment(void) POP_PARENT(); - if (next_if(T___except)) { + if (accept(T___except)) { expression_t *const expr = parse_condition(); type_t * type = skip_typeref(expr->base.type); if (is_type_integer(type)) { type = promote_integer(type); } else if (is_type_valid(type)) { - errorf(&expr->base.source_position, + errorf(&expr->base.pos, "__expect expression is not an integer, but '%T'", type); type = type_error_type; } statement->ms_try.except_expression = create_implicit_cast(expr, type); - } else if (!next_if(T__finally)) { + } else if (!accept(T__finally)) { parse_error_expected("while parsing __try statement", T___except, T___finally, NULL); } statement->ms_try.final_statement = parse_compound_statement(false); @@ -9555,12 +9657,12 @@ static statement_t *parse_local_label_declaration(void) add_anchor_token(';'); add_anchor_token(','); do { - source_position_t pos; + position_t pos; symbol_t *const symbol = expect_identifier("while parsing local label declaration", &pos); if (symbol) { entity_t *entity = get_entity(symbol, NAMESPACE_LABEL); if (entity != NULL && entity->base.parent_scope == current_scope) { - source_position_t const *const ppos = &entity->base.source_position; + position_t const *const ppos = &entity->base.pos; errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos); } else { entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol, &pos); @@ -9573,7 +9675,7 @@ static statement_t *parse_local_label_declaration(void) environment_push(entity); } } - } while (next_if(',')); + } while (accept(',')); rem_anchor_token(','); rem_anchor_token(';'); expect(';'); @@ -9726,7 +9828,8 @@ static statement_t *parse_statement(void) if (statement->kind == STATEMENT_EXPRESSION) { expression_t *expression = statement->expression.expression; if (!expression_has_effect(expression)) { - warningf(WARN_UNUSED_VALUE, &expression->base.source_position, "statement has no effect"); + warningf(WARN_UNUSED_VALUE, &expression->base.pos, + "statement has no effect"); } } @@ -9758,17 +9861,17 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) add_anchor_token('~'); add_anchor_token(T_CHARACTER_CONSTANT); add_anchor_token(T_COLONCOLON); - add_anchor_token(T_FLOATINGPOINT); add_anchor_token(T_IDENTIFIER); - add_anchor_token(T_INTEGER); add_anchor_token(T_MINUSMINUS); + add_anchor_token(T_NUMBER); add_anchor_token(T_PLUSPLUS); add_anchor_token(T_STRING_LITERAL); + add_anchor_token(T__Alignof); add_anchor_token(T__Bool); add_anchor_token(T__Complex); add_anchor_token(T__Imaginary); + add_anchor_token(T__Thread_local); add_anchor_token(T___PRETTY_FUNCTION__); - add_anchor_token(T___alignof__); add_anchor_token(T___attribute__); add_anchor_token(T___builtin_va_start); add_anchor_token(T___extension__); @@ -9776,7 +9879,6 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) add_anchor_token(T___imag__); add_anchor_token(T___label__); add_anchor_token(T___real__); - add_anchor_token(T___thread); add_anchor_token(T_asm); add_anchor_token(T_auto); add_anchor_token(T_bool); @@ -9843,7 +9945,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) if (sub_statement->kind != STATEMENT_DECLARATION) { only_decls_so_far = false; } else if (!only_decls_so_far) { - source_position_t const *const pos = &sub_statement->base.source_position; + position_t const *const pos = &sub_statement->base.pos; warningf(WARN_DECLARATION_AFTER_STATEMENT, pos, "ISO C90 forbids mixed declarations and code"); } @@ -9865,7 +9967,8 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) expression_t *expression = sub_statement->expression.expression; if (!expression_has_effect(expression)) { - warningf(WARN_UNUSED_VALUE, &expression->base.source_position, "statement has no effect"); + warningf(WARN_UNUSED_VALUE, &expression->base.pos, + "statement has no effect"); } } } @@ -9924,7 +10027,6 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) rem_anchor_token(T_bool); rem_anchor_token(T_auto); rem_anchor_token(T_asm); - rem_anchor_token(T___thread); rem_anchor_token(T___real__); rem_anchor_token(T___label__); rem_anchor_token(T___imag__); @@ -9932,17 +10034,17 @@ static statement_t *parse_compound_statement(bool inside_expression_statement) rem_anchor_token(T___extension__); rem_anchor_token(T___builtin_va_start); rem_anchor_token(T___attribute__); - rem_anchor_token(T___alignof__); rem_anchor_token(T___PRETTY_FUNCTION__); + rem_anchor_token(T__Thread_local); rem_anchor_token(T__Imaginary); rem_anchor_token(T__Complex); rem_anchor_token(T__Bool); + rem_anchor_token(T__Alignof); rem_anchor_token(T_STRING_LITERAL); rem_anchor_token(T_PLUSPLUS); + rem_anchor_token(T_NUMBER); rem_anchor_token(T_MINUSMINUS); - rem_anchor_token(T_INTEGER); rem_anchor_token(T_IDENTIFIER); - rem_anchor_token(T_FLOATINGPOINT); rem_anchor_token(T_COLONCOLON); rem_anchor_token(T_CHARACTER_CONSTANT); rem_anchor_token('~'); @@ -9989,13 +10091,13 @@ static void check_unused_globals(void) continue; why = WARN_UNUSED_FUNCTION; - s = entity->function.statement != NULL ? "defined" : "declared"; + s = entity->function.body != NULL ? "defined" : "declared"; } else { why = WARN_UNUSED_VARIABLE; s = "defined"; } - warningf(why, &declaration->base.source_position, "'%#N' %s but not used", entity, s); + warningf(why, &declaration->base.pos, "'%#N' %s but not used", entity, s); } } @@ -10024,8 +10126,8 @@ static void parse_linkage_specification(void) { eat(T_extern); - source_position_t const pos = *HERE; - char const *const linkage = parse_string_literals(NULL).begin; + position_t const pos = *HERE; + char const *const linkage = parse_string_literals(NULL).begin; linkage_kind_t old_linkage = current_linkage; linkage_kind_t new_linkage; @@ -10039,7 +10141,7 @@ static void parse_linkage_specification(void) } current_linkage = new_linkage; - if (next_if('{')) { + if (accept('{')) { parse_externals(); expect('}'); } else { @@ -10163,8 +10265,6 @@ void start_parsing(void) { environment_stack = NEW_ARR_F(stack_entry_t, 0); label_stack = NEW_ARR_F(stack_entry_t, 0); - error_count = 0; - warning_count = 0; print_to_file(stderr); @@ -10211,7 +10311,7 @@ static void complete_incomplete_arrays(void) if (!is_type_incomplete(type)) continue; - source_position_t const *const pos = &decl->base.source_position; + position_t const *const pos = &decl->base.pos; warningf(WARN_OTHER, pos, "array '%#N' assumed to have one element", (entity_t const*)decl); type_t *const new_type = duplicate_type(type); @@ -10227,31 +10327,31 @@ static void complete_incomplete_arrays(void) static void prepare_main_collect2(entity_t *const entity) { - PUSH_SCOPE(&entity->function.statement->compound.scope); + PUSH_SCOPE(&entity->function.body->compound.scope); // create call to __main symbol_t *symbol = symbol_table_insert("__main"); entity_t *subsubmain_ent - = create_implicit_function(symbol, &builtin_source_position); + = create_implicit_function(symbol, &builtin_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 *ref = allocate_expression_zero(EXPR_REFERENCE); + type_t *ftype = subsubmain_ent->declaration.type; + ref->base.pos = builtin_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; + expression_t *call = allocate_expression_zero(EXPR_CALL); + call->base.pos = builtin_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->base.pos = builtin_position; expr_statement->expression.expression = call; - statement_t *statement = entity->function.statement; - assert(statement->kind == STATEMENT_COMPOUND); - compound_statement_t *compounds = &statement->compound; + statement_t *const body = entity->function.body; + assert(body->kind == STATEMENT_COMPOUND); + compound_statement_t *compounds = &body->compound; expr_statement->base.next = compounds->statements; compounds->statements = expr_statement; @@ -10278,8 +10378,6 @@ void parse(void) */ void init_parser(void) { - sym_anonymous = symbol_table_insert(""); - memset(token_anchor_set, 0, sizeof(token_anchor_set)); init_expression_parsers();