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);
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)
static void parse_asm_arguments(asm_argument_t **anchor, bool const is_out)
{
if (token.kind == T_STRING_LITERAL || token.kind == '[') {
+ add_anchor_token(',');
do {
asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
+ add_anchor_token(')');
+ add_anchor_token('(');
+ add_anchor_token(T_STRING_LITERAL);
+
if (accept('[')) {
add_anchor_token(']');
argument->symbol = expect_identifier("while parsing asm argument", NULL);
expect(']');
}
+ rem_anchor_token(T_STRING_LITERAL);
argument->constraints = parse_string_literals("asm argument");
- add_anchor_token(')');
+ rem_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
mark_vars_read(expression, NULL);
}
argument->expression = expression;
+ rem_anchor_token(')');
expect(')');
set_address_taken(expression, true);
*anchor = argument;
anchor = &argument->next;
} while (accept(','));
+ rem_anchor_token(',');
}
}
static void parse_asm_clobbers(asm_clobber_t **anchor)
{
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);
*anchor = clobber;
anchor = &clobber->next;
} while (accept(','));
+ rem_anchor_token(',');
+ }
+}
+
+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;
+
+ *anchor = asm_label;
+ anchor = &asm_label->next;
+ }
+ } while (accept(','));
+ rem_anchor_token(',');
}
}
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 (accept(':')) parse_asm_arguments(&asm_statement->outputs, true);
if (accept(':')) parse_asm_arguments(&asm_statement->inputs, false);
- rem_anchor_token(':');
if (accept(':')) parse_asm_clobbers( &asm_statement->clobbers);
+ rem_anchor_token(':');
+ 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(')');
expect(';');