fix cases where compoundlits are constant/get an entity
[cparser] / parser.c
index 01fd20d..a9a4041 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -6187,21 +6187,24 @@ 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 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;
 }
@@ -6305,7 +6308,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);
@@ -7543,9 +7546,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");
+                       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)) {
@@ -7780,10 +7782,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");
+                       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;
        }
@@ -7804,10 +7805,9 @@ static void semantic_binexpr_integer(binary_expression_t *const expression)
        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;
        }
@@ -7834,14 +7834,23 @@ static void warn_div_by_zero(binary_expression_t const *const expression)
 }
 
 /**
- * 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)
@@ -7868,10 +7877,9 @@ 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");
+                       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;
        }
@@ -8475,8 +8483,8 @@ 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)
@@ -8641,9 +8649,14 @@ static void init_expression_parsers(void)
 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);
@@ -8651,11 +8664,11 @@ static void parse_asm_arguments(asm_argument_t **anchor, bool const is_out)
                                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
@@ -8712,6 +8725,7 @@ static void parse_asm_arguments(asm_argument_t **anchor, bool const is_out)
                                mark_vars_read(expression, NULL);
                        }
                        argument->expression = expression;
+                       rem_anchor_token(')');
                        expect(')');
 
                        set_address_taken(expression, true);
@@ -8719,6 +8733,7 @@ static void parse_asm_arguments(asm_argument_t **anchor, bool const is_out)
                        *anchor = argument;
                        anchor  = &argument->next;
                } while (accept(','));
+               rem_anchor_token(',');
        }
 }
 
@@ -8728,6 +8743,7 @@ static void parse_asm_arguments(asm_argument_t **anchor, bool const is_out)
 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);
@@ -8735,6 +8751,25 @@ static void parse_asm_clobbers(asm_clobber_t **anchor)
                        *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(',');
        }
 }
 
@@ -8754,15 +8789,28 @@ static statement_t *parse_asm_statement(void)
        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(';');