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),
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;
}
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;
case EXPR_OFFSETOF:
case EXPR_STATEMENT: // TODO
case EXPR_LABEL_ADDRESS:
- case EXPR_REFERENCE_ENUM_VALUE:
+ case EXPR_ENUM_CONSTANT:
return;
}
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);
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 (c_mode & _CXX) {
+ /* ISO/IEC 14882:1998(E) §8.3.5:2 It must be literally (void). A typedef
+ * is not allowed. */
+ errorf(HERE, "empty parameter list defined with a typedef of 'void' not allowed in C++");
+ } else 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;
}
}
case EXPR_REFERENCE:
- case EXPR_REFERENCE_ENUM_VALUE:
+ case EXPR_ENUM_CONSTANT:
case EXPR_LITERAL_CASES:
case EXPR_STRING_LITERAL:
case EXPR_WIDE_STRING_LITERAL:
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");
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;
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 */
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:
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) {
/* 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;
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))) {
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");
}
"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);
}
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);
"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 {
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 */
* 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;
return stmt;
}
+/**
+ * Parse an expression in parentheses and mark its variables as read.
+ */
+static expression_t *parse_condition(void)
+{
+ expect('(', end_error0);
+ add_anchor_token(')');
+ expression_t *const expr = parse_expression();
+ mark_vars_read(expr, NULL);
+ rem_anchor_token(')');
+ expect(')', end_error1);
+end_error1:
+ return expr;
+end_error0:
+ return create_error_expression();
+}
+
/**
* Parse an if statement.
*/
add_anchor_token('{');
- expect('(', end_error);
- add_anchor_token(')');
- expression_t *const expr = parse_expression();
+ expression_t *const expr = parse_condition();
statement->ifs.condition = expr;
/* §6.8.4.1:1 The controlling expression of an if statement shall have
* scalar type. */
semantic_condition(expr, "condition of 'if'-statment");
- mark_vars_read(expr, NULL);
- rem_anchor_token(')');
- expect(')', end_error);
-end_error:
rem_anchor_token('{');
add_anchor_token(T_else);
PUSH_PARENT(statement);
- expect('(', end_error);
- add_anchor_token(')');
- expression_t *const expr = parse_expression();
- mark_vars_read(expr, NULL);
+ expression_t *const expr = parse_condition();
type_t * type = skip_typeref(expr->base.type);
if (is_type_integer(type)) {
type = promote_integer(type);
type = type_error_type;
}
statement->switchs.expression = create_implicit_cast(expr, type);
- expect(')', end_error);
- rem_anchor_token(')');
switch_statement_t *rem = current_switch;
current_switch = &statement->switchs;
POP_PARENT();
return statement;
-end_error:
- POP_PARENT();
- return create_error_statement();
}
static statement_t *parse_loop_body(statement_t *const loop)
PUSH_PARENT(statement);
- expect('(', end_error);
- add_anchor_token(')');
- expression_t *const cond = parse_expression();
+ expression_t *const cond = parse_condition();
statement->whiles.condition = cond;
/* §6.8.5:2 The controlling expression of an iteration statement shall
* have scalar type. */
semantic_condition(cond, "condition of 'while'-statement");
- mark_vars_read(cond, NULL);
- rem_anchor_token(')');
- expect(')', end_error);
statement->whiles.body = parse_loop_body(statement);
POP_PARENT();
return statement;
-end_error:
- POP_PARENT();
- return create_error_statement();
}
/**
rem_anchor_token(T_while);
expect(T_while, end_error);
- expect('(', end_error);
- add_anchor_token(')');
- expression_t *const cond = parse_expression();
+ expression_t *const cond = parse_condition();
statement->do_while.condition = cond;
/* §6.8.5:2 The controlling expression of an iteration statement shall
* have scalar type. */
semantic_condition(cond, "condition of 'do-while'-statement");
- mark_vars_read(cond, NULL);
- rem_anchor_token(')');
- expect(')', end_error);
expect(';', end_error);
POP_PARENT();
warningf(WARN_UNUSED_VALUE, &init->base.source_position, "initialisation of 'for'-statement has no effect");
}
rem_anchor_token(';');
- expect(';', end_error2);
+ expect(';', end_error3);
+end_error3:;
}
POP_EXTENSION();
else
parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
eat_until_anchor();
- return create_error_statement();
+ statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous)->label;
}
}
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.
*/
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);
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;
POP_PARENT();
if (next_if(T___except)) {
- expect('(', end_error);
- add_anchor_token(')');
- expression_t *const expr = parse_expression();
- mark_vars_read(expr, NULL);
+ expression_t *const expr = parse_condition();
type_t * type = skip_typeref(expr->base.type);
if (is_type_integer(type)) {
type = promote_integer(type);
type = type_error_type;
}
statement->ms_try.except_expression = create_implicit_cast(expr, type);
- rem_anchor_token(')');
- expect(')', end_error);
- statement->ms_try.final_statement = parse_compound_statement(false);
- } else if (next_if(T__finally)) {
- statement->ms_try.final_statement = parse_compound_statement(false);
- } else {
+ } else if (!next_if(T__finally)) {
parse_error_expected("while parsing __try statement", T___except, T___finally, NULL);
- return create_error_statement();
}
+ statement->ms_try.final_statement = parse_compound_statement(false);
return statement;
-end_error:
- return create_error_statement();
}
static statement_t *parse_empty_statement(void)
*/
static statement_t *intern_parse_statement(void)
{
- statement_t *statement = NULL;
-
/* declaration or statement */
- add_anchor_token(';');
+ statement_t *statement;
switch (token.kind) {
case T_IDENTIFIER: {
token_kind_t la1_type = (token_kind_t)look_ahead(1)->kind;
default:
errorf(HERE, "unexpected token %K while parsing statement", &token);
statement = create_error_statement();
- if (!at_anchor())
- next_token();
+ eat_until_anchor();
break;
}
- rem_anchor_token(';');
-
- assert(statement != NULL
- && statement->base.source_position.input_name != NULL);
return statement;
}
add_anchor_token('*');
add_anchor_token('+');
add_anchor_token('-');
+ add_anchor_token(';');
add_anchor_token('{');
add_anchor_token('~');
add_anchor_token(T_CHARACTER_CONSTANT);
rem_anchor_token(T_CHARACTER_CONSTANT);
rem_anchor_token('~');
rem_anchor_token('{');
+ rem_anchor_token(';');
rem_anchor_token('-');
rem_anchor_token('+');
rem_anchor_token('*');