#include "walk.h"
#include "warning.h"
#include "printer.h"
+#include "ast2firm.h"
#include "adt/bitfiddle.h"
#include "adt/error.h"
#include "adt/array.h"
#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)
[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),
[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),
next_token();
}
-static inline bool next_if(token_kind_t const kind)
+/**
+ * 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 == kind) {
eat(kind);
static void eat_block(void)
{
eat_until_matching_token('{');
- next_if('}');
+ accept('}');
}
/**
warningf(WARN_TRADITIONAL, HERE, "traditional C rejects string constant concatenation");
string_encoding_t enc = token.literal.string.encoding;
do {
- if (token.literal.string.encoding != STRING_ENCODING_CHAR) {
- enc = token.literal.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.literal.string);
eat(T_STRING_LITERAL);
string_t const res = concat_string_literals();
if (res.encoding != STRING_ENCODING_CHAR) {
- errorf(&pos, "expected plain string literal, got wide string literal");
+ errorf(&pos, "expected plain string literal, got %s string literal", get_string_encoding_prefix(res.encoding));
}
return res;
/* append argument */
*anchor = argument;
anchor = &argument->next;
- } while (next_if(','));
+ } while (accept(','));
expect(')');
return first;
}
next_token();
/* parse arguments */
- if (next_if('('))
+ if (accept('('))
attribute->a.arguments = parse_attribute_arguments();
return attribute;
*anchor = attribute;
anchor = &attribute->next;
}
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(')');
array_type_t *const array_type = &type->array;
type_t *const element_type = skip_typeref(array_type->element_type);
switch (expression->string_literal.value.encoding) {
- case STRING_ENCODING_CHAR: {
+ 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)) {
break;
}
+ case STRING_ENCODING_CHAR16:
+ case STRING_ENCODING_CHAR32:
case STRING_ENCODING_WIDE: {
- type_t *bare_wchar_type = skip_typeref(type_wchar_t);
- if (get_unqualified_type(element_type) == bare_wchar_type) {
+ 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;
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");
*/
static void skip_initializers(void)
{
- next_if('{');
+ accept('{');
while (token.kind != '}') {
if (token.kind == T_EOF)
if (expression->kind == EXPR_STRING_LITERAL && outer_type != NULL) {
result = initializer_from_expression(outer_type, expression);
if (result != NULL) {
- next_if(',');
+ accept(',');
if (token.kind != '}') {
warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", outer_type);
}
ARR_APP1(initializer_t*, initializers, sub);
error_parse_next:
- if (!next_if(','))
+ if (!accept(','))
break;
if (token.kind == '}') {
break;
}
if (attributes != NULL) {
+ entity->compound.attributes = attributes;
handle_entity_attributes(attributes, entity);
}
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);
}
record_entity(entity, false);
- } while (next_if(',') && token.kind != '}');
+ } while (accept(',') && token.kind != '}');
rem_anchor_token(',');
rem_anchor_token('}');
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(')');
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;
}
/* parse arguments */
- if (next_if('('))
+ if (accept('('))
attribute->a.arguments = parse_attribute_arguments();
return attribute;
*anchor = attribute;
anchor = &attribute->next;
- } while (next_if(','));
+ } while (accept(','));
}
rem_anchor_token(')');
expect(')');
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)
default:
goto parameters_finished;
}
- } while (next_if(','));
+ } while (accept(','));
parameters_finished:
rem_anchor_token(',');
}
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;
check_variable_type_complete(entity);
- if (!next_if(','))
+ if (!accept(','))
break;
add_anchor_token('=');
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);
}
}
return;
if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) {
- long const val = fold_constant_to_int(expr);
+ 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) {
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;
}
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;
switch (parent->kind) {
case STATEMENT_SWITCH:
- case STATEMENT_WHILE:
case STATEMENT_DO_WHILE:
case STATEMENT_FOR:
last = 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;
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)
environment_push(parameter);
}
- if (function->statement != NULL) {
+ if (function->body != NULL) {
parser_error_multiple_definition(entity, HERE);
eat_block();
} else {
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();
append_entity(&compound->members, entity);
}
}
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(';');
expect(';');
{
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");
}
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 (size > 1) {
if (!GNU_MODE && !(c_mode & _C99)) {
}
break;
- case STRING_ENCODING_WIDE:
- literal->base.type = type_int;
+ 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");
}
source_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;
/* lookup entity */
entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL);
- if (!next_if(T_COLONCOLON))
+ if (!accept(T_COLONCOLON))
break;
switch (entity->kind) {
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);
}
return true;
}
-static expression_t *parse_compound_literal(source_position_t const *const pos, type_t *type)
+static expression_t *parse_compound_literal(source_position_t const *const pos,
+ type_t *type)
{
expression_t *expression = allocate_expression_zero(EXPR_COMPOUND_LITERAL);
expression->base.source_position = *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;
}
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);
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);
if (!designator->symbol)
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;
if (token.kind != ')') do {
(void)parse_assignment_expression();
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(')');
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.source_position, "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;
warningf(WARN_CHAR_SUBSCRIPTS, pos, "array subscript has char type");
"third argument of '%Y' must be a constant expression",
call->function->reference.entity->base.symbol);
}
- locality = rw->next;
}
break;
default:
*anchor = argument;
anchor = &argument->next;
- } while (next_if(','));
+ } while (accept(','));
}
rem_anchor_token(',');
rem_anchor_token(')');
eat(T_delete);
- if (next_if('[')) {
+ if (accept('[')) {
result->kind = EXPR_UNARY_DELETE_ARRAY;
expect(']');
}
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");
+ source_position_t const *const pos = &expression->base.source_position;
+ errorf(pos, "operand of unary expression must have arithmetic type, but is '%T'", orig_type);
}
return;
} else if (is_type_integer(type)) {
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");
+ source_position_t const *const pos = &expression->base.source_position;
+ errorf(pos, "operands of binary expression must have arithmetic types, but are '%T' and '%T'", orig_type_left, orig_type_right);
}
return;
}
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_valid(type_left) && is_type_valid(type_right)) {
- errorf(&expression->base.source_position,
- "operation needs integer types");
+ source_position_t const *const pos = &expression->base.source_position;
+ errorf(pos, "operands of binary expression must have integer types, but are '%T' and '%T'", orig_type_left, orig_type_right);
}
return;
}
}
/**
- * 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)
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");
+ source_position_t const *const pos = &expression->base.source_position;
+ errorf(pos, "operands of shift expression must have integer types, but are '%T' and '%T'", orig_type_left, orig_type_right);
}
return false;
}
}
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)
/**
* 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;
-
- while (token.kind == T_STRING_LITERAL || token.kind == '[') {
- asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
+ if (token.kind == T_STRING_LITERAL || token.kind == '[') {
+ add_anchor_token(',');
+ do {
+ asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
- if (next_if('[')) {
- add_anchor_token(']');
- argument->symbol = expect_identifier("while parsing asm argument", NULL);
- rem_anchor_token(']');
- expect(']');
- if (!argument->symbol)
- return NULL;
- }
+ add_anchor_token(')');
+ add_anchor_token('(');
+ add_anchor_token(T_STRING_LITERAL);
- 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.source_position, "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(')');
-
- set_address_taken(expression, true);
+ }
+ argument->expression = expression;
+ rem_anchor_token(')');
+ expect(')');
- *anchor = argument;
- anchor = &argument->next;
+ set_address_taken(expression, true);
- 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;
}
/**
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.source_position, "assembler statement with labels should be 'asm goto'");
+ parse_asm_labels(&asm_statement->labels);
+ if (asm_statement->labels)
+ errorf(&statement->base.source_position, "'asm goto' not supported");
+ } else {
+ if (asm_goto)
+ warningf(WARN_OTHER, &statement->base.source_position, "'asm goto' without labels");
+ }
rem_anchor_token(')');
expect(')');
}
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);
}
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");
}
} else {
label->base.source_position = *pos;
label->statement = statement;
+ label->n_users += 1;
}
eat(':');
"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) {
{
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;
}
source_position_t const *const pos = &statement->base.source_position;
warningf(WARN_SWITCH_ENUM, pos, "'%N' not handled in switch", entry);
}
- last_value = value;
}
}
*/
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();
PUSH_EXTENSION();
- if (next_if(';')) {
+ if (accept(';')) {
} else if (is_declaration_specifier(&token)) {
parse_declaration(record_entity, DECL_FLAGS_NONE);
} else {
label_t *const label = get_label("while parsing goto");
if (label) {
+ label->n_users += 1;
label->used = true;
statement->gotos.label = label;
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 = 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);
environment_push(entity);
}
}
- } while (next_if(','));
+ } while (accept(','));
rem_anchor_token(',');
rem_anchor_token(';');
expect(';');
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";
}
current_linkage = new_linkage;
- if (next_if('{')) {
+ if (accept('{')) {
parse_externals();
expect('}');
} else {
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");
expr_statement->base.source_position = builtin_source_position;
expr_statement->expression.expression = call;
- statement_t *statement = entity->function.statement;
- assert(statement->kind == STATEMENT_COMPOUND);
- compound_statement_t *compounds = &statement->compound;
+ 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;