Cleanup, reduce code duplication.
[cparser] / parser.c
index a28efbf..a8ac494 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -1331,6 +1331,8 @@ static attribute_t *parse_attributes(attribute_t *first)
                switch (token.type) {
                case T___attribute__:
                        attribute = parse_attribute_gnu();
+                       if (attribute == NULL)
+                               continue;
                        break;
 
                case T_asm:
@@ -1961,7 +1963,7 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                                if (iter == NULL) {
                                        errorf(&designator->source_position,
                                               "'%T' has no member named '%Y'", orig_type, symbol);
-                                       goto failed;
+                                       return false;
                                }
                                assert(iter->kind == ENTITY_COMPOUND_MEMBER);
                                if (used_in_offsetof) {
@@ -1970,7 +1972,7 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                                                errorf(&designator->source_position,
                                                       "offsetof designator '%Y' must not specify bitfield",
                                                       symbol);
-                                               goto failed;
+                                               return false;
                                        }
                                }
 
@@ -1988,7 +1990,7 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                                               "[%E] designator used for non-array type '%T'",
                                               array_index, orig_type);
                                }
-                               goto failed;
+                               return false;
                        }
 
                        long index = fold_constant_to_int(array_index);
@@ -2017,9 +2019,6 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                }
        }
        return true;
-
-failed:
-       return false;
 }
 
 static void advance_current_object(type_path_t *path, size_t top_path_level)
@@ -2956,7 +2955,7 @@ wrong_thread_storage_class:
 
                case T_long:
                        if (type_specifiers & SPECIFIER_LONG_LONG) {
-                               errorf(HERE, "multiple type specifiers given");
+                               errorf(HERE, "too many long type specifiers given");
                        } else if (type_specifiers & SPECIFIER_LONG) {
                                type_specifiers |= SPECIFIER_LONG_LONG;
                        } else {
@@ -3041,8 +3040,6 @@ wrong_thread_storage_class:
 
                                                next_token();
                                                saw_error = true;
-                                               if (la1_type == '&' || la1_type == '*')
-                                                       goto finish_specifiers;
                                                continue;
                                        }
 
@@ -3379,10 +3376,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
                /* ISO/IEC 14882:1998(E) §C.1.6:1 */
                if (!(c_mode & _CXX))
                        type->unspecified_parameters = true;
-               goto parameters_finished;
-       }
-
-       if (has_parameters()) {
+       } else if (has_parameters()) {
                function_parameter_t **anchor = &type->parameters;
                do {
                        switch (token.type) {
@@ -3423,7 +3417,6 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
                } while (next_if(','));
        }
 
-
 parameters_finished:
        rem_anchor_token(')');
        expect(')', end_error);
@@ -3640,25 +3633,45 @@ ptr_operator_end: ;
                }
                next_token();
                break;
-       case '(':
-               /* §6.7.6:2 footnote 126:  Empty parentheses in a type name are
-                * interpreted as ``function with no parameter specification'', rather
-                * than redundant parentheses around the omitted identifier. */
-               if (look_ahead(1)->type != ')') {
-                       next_token();
-                       add_anchor_token(')');
-                       inner_types = parse_inner_declarator(env);
-                       if (inner_types != NULL) {
-                               /* All later declarators only modify the return type */
-                               env->must_be_abstract = true;
-                       }
-                       rem_anchor_token(')');
-                       expect(')', end_error);
-               } else if (!env->may_be_abstract) {
-                       errorf(HERE, "declarator must have a name");
-                       goto error_out;
+
+       case '(': {
+               /* Parenthesized declarator or function declarator? */
+               token_t const *const la1 = look_ahead(1);
+               switch (la1->type) {
+                       case T_IDENTIFIER:
+                               if (is_typedef_symbol(la1->symbol)) {
+                       case ')':
+                                       /* §6.7.6:2 footnote 126:  Empty parentheses in a type name are
+                                        * interpreted as ``function with no parameter specification'', rather
+                                        * than redundant parentheses around the omitted identifier. */
+                       default:
+                                       /* Function declarator. */
+                                       if (!env->may_be_abstract) {
+                                               errorf(HERE, "function declarator must have a name");
+                                               goto error_out;
+                                       }
+                               } else {
+                       case '&':
+                       case '(':
+                       case '*':
+                       case '[':
+                       case T___attribute__: /* FIXME __attribute__ might also introduce a parameter of a function declarator. */
+                                       /* Paranthesized declarator. */
+                                       next_token();
+                                       add_anchor_token(')');
+                                       inner_types = parse_inner_declarator(env);
+                                       if (inner_types != NULL) {
+                                               /* All later declarators only modify the return type */
+                                               env->must_be_abstract = true;
+                                       }
+                                       rem_anchor_token(')');
+                                       expect(')', end_error);
+                               }
+                               break;
                }
                break;
+       }
+
        default:
                if (env->may_be_abstract)
                        break;
@@ -4051,23 +4064,30 @@ static void check_main(const entity_t *entity)
        }
        const function_parameter_t *parm = func_type->parameters;
        if (parm != NULL) {
-               type_t *const first_type = parm->type;
-               if (!types_compatible(skip_typeref(first_type), type_int)) {
+               type_t *const first_type        = skip_typeref(parm->type);
+               type_t *const first_type_unqual = get_unqualified_type(first_type);
+               if (!types_compatible(first_type_unqual, type_int)) {
                        warningf(pos,
                                 "first argument of 'main' should be 'int', but is '%T'",
-                                first_type);
+                                parm->type);
                }
                parm = parm->next;
                if (parm != NULL) {
-                       type_t *const second_type = parm->type;
-                       if (!types_compatible(skip_typeref(second_type), type_char_ptr_ptr)) {
-                               warningf(pos, "second argument of 'main' should be 'char**', but is '%T'", second_type);
+                       type_t *const second_type = skip_typeref(parm->type);
+                       type_t *const second_type_unqual
+                               = get_unqualified_type(second_type);
+                       if (!types_compatible(second_type_unqual, type_char_ptr_ptr)) {
+                               warningf(pos, "second argument of 'main' should be 'char**', but is '%T'",
+                                        parm->type);
                        }
                        parm = parm->next;
                        if (parm != NULL) {
-                               type_t *const third_type = parm->type;
-                               if (!types_compatible(skip_typeref(third_type), type_char_ptr_ptr)) {
-                                       warningf(pos, "third argument of 'main' should be 'char**', but is '%T'", third_type);
+                               type_t *const third_type = skip_typeref(parm->type);
+                               type_t *const third_type_unqual
+                                       = get_unqualified_type(third_type);
+                               if (!types_compatible(third_type_unqual, type_char_ptr_ptr)) {
+                                       warningf(pos, "third argument of 'main' should be 'char**', but is '%T'",
+                                                parm->type);
                                }
                                parm = parm->next;
                                if (parm != NULL)
@@ -6184,7 +6204,7 @@ static expression_t *parse_character_constant(void)
        literal->literal.value        = token.literal;
 
        size_t len = literal->literal.value.size;
-       if (len != 1) {
+       if (len > 1) {
                if (!GNU_MODE && !(c_mode & _C99)) {
                        errorf(HERE, "more than 1 character in character constant");
                } else if (warning.multichar) {
@@ -6208,7 +6228,7 @@ static expression_t *parse_wide_character_constant(void)
        literal->literal.value        = token.literal;
 
        size_t len = wstrlen(&literal->literal.value);
-       if (len != 1) {
+       if (len > 1) {
                warningf(HERE, "multi-character character constant");
        }
 
@@ -7170,29 +7190,15 @@ static expression_t *parse_primary_expression(void)
        return create_invalid_expression();
 }
 
-/**
- * Check if the expression has the character type and issue a warning then.
- */
-static void check_for_char_index_type(const expression_t *expression)
-{
-       type_t       *const type      = expression->base.type;
-       const type_t *const base_type = skip_typeref(type);
-
-       if (is_type_atomic(base_type, ATOMIC_TYPE_CHAR) &&
-                       warning.char_subscripts) {
-               warningf(&expression->base.source_position,
-                        "array subscript has type '%T'", type);
-       }
-}
-
 static expression_t *parse_array_expression(expression_t *left)
 {
-       expression_t *expression = allocate_expression_zero(EXPR_ARRAY_ACCESS);
+       expression_t              *const expr = allocate_expression_zero(EXPR_ARRAY_ACCESS);
+       array_access_expression_t *const arr  = &expr->array_access;
 
        eat('[');
        add_anchor_token(']');
 
-       expression_t *inside = parse_expression();
+       expression_t *const inside = parse_expression();
 
        type_t *const orig_type_left   = left->base.type;
        type_t *const orig_type_inside = inside->base.type;
@@ -7200,36 +7206,46 @@ static expression_t *parse_array_expression(expression_t *left)
        type_t *const type_left   = skip_typeref(orig_type_left);
        type_t *const type_inside = skip_typeref(orig_type_inside);
 
-       type_t                    *return_type;
-       array_access_expression_t *array_access = &expression->array_access;
+       expression_t *ref;
+       expression_t *idx;
+       type_t       *idx_type;
+       type_t       *res_type;
        if (is_type_pointer(type_left)) {
-               return_type             = type_left->pointer.points_to;
-               array_access->array_ref = left;
-               array_access->index     = inside;
-               check_for_char_index_type(inside);
+               ref      = left;
+               idx      = inside;
+               idx_type = type_inside;
+               res_type = type_left->pointer.points_to;
+               goto check_idx;
        } else if (is_type_pointer(type_inside)) {
-               return_type             = type_inside->pointer.points_to;
-               array_access->array_ref = inside;
-               array_access->index     = left;
-               array_access->flipped   = true;
-               check_for_char_index_type(left);
+               arr->flipped = true;
+               ref      = inside;
+               idx      = left;
+               idx_type = type_left;
+               res_type = type_inside->pointer.points_to;
+check_idx:
+               res_type = automatic_type_conversion(res_type);
+               if (is_type_atomic(idx_type, ATOMIC_TYPE_CHAR) && warning.char_subscripts) {
+                       warningf(&idx->base.source_position, "array subscript has char type");
+               }
        } else {
                if (is_type_valid(type_left) && is_type_valid(type_inside)) {
                        errorf(HERE,
                                "array access on object with non-pointer types '%T', '%T'",
                                orig_type_left, orig_type_inside);
                }
-               return_type             = type_error_type;
-               array_access->array_ref = left;
-               array_access->index     = inside;
+               res_type = type_error_type;
+               ref      = left;
+               idx      = inside;
        }
 
-       expression->base.type = automatic_type_conversion(return_type);
+       arr->array_ref = ref;
+       arr->index     = idx;
+       arr->base.type = res_type;
 
        rem_anchor_token(']');
        expect(']', end_error);
 end_error:
-       return expression;
+       return expr;
 }
 
 static expression_t *parse_typeprop(expression_kind_t const kind)