X-Git-Url: http://nsz.repo.hu/git/?a=blobdiff_plain;f=parser.c;h=ad746a0b0e8a5ac54ebd2a07d388de4af030b0da;hb=9bf914ca0a1473ee629d30d8a6a65cfbd633712b;hp=23d640512feea9120287d75047884d8370c79701;hpb=e148abb62889e5c132d1686ab5bdcf3d3c5a8c18;p=cparser diff --git a/parser.c b/parser.c index 23d6405..ad746a0 100644 --- a/parser.c +++ b/parser.c @@ -284,25 +284,26 @@ static void semantic_comparison(binary_expression_t *expression); static size_t get_statement_struct_size(statement_kind_t kind) { static const size_t sizes[] = { - [STATEMENT_ERROR] = sizeof(statement_base_t), - [STATEMENT_EMPTY] = sizeof(statement_base_t), - [STATEMENT_COMPOUND] = sizeof(compound_statement_t), - [STATEMENT_RETURN] = sizeof(return_statement_t), - [STATEMENT_DECLARATION] = sizeof(declaration_statement_t), - [STATEMENT_IF] = sizeof(if_statement_t), - [STATEMENT_SWITCH] = sizeof(switch_statement_t), - [STATEMENT_EXPRESSION] = sizeof(expression_statement_t), - [STATEMENT_CONTINUE] = sizeof(statement_base_t), - [STATEMENT_BREAK] = sizeof(statement_base_t), - [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), - [STATEMENT_MS_TRY] = sizeof(ms_try_statement_t), - [STATEMENT_LEAVE] = sizeof(leave_statement_t) + [STATEMENT_ERROR] = sizeof(statement_base_t), + [STATEMENT_EMPTY] = sizeof(statement_base_t), + [STATEMENT_COMPOUND] = sizeof(compound_statement_t), + [STATEMENT_RETURN] = sizeof(return_statement_t), + [STATEMENT_DECLARATION] = sizeof(declaration_statement_t), + [STATEMENT_IF] = sizeof(if_statement_t), + [STATEMENT_SWITCH] = sizeof(switch_statement_t), + [STATEMENT_EXPRESSION] = sizeof(expression_statement_t), + [STATEMENT_CONTINUE] = sizeof(statement_base_t), + [STATEMENT_BREAK] = sizeof(statement_base_t), + [STATEMENT_COMPUTED_GOTO] = sizeof(computed_goto_statement_t), + [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), + [STATEMENT_MS_TRY] = sizeof(ms_try_statement_t), + [STATEMENT_LEAVE] = sizeof(leave_statement_t) }; assert((size_t)kind < lengthof(sizes)); assert(sizes[kind] != 0); @@ -319,7 +320,7 @@ static size_t get_expression_struct_size(expression_kind_t kind) static const size_t sizes[] = { [EXPR_ERROR] = sizeof(expression_base_t), [EXPR_REFERENCE] = sizeof(reference_expression_t), - [EXPR_REFERENCE_ENUM_VALUE] = sizeof(reference_expression_t), + [EXPR_ENUM_CONSTANT] = sizeof(reference_expression_t), [EXPR_LITERAL_BOOLEAN] = sizeof(literal_expression_t), [EXPR_LITERAL_INTEGER] = sizeof(literal_expression_t), [EXPR_LITERAL_INTEGER_OCTAL] = sizeof(literal_expression_t), @@ -998,10 +999,10 @@ static assign_error_t semantic_assign(type_t *orig_type_left, points_to_left = get_unqualified_type(points_to_left); points_to_right = get_unqualified_type(points_to_right); - if (is_type_atomic(points_to_left, ATOMIC_TYPE_VOID)) + if (is_type_void(points_to_left)) return res; - if (is_type_atomic(points_to_right, ATOMIC_TYPE_VOID)) { + if (is_type_void(points_to_right)) { /* ISO/IEC 14882:1998(E) §C.1.2:6 */ return c_mode & _CXX ? ASSIGN_ERROR_INCOMPATIBLE : res; } @@ -1440,7 +1441,7 @@ static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent) case EXPR_UNARY_CAST: /* Special case: Use void cast to mark a variable as "read" */ - if (is_type_atomic(skip_typeref(expr->base.type), ATOMIC_TYPE_VOID)) + if (is_type_void(skip_typeref(expr->base.type))) lhs_ent = NULL; goto unary; @@ -1521,7 +1522,7 @@ unary: determine_lhs_ent(expr->va_starte.ap, lhs_ent); return; - EXPR_LITERAL_CASES + case EXPR_LITERAL_CASES: case EXPR_ERROR: case EXPR_STRING_LITERAL: case EXPR_WIDE_STRING_LITERAL: @@ -1535,7 +1536,7 @@ unary: case EXPR_OFFSETOF: case EXPR_STATEMENT: // TODO case EXPR_LABEL_ADDRESS: - case EXPR_REFERENCE_ENUM_VALUE: + case EXPR_ENUM_CONSTANT: return; } @@ -1665,15 +1666,6 @@ static initializer_t *initializer_from_expression(type_t *orig_type, return result; } -/** - * Checks if a given expression can be used as a constant initializer. - */ -static bool is_initializer_constant(const expression_t *expression) -{ - return is_constant_expression(expression) != EXPR_CLASS_VARIABLE || - is_linker_constant(expression) != EXPR_CLASS_VARIABLE; -} - /** * Parses an scalar initializer. * @@ -1694,7 +1686,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_initializer_constant(expression)) { + if (must_be_constant && !is_linker_constant(expression)) { errorf(&expression->base.source_position, "initialisation expression '%E' is not constant", expression); @@ -2114,7 +2106,7 @@ finish_designator: expression_t *expression = parse_assignment_expression(); mark_vars_read(expression, NULL); - if (env->must_be_constant && !is_initializer_constant(expression)) { + if (env->must_be_constant && !is_linker_constant(expression)) { errorf(&expression->base.source_position, "Initialisation expression '%E' is not constant", expression); @@ -3216,6 +3208,8 @@ static void semantic_parameter_incomplete(const entity_t *entity) static bool has_parameters(void) { /* func(void) is not a parameter */ + if (look_ahead(1)->kind != ')') + return true; if (token.kind == T_IDENTIFIER) { entity_t const *const entity = get_entity(token.identifier.symbol, NAMESPACE_NORMAL); @@ -3223,13 +3217,16 @@ static bool has_parameters(void) return true; if (entity->kind != ENTITY_TYPEDEF) return true; - if (skip_typeref(entity->typedefe.type) != type_void) + type_t const *const type = skip_typeref(entity->typedefe.type); + if (!is_type_void(type)) return true; + if (type->base.qualifiers != TYPE_QUALIFIER_NONE) { + /* §6.7.5.3:10 Qualification is not allowed here. */ + errorf(HERE, "'void' as parameter must not have type qualifiers"); + } } else if (token.kind != T_void) { return true; } - if (look_ahead(1)->kind != ')') - return true; next_token(); return false; } @@ -4629,10 +4626,6 @@ static void check_labels(void) for (const goto_statement_t *goto_statement = goto_first; goto_statement != NULL; goto_statement = goto_statement->next) { - /* skip computed gotos */ - if (goto_statement->expression != NULL) - continue; - label_t *label = goto_statement->label; if (label->base.source_position.input_name == NULL) { print_in_function(); @@ -4732,10 +4725,12 @@ static bool expression_returns(expression_t const *const expr) switch (expr->kind) { case EXPR_CALL: { expression_t const *const func = expr->call.function; - if (func->kind == EXPR_REFERENCE) { - entity_t *entity = func->reference.entity; - if (entity->kind == ENTITY_FUNCTION - && entity->declaration.modifiers & DM_NORETURN) + type_t const *const type = skip_typeref(func->base.type); + if (type->kind == TYPE_POINTER) { + type_t const *const points_to + = skip_typeref(type->pointer.points_to); + if (points_to->kind == TYPE_FUNCTION + && points_to->function.modifiers & DM_NORETURN) return false; } @@ -4751,8 +4746,8 @@ static bool expression_returns(expression_t const *const expr) } case EXPR_REFERENCE: - case EXPR_REFERENCE_ENUM_VALUE: - EXPR_LITERAL_CASES + case EXPR_ENUM_CONSTANT: + case EXPR_LITERAL_CASES: case EXPR_STRING_LITERAL: case EXPR_WIDE_STRING_LITERAL: case EXPR_COMPOUND_LITERAL: // TODO descend into initialisers @@ -4805,13 +4800,13 @@ static bool expression_returns(expression_t const *const expr) case EXPR_VA_COPY: return expression_returns(expr->va_copye.src); - EXPR_UNARY_CASES_MANDATORY + case EXPR_UNARY_CASES_MANDATORY: return expression_returns(expr->unary.value); case EXPR_UNARY_THROW: return false; - EXPR_BINARY_CASES + case EXPR_BINARY_CASES: // TODO handle constant lhs of && and || return expression_returns(expr->binary.left) && @@ -5010,20 +5005,21 @@ static void check_reachable(statement_t *const stmt) found_break_parent: break; - case STATEMENT_GOTO: - if (stmt->gotos.expression) { - if (!expression_returns(stmt->gotos.expression)) - return; + case STATEMENT_COMPUTED_GOTO: { + if (!expression_returns(stmt->computed_goto.expression)) + return; - statement_t *parent = stmt->base.parent; - if (parent == NULL) /* top level goto */ - return; - next = parent; - } else { - next = stmt->gotos.label->statement; - if (next == NULL) /* missing label */ - return; - } + statement_t *parent = stmt->base.parent; + if (parent == NULL) /* top level goto */ + return; + next = parent; + break; + } + + case STATEMENT_GOTO: + next = stmt->gotos.label->statement; + if (next == NULL) /* missing label */ + return; break; case STATEMENT_LABEL: @@ -5120,8 +5116,8 @@ found_break_parent: type_t *const type = skip_typeref(current_function->base.type); assert(is_type_function(type)); type_t *const ret = skip_typeref(type->function.return_type); - if (!is_type_atomic(ret, ATOMIC_TYPE_VOID) && - is_type_valid(ret) && + if (!is_type_void(ret) && + is_type_valid(ret) && !is_sym_main(current_function->base.base.symbol)) { source_position_t const *const pos = &stmt->base.source_position; warningf(WARN_RETURN_TYPE, pos, "control reaches end of non-void function"); @@ -5138,6 +5134,7 @@ found_break_parent: case STATEMENT_RETURN: case STATEMENT_CONTINUE: case STATEMENT_BREAK: + case STATEMENT_COMPUTED_GOTO: case STATEMENT_GOTO: case STATEMENT_LEAVE: panic("invalid control flow in function"); @@ -6241,7 +6238,7 @@ static expression_t *parse_reference(void) expression_kind_t kind = EXPR_REFERENCE; if (entity->kind == ENTITY_ENUM_VALUE) - kind = EXPR_REFERENCE_ENUM_VALUE; + kind = EXPR_ENUM_CONSTANT; expression_t *expression = allocate_expression_zero(kind); expression->base.source_position = pos; @@ -6281,7 +6278,7 @@ static bool semantic_cast(expression_t *cast) source_position_t const *pos = &cast->base.source_position; /* §6.5.4 A (void) cast is explicitly permitted, more for documentation than for utility. */ - if (dst_type == type_void) + if (is_type_void(dst_type)) return true; /* only integer and pointer can be casted to pointer */ @@ -6876,9 +6873,10 @@ static expression_t *parse_noop_expression(void) if (token.kind != ')') do { (void)parse_assignment_expression(); } while (next_if(',')); + + rem_anchor_token(','); + rem_anchor_token(')'); } - rem_anchor_token(','); - rem_anchor_token(')'); expect(')', end_error); end_error: @@ -7059,7 +7057,7 @@ typeprop_expression: type_t const* const type = skip_typeref(orig_type); char const* wrong_type = NULL; if (is_type_incomplete(type)) { - if (!is_type_atomic(type, ATOMIC_TYPE_VOID) || !GNU_MODE) + if (!is_type_void(type) || !GNU_MODE) wrong_type = "incomplete"; } else if (type->kind == TYPE_FUNCTION) { if (GNU_MODE) { @@ -7489,16 +7487,14 @@ end_error:; /* 6.5.15.3 */ source_position_t const *const pos = &conditional->base.source_position; type_t *result_type; - if (is_type_atomic(true_type, ATOMIC_TYPE_VOID) || - is_type_atomic(false_type, ATOMIC_TYPE_VOID)) { + 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) { result_type = false_type; } else if (false_expression->kind == EXPR_UNARY_THROW) { result_type = true_type; } else { - if (!is_type_atomic(true_type, ATOMIC_TYPE_VOID) || - !is_type_atomic(false_type, ATOMIC_TYPE_VOID)) { + if (!is_type_void(true_type) || !is_type_void(false_type)) { warningf(WARN_OTHER, pos, "ISO C forbids conditional expression with only one void side"); } result_type = type_void; @@ -7531,8 +7527,7 @@ end_error:; type_t *to2 = skip_typeref(other_type->pointer.points_to); type_t *to; - if (is_type_atomic(to1, ATOMIC_TYPE_VOID) || - is_type_atomic(to2, ATOMIC_TYPE_VOID)) { + if (is_type_void(to1) || is_type_void(to2)) { to = type_void; } else if (types_compatible(get_unqualified_type(to1), get_unqualified_type(to2))) { @@ -7626,7 +7621,7 @@ end_error:; errorf(&value->base.source_position, "operand of delete must have pointer type"); } - } else if (is_type_atomic(skip_typeref(type->pointer.points_to), ATOMIC_TYPE_VOID)) { + } else if (is_type_void(skip_typeref(type->pointer.points_to))) { source_position_t const *const pos = &value->base.source_position; warningf(WARN_OTHER, pos, "deleting 'void*' is undefined"); } @@ -7657,8 +7652,7 @@ static expression_t *parse_throw(void) "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_atomic(points_to, ATOMIC_TYPE_VOID)) { + if (is_type_incomplete(points_to) && !is_type_void(points_to)) { errorf(&value->base.source_position, "cannot throw pointer to incomplete type '%T'", orig_type); } @@ -7681,7 +7675,7 @@ static bool check_pointer_arithmetic(const source_position_t *source_position, points_to = skip_typeref(points_to); if (is_type_incomplete(points_to)) { - if (!GNU_MODE || !is_type_atomic(points_to, ATOMIC_TYPE_VOID)) { + if (!GNU_MODE || !is_type_void(points_to)) { errorf(source_position, "arithmetic with pointer to incomplete type '%T' not allowed", orig_pointer_type); @@ -8195,7 +8189,7 @@ static void semantic_sub(binary_expression_t *expression) "subtracting pointers to incompatible types '%T' and '%T'", orig_type_left, orig_type_right); } else if (!is_type_object(unqual_left)) { - if (!is_type_atomic(unqual_left, ATOMIC_TYPE_VOID)) { + if (!is_type_void(unqual_left)) { errorf(pos, "subtracting pointers to non-object types '%T'", orig_type_left); } else { @@ -8550,7 +8544,7 @@ static bool expression_has_effect(const expression_t *const expr) switch (expr->kind) { case EXPR_ERROR: return true; /* do NOT warn */ case EXPR_REFERENCE: return false; - case EXPR_REFERENCE_ENUM_VALUE: return false; + case EXPR_ENUM_CONSTANT: return false; case EXPR_LABEL_ADDRESS: return false; /* suppress the warning for microsoft __noop operations */ @@ -8618,7 +8612,7 @@ static bool expression_has_effect(const expression_t *const expr) * suppress the warning */ case EXPR_UNARY_CAST: { type_t *const type = skip_typeref(expr->base.type); - return is_type_atomic(type, ATOMIC_TYPE_VOID); + return is_type_void(type); } case EXPR_UNARY_ASSUME: return true; @@ -9103,7 +9097,22 @@ static statement_t *parse_case_statement(void) eat(T_case); - expression_t *const expression = parse_expression(); + expression_t *expression = parse_expression(); + type_t *expression_type = expression->base.type; + type_t *skipped = skip_typeref(expression_type); + if (!is_type_integer(skipped) && is_type_valid(skipped)) { + errorf(pos, "case expression '%E' must have integer type but has type '%T'", + expression, expression_type); + } + + type_t *type = expression_type; + if (current_switch != NULL) { + type_t *switch_type = current_switch->expression->base.type; + if (is_type_valid(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) { @@ -9119,7 +9128,15 @@ static statement_t *parse_case_statement(void) if (GNU_MODE) { if (next_if(T_DOTDOTDOT)) { - expression_t *const end_range = parse_expression(); + expression_t *end_range = parse_expression(); + expression_type = expression->base.type; + skipped = skip_typeref(expression_type); + if (!is_type_integer(skipped) && is_type_valid(skipped)) { + errorf(pos, "case expression '%E' must have integer type but has type '%T'", + expression, expression_type); + } + + 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) { @@ -9563,10 +9580,12 @@ end_error1: */ static statement_t *parse_goto(void) { - statement_t *statement = allocate_statement_zero(STATEMENT_GOTO); - eat(T_goto); + statement_t *statement; + if (GNU_MODE && look_ahead(1)->kind == '*') { + statement = allocate_statement_zero(STATEMENT_COMPUTED_GOTO); + eat(T_goto); + eat('*'); - if (GNU_MODE && next_if('*')) { expression_t *expression = parse_expression(); mark_vars_read(expression, NULL); @@ -9584,24 +9603,28 @@ static statement_t *parse_goto(void) expression = create_implicit_cast(expression, type_void_ptr); } - statement->gotos.expression = expression; - } else if (token.kind == T_IDENTIFIER) { - label_t *const label = get_label(); - label->used = true; - statement->gotos.label = label; + statement->computed_goto.expression = expression; } else { - if (GNU_MODE) - parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL); - else - parse_error_expected("while parsing goto", T_IDENTIFIER, NULL); - eat_until_anchor(); - return create_error_statement(); + statement = allocate_statement_zero(STATEMENT_GOTO); + eat(T_goto); + if (token.kind == T_IDENTIFIER) { + label_t *const label = get_label(); + label->used = true; + statement->gotos.label = label; + + /* remember the goto's in a list for later checking */ + *goto_anchor = &statement->gotos; + goto_anchor = &statement->gotos.next; + } else { + if (GNU_MODE) + parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL); + else + parse_error_expected("while parsing goto", T_IDENTIFIER, NULL); + eat_until_anchor(); + return create_error_statement(); + } } - /* remember the goto's in a list for later checking */ - *goto_anchor = &statement->gotos; - goto_anchor = &statement->gotos.next; - expect(';', end_error); end_error: @@ -9713,6 +9736,15 @@ entity_t *expression_is_variable(const expression_t *expression) return entity; } +static void err_or_warn(source_position_t const *const pos, char const *const msg) +{ + if (c_mode & _CXX || strict_mode) { + errorf(pos, msg); + } else { + warningf(WARN_OTHER, pos, msg); + } +} + /** * Parse a return statement. */ @@ -9735,24 +9767,14 @@ static statement_t *parse_return(void) if (return_value != NULL) { type_t *return_value_type = skip_typeref(return_value->base.type); - if (is_type_atomic(return_type, ATOMIC_TYPE_VOID)) { - if (is_type_atomic(return_value_type, ATOMIC_TYPE_VOID)) { + if (is_type_void(return_type)) { + if (!is_type_void(return_value_type)) { /* ISO/IEC 14882:1998(E) §6.6.3:2 */ /* Only warn in C mode, because GCC does the same */ - if (c_mode & _CXX || strict_mode) { - errorf(pos, - "'return' with a value, in function returning 'void'"); - } else { - warningf(WARN_OTHER, pos, "'return' with a value, in function returning 'void'"); - } + err_or_warn(pos, "'return' with a value, in function returning 'void'"); } else if (!(c_mode & _CXX)) { /* ISO/IEC 14882:1998(E) §6.6.3:3 */ /* Only warn in C mode, because GCC does the same */ - if (strict_mode) { - errorf(pos, - "'return' with expression in function returning 'void'"); - } else { - warningf(WARN_OTHER, pos, "'return' with expression in function returning 'void'"); - } + err_or_warn(pos, "'return' with expression in function returning 'void'"); } } else { assign_error_t error = semantic_assign(return_type, return_value); @@ -9767,14 +9789,9 @@ static statement_t *parse_return(void) warningf(WARN_OTHER, pos, "function returns address of local variable"); } } - } else if (!is_type_atomic(return_type, ATOMIC_TYPE_VOID)) { + } else if (!is_type_void(return_type)) { /* ISO/IEC 14882:1998(E) §6.6.3:3 */ - if (c_mode & _CXX || strict_mode) { - errorf(pos, - "'return' without value, in function returning non-void"); - } else { - warningf(WARN_OTHER, pos, "'return' without value, in function returning non-void"); - } + err_or_warn(pos, "'return' without value, in function returning non-void"); } statement->returns.value = return_value;