Simplify daisy chaining local labels.
[cparser] / parser.c
index 5189da8..c99427c 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -658,7 +658,7 @@ static void type_error_incompatible(const char *msg,
 /**
  * Expect the current token is the expected token.
  * If not, generate an error, eat the current statement,
- * and goto the end_error label.
+ * and goto the error_label label.
  */
 #define expect(expected, error_label)                     \
        do {                                                  \
@@ -823,7 +823,7 @@ static void stack_pop_to(stack_entry_t **stack_ptr, size_t new_top)
                }
        }
 
-       ARR_SHRINKLEN(*stack_ptr, (int) new_top);
+       ARR_SHRINKLEN(*stack_ptr, new_top);
 }
 
 /**
@@ -1055,8 +1055,8 @@ static assign_error_t semantic_assign(type_t *orig_type_left,
                        return ASSIGN_WARNING_POINTER_FROM_INT;
                }
        } else if ((is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) ||
-           (is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
-               && is_type_pointer(type_right))) {
+                       (is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
+                               && is_type_pointer(type_right))) {
                return ASSIGN_SUCCESS;
        } else if ((is_type_compound(type_left)  && is_type_compound(type_right))
                        || (is_type_builtin(type_left) && is_type_builtin(type_right))) {
@@ -1261,7 +1261,7 @@ static attribute_t *parse_attribute_gnu_single(void)
        symbol_t *symbol = get_symbol_from_token();
        if (symbol == NULL) {
                parse_error_expected("while parsing attribute((", T_IDENTIFIER, NULL);
-               goto end_error;
+               return NULL;
        }
 
        const char *name = symbol->string;
@@ -1290,9 +1290,6 @@ static attribute_t *parse_attribute_gnu_single(void)
                attribute->a.arguments = parse_attribute_arguments();
 
        return attribute;
-
-end_error:
-       return NULL;
 }
 
 static attribute_t *parse_attribute_gnu(void)
@@ -1999,8 +1996,8 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                                        long array_size = type->array.size;
                                        if (index >= array_size) {
                                                errorf(&designator->source_position,
-                                                      "designator [%E] (%d) exceeds array size %d",
-                                                      array_index, index, array_size);
+                                                      "designator [%E] (%d) exceeds array size %d",
+                                                      array_index, index, array_size);
                                        }
                                }
                        }
@@ -2888,10 +2885,10 @@ check_thread_storage_class:
                                                break;
 
                                                char const* wrong;
-                                       case STORAGE_CLASS_AUTO:     wrong = "auto";     goto wrong_thread_stoarge_class;
-                                       case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_stoarge_class;
-                                       case STORAGE_CLASS_TYPEDEF:  wrong = "typedef";  goto wrong_thread_stoarge_class;
-wrong_thread_stoarge_class:
+                                       case STORAGE_CLASS_AUTO:     wrong = "auto";     goto wrong_thread_storage_class;
+                                       case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_storage_class;
+                                       case STORAGE_CLASS_TYPEDEF:  wrong = "typedef";  goto wrong_thread_storage_class;
+wrong_thread_storage_class:
                                                errorf(HERE, "'__thread' used with '%s'", wrong);
                                                break;
                                }
@@ -3930,10 +3927,10 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                bool in_function_scope = current_function != NULL;
 
                                if (specifiers->thread_local || (
-                                     specifiers->storage_class != STORAGE_CLASS_EXTERN &&
-                                         specifiers->storage_class != STORAGE_CLASS_NONE   &&
-                                         (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC)
-                                  )) {
+                                                       specifiers->storage_class != STORAGE_CLASS_EXTERN &&
+                                                       specifiers->storage_class != STORAGE_CLASS_NONE   &&
+                                                       (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC)
+                                               )) {
                                        errorf(&env.source_position,
                                                        "invalid storage class for function '%Y'", env.symbol);
                                }
@@ -7421,8 +7418,21 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) {
                        }
                        break;
                }
-               case bk_gnu_builtin_prefetch: {
+               case bk_gnu_builtin_object_size:
+                       if (call->arguments == NULL)
+                               break;
+
+                       call_argument_t *arg = call->arguments->next;
+                       if (arg != NULL && ! is_constant_expression(arg->expression)) {
+                               errorf(&call->base.source_position,
+                                          "second argument of '%Y' must be a constant expression",
+                                          call->function->reference.entity->base.symbol);
+                       }
+                       break;
+               case bk_gnu_builtin_prefetch:
                        /* second and third argument must be constant if existent */
+                       if (call->arguments == NULL)
+                               break;
                        call_argument_t *rw = call->arguments->next;
                        call_argument_t *locality = NULL;
 
@@ -7443,7 +7453,6 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) {
                                locality = rw->next;
                        }
                        break;
-               }
                default:
                        break;
        }
@@ -7520,6 +7529,10 @@ static expression_t *parse_call_expression(expression_t *expression)
        /* do default promotion for other arguments */
        for (; argument != NULL; argument = argument->next) {
                type_t *type = argument->expression->base.type;
+               if (!is_type_object(skip_typeref(type))) {
+                       errorf(&argument->expression->base.source_position,
+                              "call argument '%E' must not be void", argument->expression);
+               }
 
                type = get_default_promoted_type(type);
 
@@ -7681,13 +7694,6 @@ end_error:;
        } else if (is_type_arithmetic(true_type)
                   && is_type_arithmetic(false_type)) {
                result_type = semantic_arithmetic(true_type, false_type);
-
-               true_expression  = create_implicit_cast(true_expression, result_type);
-               false_expression = create_implicit_cast(false_expression, result_type);
-
-               conditional->true_expression  = true_expression;
-               conditional->false_expression = false_expression;
-               conditional->base.type        = result_type;
        } else if (same_compound_type(true_type, false_type)) {
                /* just take 1 of the 2 types */
                result_type = true_type;
@@ -7739,7 +7745,7 @@ end_error:;
                        result_type = pointer_type;
                } else {
                        if (is_type_valid(other_type)) {
-                               type_error_incompatible("while parsing conditional",
+                               type_error_incompatible("while parsing conditional",
                                                &expression->base.source_position, true_type, false_type);
                        }
                        result_type = type_error_type;
@@ -9262,6 +9268,36 @@ end_error:
        return create_invalid_statement();
 }
 
+static statement_t *parse_label_inner_statement(char const *const label, bool const eat_empty_stmt)
+{
+       statement_t *inner_stmt;
+       switch (token.type) {
+               case '}':
+                       errorf(HERE, "%s at end of compound statement", label);
+                       inner_stmt = create_invalid_statement();
+                       break;
+
+               case ';':
+                       if (eat_empty_stmt) {
+                               /* Eat an empty statement here, to avoid the warning about an empty
+                                * statement after a label.  label:; is commonly used to have a label
+                                * before a closing brace. */
+                               inner_stmt = create_empty_statement();
+                               next_token();
+                               break;
+                       }
+                       /* FALLTHROUGH */
+
+               default:
+                       inner_stmt = parse_statement();
+                       if (inner_stmt->kind == STATEMENT_DECLARATION) {
+                               errorf(&inner_stmt->base.source_position, "declaration after %s", label);
+                       }
+                       break;
+       }
+       return inner_stmt;
+}
+
 /**
  * Parse a case statement.
  */
@@ -9344,11 +9380,7 @@ end_error:
                errorf(pos, "case label not within a switch statement");
        }
 
-       statement_t *const inner_stmt = parse_statement();
-       statement->case_label.statement = inner_stmt;
-       if (inner_stmt->kind == STATEMENT_DECLARATION) {
-               errorf(&inner_stmt->base.source_position, "declaration after case label");
-       }
+       statement->case_label.statement = parse_label_inner_statement("case label", false);
 
        POP_PARENT;
        return statement;
@@ -9366,6 +9398,8 @@ static statement_t *parse_default_statement(void)
        PUSH_PARENT(statement);
 
        expect(':', end_error);
+end_error:
+
        if (current_switch != NULL) {
                const case_label_statement_t *def_label = current_switch->default_label;
                if (def_label != NULL) {
@@ -9387,17 +9421,10 @@ static statement_t *parse_default_statement(void)
                        "'default' label not within a switch statement");
        }
 
-       statement_t *const inner_stmt = parse_statement();
-       statement->case_label.statement = inner_stmt;
-       if (inner_stmt->kind == STATEMENT_DECLARATION) {
-               errorf(&inner_stmt->base.source_position, "declaration after default label");
-       }
+       statement->case_label.statement = parse_label_inner_statement("default label", false);
 
        POP_PARENT;
        return statement;
-end_error:
-       POP_PARENT;
-       return create_invalid_statement();
 }
 
 /**
@@ -9429,22 +9456,7 @@ static statement_t *parse_label_statement(void)
 
        eat(':');
 
-       if (token.type == '}') {
-               errorf(HERE, "label at end of compound statement");
-               statement->label.statement = create_invalid_statement();
-       } else if (token.type == ';') {
-               /* Eat an empty statement here, to avoid the warning about an empty
-                * statement after a label.  label:; is commonly used to have a label
-                * before a closing brace. */
-               statement->label.statement = create_empty_statement();
-               next_token();
-       } else {
-               statement_t *const inner_stmt = parse_statement();
-               statement->label.statement = inner_stmt;
-               if (inner_stmt->kind == STATEMENT_DECLARATION) {
-                       errorf(&inner_stmt->base.source_position, "declaration after label");
-               }
-       }
+       statement->label.statement = parse_label_inner_statement("label", true);
 
        /* remember the labels in a list for later checking */
        *label_anchor = &statement->label;
@@ -9791,7 +9803,7 @@ static statement_t *parse_goto(void)
                else
                        parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
                eat_until_anchor();
-               goto end_error;
+               return create_invalid_statement();
        }
 
        /* remember the goto's in a list for later checking */
@@ -9800,9 +9812,8 @@ static statement_t *parse_goto(void)
 
        expect(';', end_error);
 
-       return statement;
 end_error:
-       return create_invalid_statement();
+       return statement;
 }
 
 /**
@@ -10088,8 +10099,9 @@ static statement_t *parse_local_label_declaration(void)
 
        eat(T___label__);
 
-       entity_t *begin = NULL, *end = NULL;
-
+       entity_t *begin   = NULL;
+       entity_t *end     = NULL;
+       entity_t **anchor = &begin;
        do {
                if (token.type != T_IDENTIFIER) {
                        parse_error_expected("while parsing local label declaration",
@@ -10109,17 +10121,15 @@ static statement_t *parse_local_label_declaration(void)
                        entity->base.source_position = token.source_position;
                        entity->base.symbol          = symbol;
 
-                       if (end != NULL)
-                               end->base.next = entity;
-                       end = entity;
-                       if (begin == NULL)
-                               begin = entity;
+                       *anchor = entity;
+                       anchor  = &entity->base.next;
+                       end     = entity;
 
                        environment_push(entity);
                }
                next_token();
        } while (next_if(','));
-       eat(';');
+       expect(';', end_error);
 end_error:
        statement->declaration.declarations_begin = begin;
        statement->declaration.declarations_end   = end;
@@ -10209,18 +10219,14 @@ static statement_t *intern_parse_statement(void)
                        switch (la1_type) {
                        case '&':
                        case '*':
-                               if (get_entity(token.symbol, NAMESPACE_NORMAL) != NULL)
-                                       goto expression_statment;
-                               /* FALLTHROUGH */
-
+                               if (get_entity(token.symbol, NAMESPACE_NORMAL) != NULL) {
+                       default:
+                                       statement = parse_expression_statement();
+                               } else {
                        DECLARATION_START
                        case T_IDENTIFIER:
-                               statement = parse_declaration_statement();
-                               break;
-
-                       default:
-expression_statment:
-                               statement = parse_expression_statement();
+                                       statement = parse_declaration_statement();
+                               }
                                break;
                        }
                }