Reduce code duplication.
[cparser] / parser.c
index 6d44cd4..c4883b5 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -1062,8 +1062,7 @@ static assign_error_t semantic_assign(type_t *orig_type_left,
                        (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))) {
+       } else if (is_type_compound(type_left) && is_type_compound(type_right)) {
                type_t *const unqual_type_left  = get_unqualified_type(type_left);
                type_t *const unqual_type_right = get_unqualified_type(type_right);
                if (types_compatible(unqual_type_left, unqual_type_right)) {
@@ -1332,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:
@@ -1962,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) {
@@ -1971,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;
                                        }
                                }
 
@@ -1989,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);
@@ -2018,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)
@@ -2156,7 +2154,6 @@ finish_designator:
                        if (type != NULL && is_type_scalar(type)) {
                                sub = parse_scalar_initializer(type, env->must_be_constant);
                        } else {
-                               eat('{');
                                if (type == NULL) {
                                        if (env->entity != NULL) {
                                                errorf(HERE,
@@ -2165,8 +2162,11 @@ finish_designator:
                                        } else {
                                                errorf(HERE, "extra brace group at end of initializer");
                                        }
-                               } else
+                                       eat('{');
+                               } else {
+                                       eat('{');
                                        descend_into_subtype(path);
+                               }
 
                                add_anchor_token('}');
                                sub = parse_sub_initializer(path, orig_type, top_path_level+1,
@@ -2413,10 +2413,11 @@ static void append_entity(scope_t *scope, entity_t *entity)
 
 static compound_t *parse_compound_type_specifier(bool is_struct)
 {
+       source_position_t const pos = *HERE;
        eat(is_struct ? T_struct : T_union);
 
-       symbol_t    *symbol   = NULL;
-       compound_t  *compound = NULL;
+       symbol_t    *symbol     = NULL;
+       entity_t    *entity     = NULL;
        attribute_t *attributes = NULL;
 
        if (token.type == T___attribute__) {
@@ -2427,46 +2428,40 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
        if (token.type == T_IDENTIFIER) {
                /* the compound has a name, check if we have seen it already */
                symbol = token.symbol;
+               entity = get_tag(symbol, kind);
                next_token();
 
-               entity_t *entity = get_tag(symbol, kind);
                if (entity != NULL) {
-                       compound = &entity->compound;
-                       if (compound->base.parent_scope != current_scope &&
+                       if (entity->base.parent_scope != current_scope &&
                            (token.type == '{' || token.type == ';')) {
                                /* we're in an inner scope and have a definition. Shadow
                                 * existing definition in outer scope */
-                               compound = NULL;
-                       } else if (compound->complete && token.type == '{') {
-                               assert(symbol != NULL);
-                               errorf(HERE, "multiple definitions of '%s %Y' (previous definition %P)",
+                               entity = NULL;
+                       } else if (entity->compound.complete && token.type == '{') {
+                               errorf(&pos, "multiple definitions of '%s %Y' (previous definition %P)",
                                       is_struct ? "struct" : "union", symbol,
-                                      &compound->base.source_position);
+                                      &entity->base.source_position);
                                /* clear members in the hope to avoid further errors */
-                               compound->members.entities = NULL;
+                               entity->compound.members.entities = NULL;
                        }
                }
        } else if (token.type != '{') {
-               if (is_struct) {
-                       parse_error_expected("while parsing struct type specifier",
-                                            T_IDENTIFIER, '{', NULL);
-               } else {
-                       parse_error_expected("while parsing union type specifier",
-                                            T_IDENTIFIER, '{', NULL);
-               }
+               char const *const msg =
+                       is_struct ? "while parsing struct type specifier" :
+                                   "while parsing union type specifier";
+               parse_error_expected(msg, T_IDENTIFIER, '{', NULL);
 
                return NULL;
        }
 
-       if (compound == NULL) {
-               entity_t *entity = allocate_entity_zero(kind);
-               compound         = &entity->compound;
+       if (entity == NULL) {
+               entity = allocate_entity_zero(kind);
 
-               compound->alignment            = 1;
-               compound->base.namespc         = NAMESPACE_TAG;
-               compound->base.source_position = token.source_position;
-               compound->base.symbol          = symbol;
-               compound->base.parent_scope    = current_scope;
+               entity->compound.alignment   = 1;
+               entity->base.namespc         = NAMESPACE_TAG;
+               entity->base.source_position = pos;
+               entity->base.symbol          = symbol;
+               entity->base.parent_scope    = current_scope;
                if (symbol != NULL) {
                        environment_push(entity);
                }
@@ -2474,20 +2469,20 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
        }
 
        if (token.type == '{') {
-               parse_compound_type_entries(compound);
+               parse_compound_type_entries(&entity->compound);
 
                /* ISO/IEC 14882:1998(E) §7.1.3:5 */
                if (symbol == NULL) {
                        assert(anonymous_entity == NULL);
-                       anonymous_entity = (entity_t*)compound;
+                       anonymous_entity = entity;
                }
        }
 
        if (attributes != NULL) {
-               handle_entity_attributes(attributes, (entity_t*) compound);
+               handle_entity_attributes(attributes, entity);
        }
 
-       return compound;
+       return &entity->compound;
 }
 
 static void parse_enum_entries(type_t *const enum_type)
@@ -2537,16 +2532,17 @@ end_error:
 
 static type_t *parse_enum_specifier(void)
 {
-       entity_t *entity;
-       symbol_t *symbol;
+       source_position_t const pos = *HERE;
+       entity_t               *entity;
+       symbol_t               *symbol;
 
        eat(T_enum);
        switch (token.type) {
                case T_IDENTIFIER:
                        symbol = token.symbol;
+                       entity = get_tag(symbol, ENTITY_ENUM);
                        next_token();
 
-                       entity = get_tag(symbol, ENTITY_ENUM);
                        if (entity != NULL) {
                                if (entity->base.parent_scope != current_scope &&
                                                (token.type == '{' || token.type == ';')) {
@@ -2554,7 +2550,7 @@ static type_t *parse_enum_specifier(void)
                                         * existing definition in outer scope */
                                        entity = NULL;
                                } else if (entity->enume.complete && token.type == '{') {
-                                       errorf(HERE, "multiple definitions of 'enum %Y' (previous definition %P)",
+                                       errorf(&pos, "multiple definitions of 'enum %Y' (previous definition %P)",
                                                        symbol, &entity->base.source_position);
                                }
                        }
@@ -2574,7 +2570,7 @@ static type_t *parse_enum_specifier(void)
        if (entity == NULL) {
                entity                       = allocate_entity_zero(ENTITY_ENUM);
                entity->base.namespc         = NAMESPACE_TAG;
-               entity->base.source_position = token.source_position;
+               entity->base.source_position = pos;
                entity->base.symbol          = symbol;
                entity->base.parent_scope    = current_scope;
        }
@@ -2683,15 +2679,6 @@ typedef enum specifiers_t {
        SPECIFIER_IMAGINARY = 1 << 18,
 } specifiers_t;
 
-static type_t *create_builtin_type(symbol_t *const symbol,
-                                   type_t *const real_type)
-{
-       type_t *type            = allocate_type_zero(TYPE_BUILTIN);
-       type->builtin.symbol    = symbol;
-       type->builtin.real_type = real_type;
-       return identify_new_type(type);
-}
-
 static type_t *get_typedef_type(symbol_t *symbol)
 {
        entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL);
@@ -2968,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 {
@@ -3053,8 +3040,6 @@ wrong_thread_storage_class:
 
                                                next_token();
                                                saw_error = true;
-                                               if (la1_type == '&' || la1_type == '*')
-                                                       goto finish_specifiers;
                                                continue;
                                        }
 
@@ -3391,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) {
@@ -3435,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);
@@ -3456,6 +3437,7 @@ typedef union construct_type_t construct_type_t;
 
 typedef struct construct_type_base_t {
        construct_type_kind_t  kind;
+       source_position_t      pos;
        construct_type_t      *next;
 } construct_type_base_t;
 
@@ -3495,16 +3477,16 @@ static construct_type_t *allocate_declarator_zero(construct_type_kind_t const ki
 {
        construct_type_t *const cons = obstack_alloc(&temp_obst, size);
        memset(cons, 0, size);
-       cons->kind = kind;
+       cons->kind     = kind;
+       cons->base.pos = *HERE;
        return cons;
 }
 
 /* §6.7.5.1 */
 static construct_type_t *parse_pointer_declarator(void)
 {
-       eat('*');
-
        construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_POINTER, sizeof(parsed_pointer_t));
+       eat('*');
        cons->pointer.type_qualifiers = parse_type_qualifiers();
        //cons->pointer.base_variable   = base_variable;
 
@@ -3514,12 +3496,11 @@ static construct_type_t *parse_pointer_declarator(void)
 /* ISO/IEC 14882:1998(E) §8.3.2 */
 static construct_type_t *parse_reference_declarator(void)
 {
-       eat('&');
-
        if (!(c_mode & _CXX))
                errorf(HERE, "references are only available for C++");
 
        construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_REFERENCE, sizeof(parsed_reference_t));
+       eat('&');
 
        return cons;
 }
@@ -3527,12 +3508,12 @@ static construct_type_t *parse_reference_declarator(void)
 /* §6.7.5.2 */
 static construct_type_t *parse_array_declarator(void)
 {
-       eat('[');
-       add_anchor_token(']');
-
        construct_type_t *const cons  = allocate_declarator_zero(CONSTRUCT_ARRAY, sizeof(parsed_array_t));
        parsed_array_t   *const array = &cons->array;
 
+       eat('[');
+       add_anchor_token(']');
+
        bool is_static = next_if(T_static);
 
        type_qualifiers_t type_qualifiers = parse_type_qualifiers();
@@ -3564,7 +3545,7 @@ static construct_type_t *parse_array_declarator(void)
        }
 
        if (is_static && size == NULL)
-               errorf(HERE, "static array parameters require a size");
+               errorf(&array->base.pos, "static array parameters require a size");
 
        rem_anchor_token(']');
        expect(']', end_error);
@@ -3576,6 +3557,8 @@ end_error:
 /* §6.7.5.3 */
 static construct_type_t *parse_function_declarator(scope_t *scope)
 {
+       construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_FUNCTION, sizeof(construct_function_type_t));
+
        type_t          *type  = allocate_type_zero(TYPE_FUNCTION);
        function_type_t *ftype = &type->function;
 
@@ -3584,7 +3567,6 @@ static construct_type_t *parse_function_declarator(scope_t *scope)
 
        parse_parameters(ftype, scope);
 
-       construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_FUNCTION, sizeof(construct_function_type_t));
        cons->function.function_type = type;
 
        return cons;
@@ -3651,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;
@@ -3722,6 +3724,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
 {
        construct_type_t *iter = construct_list;
        for (; iter != NULL; iter = iter->base.next) {
+               source_position_t const* const pos = &iter->base.pos;
                switch (iter->kind) {
                case CONSTRUCT_INVALID:
                        break;
@@ -3734,13 +3737,12 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                        type_t *skipped_return_type = skip_typeref(type);
                        /* §6.7.5.3:1 */
                        if (is_type_function(skipped_return_type)) {
-                               errorf(HERE, "function returning function is not allowed");
+                               errorf(pos, "function returning function is not allowed");
                        } else if (is_type_array(skipped_return_type)) {
-                               errorf(HERE, "function returning array is not allowed");
+                               errorf(pos, "function returning array is not allowed");
                        } else {
                                if (skipped_return_type->base.qualifiers != 0 && warning.other) {
-                                       warningf(HERE,
-                                               "type qualifiers in return type of function type are meaningless");
+                                       warningf(pos, "type qualifiers in return type of function type are meaningless");
                                }
                        }
 
@@ -3752,7 +3754,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
 
                case CONSTRUCT_POINTER: {
                        if (is_type_reference(skip_typeref(type)))
-                               errorf(HERE, "cannot declare a pointer to reference");
+                               errorf(pos, "cannot declare a pointer to reference");
 
                        parsed_pointer_t *pointer = &iter->pointer;
                        type = make_based_pointer_type(type, pointer->type_qualifiers, pointer->base_variable);
@@ -3761,14 +3763,14 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
 
                case CONSTRUCT_REFERENCE:
                        if (is_type_reference(skip_typeref(type)))
-                               errorf(HERE, "cannot declare a reference to reference");
+                               errorf(pos, "cannot declare a reference to reference");
 
                        type = make_reference_type(type);
                        continue;
 
                case CONSTRUCT_ARRAY: {
                        if (is_type_reference(skip_typeref(type)))
-                               errorf(HERE, "cannot declare an array of references");
+                               errorf(pos, "cannot declare an array of references");
 
                        parsed_array_t *array      = &iter->array;
                        type_t         *array_type = allocate_type_zero(TYPE_ARRAY);
@@ -3817,15 +3819,15 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                        type_t *skipped_type = skip_typeref(type);
                        /* §6.7.5.2:1 */
                        if (is_type_incomplete(skipped_type)) {
-                               errorf(HERE, "array of incomplete type '%T' is not allowed", type);
+                               errorf(pos, "array of incomplete type '%T' is not allowed", type);
                        } else if (is_type_function(skipped_type)) {
-                               errorf(HERE, "array of functions is not allowed");
+                               errorf(pos, "array of functions is not allowed");
                        }
                        type = identify_new_type(array_type);
                        continue;
                }
                }
-               internal_errorf(HERE, "invalid type construction found");
+               internal_errorf(pos, "invalid type construction found");
        }
 
        return type;
@@ -4000,7 +4002,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                storage_class_t storage_class = specifiers->storage_class;
                entity->declaration.declared_storage_class = storage_class;
 
-               if (storage_class == STORAGE_CLASS_NONE && current_function != NULL)
+               if (storage_class == STORAGE_CLASS_NONE && current_function != NULL)
                        storage_class = STORAGE_CLASS_AUTO;
                entity->declaration.storage_class = storage_class;
        }
@@ -4062,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)
@@ -4264,7 +4273,7 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
                        } else {
                                unsigned old_storage_class = prev_decl->storage_class;
 
-                               if (warning.redundant_decls               &&
+                               if (warning.redundant_decls               &&
                                                is_definition                     &&
                                                !prev_decl->used                  &&
                                                !(prev_decl->modifiers & DM_USED) &&
@@ -4601,7 +4610,7 @@ static entity_t *finished_kr_declaration(entity_t *entity, bool is_definition)
        entity_t *previous_entity = get_entity(symbol, NAMESPACE_NORMAL);
        if (previous_entity == NULL
                        || previous_entity->base.parent_scope != current_scope) {
-               errorf(HERE, "expected declaration of a function parameter, found '%Y'",
+               errorf(&entity->base.source_position, "expected declaration of a function parameter, found '%Y'",
                       symbol);
                return entity;
        }
@@ -5578,15 +5587,15 @@ static void parse_external_declaration(void)
 
        if (warning.aggregate_return &&
            is_type_compound(skip_typeref(type->function.return_type))) {
-               warningf(HERE, "function '%Y' returns an aggregate",
+               warningf(&ndeclaration->base.source_position, "function '%Y' returns an aggregate",
                         ndeclaration->base.symbol);
        }
        if (warning.traditional && !type->function.unspecified_parameters) {
-               warningf(HERE, "traditional C rejects ISO C style function definition of function '%Y'",
+               warningf(&ndeclaration->base.source_position, "traditional C rejects ISO C style function definition of function '%Y'",
                        ndeclaration->base.symbol);
        }
        if (warning.old_style_definition && type->function.unspecified_parameters) {
-               warningf(HERE, "old-style function definition '%Y'",
+               warningf(&ndeclaration->base.source_position, "old-style function definition '%Y'",
                        ndeclaration->base.symbol);
        }
 
@@ -5605,7 +5614,7 @@ static void parse_external_declaration(void)
        assert(entity->kind == ENTITY_FUNCTION);
        assert(ndeclaration->kind == ENTITY_FUNCTION);
 
-       function_t *function = &entity->function;
+       function_t *const function = &entity->function;
        if (ndeclaration != entity) {
                function->parameters = ndeclaration->function.parameters;
        }
@@ -5640,7 +5649,7 @@ static void parse_external_declaration(void)
                function_t *old_current_function = current_function;
                entity_t   *old_current_entity   = current_entity;
                current_function                 = function;
-               current_entity                   = (entity_t*) function;
+               current_entity                   = entity;
                current_parent                   = NULL;
 
                goto_first   = NULL;
@@ -5672,7 +5681,7 @@ static void parse_external_declaration(void)
 
                assert(current_parent   == NULL);
                assert(current_function == function);
-               assert(current_entity   == (entity_t*) function);
+               assert(current_entity   == entity);
                current_entity   = old_current_entity;
                current_function = old_current_function;
                label_pop_to(label_stack_top);
@@ -6195,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) {
@@ -6219,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");
        }
 
@@ -6430,7 +6439,8 @@ end_error:
 
 static expression_t *parse_reference(void)
 {
-       entity_t *entity = parse_qualified_identifier();
+       source_position_t const pos    = token.source_position;
+       entity_t         *const entity = parse_qualified_identifier();
 
        type_t *orig_type;
        if (is_declaration(entity)) {
@@ -6449,9 +6459,10 @@ static expression_t *parse_reference(void)
        if (entity->kind == ENTITY_ENUM_VALUE)
                kind = EXPR_REFERENCE_ENUM_VALUE;
 
-       expression_t *expression     = allocate_expression_zero(kind);
-       expression->reference.entity = entity;
-       expression->base.type        = type;
+       expression_t *expression         = allocate_expression_zero(kind);
+       expression->base.source_position = pos;
+       expression->base.type            = type;
+       expression->reference.entity     = entity;
 
        /* this declaration is used */
        if (is_declaration(entity)) {
@@ -6476,7 +6487,7 @@ static expression_t *parse_reference(void)
        if (warning.init_self && entity == current_init_decl && !in_type_prop
            && entity->kind == ENTITY_VARIABLE) {
                current_init_decl = NULL;
-               warningf(HERE, "variable '%#T' is initialized by itself",
+               warningf(&pos, "variable '%#T' is initialized by itself",
                         entity->declaration.type, entity->base.symbol);
        }
 
@@ -6554,10 +6565,11 @@ static expression_t *parse_compound_literal(type_t *type)
  */
 static expression_t *parse_cast(void)
 {
-       add_anchor_token(')');
-
        source_position_t source_position = token.source_position;
 
+       eat('(');
+       add_anchor_token(')');
+
        type_t *type = parse_typename();
 
        rem_anchor_token(')');
@@ -6588,10 +6600,11 @@ end_error:
  */
 static expression_t *parse_statement_expression(void)
 {
-       add_anchor_token(')');
-
        expression_t *expression = allocate_expression_zero(EXPR_STATEMENT);
 
+       eat('(');
+       add_anchor_token(')');
+
        statement_t *statement          = parse_compound_statement(true);
        statement->compound.stmt_expr   = true;
        expression->statement.statement = statement;
@@ -6623,22 +6636,21 @@ end_error:
  */
 static expression_t *parse_parenthesized_expression(void)
 {
-       eat('(');
-
-       switch (token.type) {
+       token_t const* const la1 = look_ahead(1);
+       switch (la1->type) {
        case '{':
                /* gcc extension: a statement expression */
                return parse_statement_expression();
 
+       case T_IDENTIFIER:
+               if (is_typedef_symbol(la1->symbol)) {
        TYPE_QUALIFIERS
        TYPE_SPECIFIERS
-               return parse_cast();
-       case T_IDENTIFIER:
-               if (is_typedef_symbol(token.symbol)) {
                        return parse_cast();
                }
        }
 
+       eat('(');
        add_anchor_token(')');
        expression_t *result = parse_expression();
        result->base.parenthesized = true;
@@ -7181,29 +7193,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;
@@ -7211,36 +7209,48 @@ 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_integer(idx_type)) {
+                       errorf(&idx->base.source_position, "array subscript must have integer type");
+               } else 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)
@@ -7431,8 +7441,8 @@ static void check_call_argument(type_t          *expected_type,
                /* report exact scope in error messages (like "in argument 3") */
                char buf[64];
                snprintf(buf, sizeof(buf), "call argument %u", pos);
-               report_assign_error(error, expected_type, arg_expr,     buf,
-                                                       &arg_expr->base.source_position);
+               report_assign_error(error, expected_type, arg_expr, buf,
+                                   &arg_expr->base.source_position);
        } else if (warning.traditional || warning.conversion) {
                type_t *const promoted_type = get_default_promoted_type(arg_type);
                if (!types_compatible(expected_type_skip, promoted_type) &&
@@ -7565,9 +7575,9 @@ static expression_t *parse_call_expression(expression_t *expression)
                }
 
                if (parameter != NULL) {
-                       errorf(HERE, "too few arguments to function '%E'", expression);
+                       errorf(&expression->base.source_position, "too few arguments to function '%E'", expression);
                } else if (argument != NULL && !function_type->variadic) {
-                       errorf(HERE, "too many arguments to function '%E'", expression);
+                       errorf(&argument->expression->base.source_position, "too many arguments to function '%E'", expression);
                }
        }
 
@@ -8083,8 +8093,8 @@ static void set_address_taken(expression_t *expression, bool may_be_register)
        if (entity->declaration.storage_class == STORAGE_CLASS_REGISTER
                        && !may_be_register) {
                errorf(&expression->base.source_position,
-                               "address of register %s '%Y' requested",
-                               get_entity_kind_name(entity->kind),     entity->base.symbol);
+                      "address of register %s '%Y' requested",
+                      get_entity_kind_name(entity->kind), entity->base.symbol);
        }
 
        if (entity->kind == ENTITY_VARIABLE) {
@@ -8265,6 +8275,30 @@ static void semantic_binexpr_arithmetic(binary_expression_t *expression)
        expression->base.type = arithmetic_type;
 }
 
+static void semantic_binexpr_integer(binary_expression_t *const expression)
+{
+       expression_t *const left            = expression->left;
+       expression_t *const right           = expression->right;
+       type_t       *const orig_type_left  = left->base.type;
+       type_t       *const orig_type_right = right->base.type;
+       type_t       *const type_left       = skip_typeref(orig_type_left);
+       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");
+               }
+               return;
+       }
+
+       type_t *const result_type = semantic_arithmetic(type_left, type_right);
+       expression->left      = create_implicit_cast(left, result_type);
+       expression->right     = create_implicit_cast(right, result_type);
+       expression->base.type = result_type;
+}
+
 static void warn_div_by_zero(binary_expression_t const *const expression)
 {
        if (!warning.div_by_zero ||
@@ -8588,33 +8622,33 @@ static bool is_valid_assignment_lhs(expression_t const* const left)
        type_t *const type_left      = skip_typeref(orig_type_left);
 
        if (!is_lvalue(left)) {
-               errorf(HERE, "left hand side '%E' of assignment is not an lvalue",
+               errorf(&left->base.source_position, "left hand side '%E' of assignment is not an lvalue",
                       left);
                return false;
        }
 
        if (left->kind == EXPR_REFERENCE
                        && left->reference.entity->kind == ENTITY_FUNCTION) {
-               errorf(HERE, "cannot assign to function '%E'", left);
+               errorf(&left->base.source_position, "cannot assign to function '%E'", left);
                return false;
        }
 
        if (is_type_array(type_left)) {
-               errorf(HERE, "cannot assign to array '%E'", left);
+               errorf(&left->base.source_position, "cannot assign to array '%E'", left);
                return false;
        }
        if (type_left->base.qualifiers & TYPE_QUALIFIER_CONST) {
-               errorf(HERE, "assignment to readonly location '%E' (type '%T')", left,
+               errorf(&left->base.source_position, "assignment to read-only location '%E' (type '%T')", left,
                       orig_type_left);
                return false;
        }
        if (is_type_incomplete(type_left)) {
-               errorf(HERE, "left-hand side '%E' of assignment has incomplete type '%T'",
+               errorf(&left->base.source_position, "left-hand side '%E' of assignment has incomplete type '%T'",
                       left, orig_type_left);
                return false;
        }
        if (is_type_compound(type_left) && has_const_fields(&type_left->compound)) {
-               errorf(HERE, "cannot assign to '%E' because compound type '%T' has readonly fields",
+               errorf(&left->base.source_position, "cannot assign to '%E' because compound type '%T' has read-only fields",
                       left, orig_type_left);
                return false;
        }
@@ -8966,9 +9000,9 @@ CREATE_BINEXPR_PARSER(T_LESSEQUAL,            EXPR_BINARY_LESSEQUAL,          PR
 CREATE_BINEXPR_PARSER(T_GREATEREQUAL,         EXPR_BINARY_GREATEREQUAL,       PREC_SHIFT,          semantic_comparison)
 CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, EXPR_BINARY_NOTEQUAL,           PREC_RELATIONAL,     semantic_comparison)
 CREATE_BINEXPR_PARSER(T_EQUALEQUAL,           EXPR_BINARY_EQUAL,              PREC_RELATIONAL,     semantic_comparison)
-CREATE_BINEXPR_PARSER('&',                    EXPR_BINARY_BITWISE_AND,        PREC_EQUALITY,       semantic_binexpr_arithmetic)
-CREATE_BINEXPR_PARSER('^',                    EXPR_BINARY_BITWISE_XOR,        PREC_AND,            semantic_binexpr_arithmetic)
-CREATE_BINEXPR_PARSER('|',                    EXPR_BINARY_BITWISE_OR,         PREC_XOR,            semantic_binexpr_arithmetic)
+CREATE_BINEXPR_PARSER('&',                    EXPR_BINARY_BITWISE_AND,        PREC_EQUALITY,       semantic_binexpr_integer)
+CREATE_BINEXPR_PARSER('^',                    EXPR_BINARY_BITWISE_XOR,        PREC_AND,            semantic_binexpr_integer)
+CREATE_BINEXPR_PARSER('|',                    EXPR_BINARY_BITWISE_OR,         PREC_XOR,            semantic_binexpr_integer)
 CREATE_BINEXPR_PARSER(T_ANDAND,               EXPR_BINARY_LOGICAL_AND,        PREC_OR,             semantic_logical_op)
 CREATE_BINEXPR_PARSER(T_PIPEPIPE,             EXPR_BINARY_LOGICAL_OR,         PREC_LOGICAL_AND,    semantic_logical_op)
 CREATE_BINEXPR_PARSER('=',                    EXPR_BINARY_ASSIGN,             PREC_ASSIGNMENT,     semantic_binexpr_assign)
@@ -9059,7 +9093,7 @@ static void register_expression_parser(parse_expression_function parser,
  * @param precedence  the precedence of the operator
  */
 static void register_infix_parser(parse_expression_infix_function parser,
-               int token_type, precedence_t precedence)
+                                  int token_type, precedence_t precedence)
 {
        expression_parser_function_t *entry = &expression_parsers[token_type];
 
@@ -9337,7 +9371,8 @@ static statement_t *parse_label_inner_statement(statement_t const *const label,
 
                default:
                        inner_stmt = parse_statement();
-                       if (inner_stmt->kind == STATEMENT_DECLARATION) {
+                       /* ISO/IEC 14882:1998(E) §6:1/§6.7  Declarations are statements */
+                       if (inner_stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
                                errorf(&inner_stmt->base.source_position, "declaration after %s", label_kind);
                        }
                        break;
@@ -10010,13 +10045,13 @@ static statement_t *parse_return(void)
                        }
                } else {
                        assign_error_t error = semantic_assign(return_type, return_value);
-                       report_assign_error(error, return_type, return_value, "'return'",
-                                       pos);
+                       report_assign_error(error, return_type, return_value, "'return'",
+                                           pos);
                }
                return_value = create_implicit_cast(return_value, return_type);
                /* check for returning address of a local var */
                if (warning.other && return_value != NULL
-                               && return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
+                   && return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
                        const expression_t *expression = return_value->unary.value;
                        if (expression_is_local_variable(expression)) {
                                warningf(pos, "function returns address of local variable");
@@ -10026,10 +10061,10 @@ static statement_t *parse_return(void)
                /* ISO/IEC 14882:1998(E) §6.6.3:3 */
                if (c_mode & _CXX || strict_mode) {
                        errorf(pos,
-                                       "'return' without value, in function returning non-void");
+                              "'return' without value, in function returning non-void");
                } else {
                        warningf(pos,
-                                       "'return' without value, in function returning non-void");
+                                "'return' without value, in function returning non-void");
                }
        }
        statement->returns.value = return_value;
@@ -10660,7 +10695,6 @@ end_error:;
 static void parse_linkage_specification(void)
 {
        eat(T_extern);
-       assert(token.type == T_STRING_LITERAL);
 
        const char *linkage = parse_string_literals().begin;
 
@@ -10926,9 +10960,6 @@ void init_parser(void)
 
        init_expression_parsers();
        obstack_init(&temp_obst);
-
-       symbol_t *const va_list_sym = symbol_table_insert("__builtin_va_list");
-       type_valist = create_builtin_type(va_list_sym, type_void_ptr);
 }
 
 /**