parser: Remove the unused attribute alignment from struct declaration_specifiers_t.
[cparser] / parser.c
index 1fc7ed3..b95b756 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -1,21 +1,6 @@
 /*
  * This file is part of cparser.
- * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * Copyright (C) 2012 Matthias Braun <matze@braunis.de>
  */
 #include <config.h>
 
 #include <stdbool.h>
 
 #include "adt/strutil.h"
+#include "adt/util.h"
 #include "parser.h"
 #include "diagnostic.h"
 #include "format_check.h"
 #include "preprocessor.h"
 #include "symbol_t.h"
+#include "symbol_table.h"
 #include "token_t.h"
 #include "types.h"
 #include "type_t.h"
 #include "type_hash.h"
 #include "ast_t.h"
-#include "entity_t.h"
 #include "attribute_t.h"
 #include "lang_features.h"
 #include "walk.h"
 #include "warning.h"
 #include "printer.h"
-#include "adt/bitfiddle.h"
+#include "ast2firm.h"
 #include "adt/error.h"
 #include "adt/array.h"
 
@@ -56,13 +42,12 @@ typedef struct {
 
 typedef struct declaration_specifiers_t  declaration_specifiers_t;
 struct declaration_specifiers_t {
-       source_position_t  source_position;
-       storage_class_t    storage_class;
-       unsigned char      alignment;         /**< Alignment, 0 if not set. */
-       bool               is_inline    : 1;
-       bool               thread_local : 1;
-       attribute_t       *attributes;        /**< list of attributes */
-       type_t            *type;
+       position_t      pos;
+       storage_class_t storage_class;
+       bool            is_inline    : 1;
+       bool            thread_local : 1;
+       attribute_t    *attributes;        /**< list of attributes */
+       type_t         *type;
 };
 
 /**
@@ -132,7 +117,7 @@ static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
 #define PUSH_EXTENSION() \
        (void)0; \
        bool const old_gcc_extension = in_gcc_extension; \
-       while (next_if(T___extension__)) { \
+       while (accept(T___extension__)) { \
                in_gcc_extension = true; \
        } \
        do {} while (0)
@@ -143,7 +128,7 @@ static elf_visibility_tag_t default_visibility = ELF_VISIBILITY_DEFAULT;
 static unsigned short token_anchor_set[T_LAST_TOKEN];
 
 /** The current source position. */
-#define HERE (&token.base.source_position)
+#define HERE (&token.base.pos)
 
 /** true if we are in GCC mode. */
 #define GNU_MODE ((c_mode & _GNUC) || in_gcc_extension)
@@ -172,7 +157,8 @@ typedef enum declarator_flags_t {
 static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                   declarator_flags_t flags);
 
-static void semantic_comparison(binary_expression_t *expression);
+static void semantic_comparison(binary_expression_t *expression,
+                                bool is_relational);
 
 #define STORAGE_CLASSES       \
        STORAGE_CLASSES_NO_EXTERN \
@@ -272,7 +258,9 @@ static void semantic_comparison(binary_expression_t *expression);
        case T_false:                     \
        case T_sizeof:                    \
        case T_throw:                     \
-       case T_true:
+       case T_true:                      \
+       case T___imag__:                  \
+       case T___real__:
 
 /**
  * Returns the size of a statement node.
@@ -296,7 +284,6 @@ static size_t get_statement_struct_size(statement_kind_t kind)
                [STATEMENT_GOTO]          = sizeof(goto_statement_t),
                [STATEMENT_LABEL]         = sizeof(label_statement_t),
                [STATEMENT_CASE_LABEL]    = sizeof(case_label_statement_t),
-               [STATEMENT_WHILE]         = sizeof(while_statement_t),
                [STATEMENT_DO_WHILE]      = sizeof(do_while_statement_t),
                [STATEMENT_FOR]           = sizeof(for_statement_t),
                [STATEMENT_ASM]           = sizeof(asm_statement_t),
@@ -323,6 +310,7 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_LITERAL_INTEGER]            = sizeof(literal_expression_t),
                [EXPR_LITERAL_FLOATINGPOINT]      = sizeof(literal_expression_t),
                [EXPR_LITERAL_CHARACTER]          = sizeof(string_literal_expression_t),
+               [EXPR_LITERAL_MS_NOOP]            = sizeof(literal_expression_t),
                [EXPR_STRING_LITERAL]             = sizeof(string_literal_expression_t),
                [EXPR_COMPOUND_LITERAL]           = sizeof(compound_literal_expression_t),
                [EXPR_CALL]                       = sizeof(call_expression_t),
@@ -365,9 +353,9 @@ static statement_t *allocate_statement_zero(statement_kind_t kind)
        size_t       size = get_statement_struct_size(kind);
        statement_t *res  = allocate_ast_zero(size);
 
-       res->base.kind            = kind;
-       res->base.parent          = current_parent;
-       res->base.source_position = *HERE;
+       res->base.kind   = kind;
+       res->base.parent = current_parent;
+       res->base.pos    = *HERE;
        return res;
 }
 
@@ -382,9 +370,9 @@ static expression_t *allocate_expression_zero(expression_kind_t kind)
        size_t        size = get_expression_struct_size(kind);
        expression_t *res  = allocate_ast_zero(size);
 
-       res->base.kind            = kind;
-       res->base.type            = type_error_type;
-       res->base.source_position = *HERE;
+       res->base.kind = kind;
+       res->base.type = type_error_type;
+       res->base.pos  = *HERE;
        return res;
 }
 
@@ -485,7 +473,13 @@ static inline void eat(token_kind_t const kind)
        next_token();
 }
 
-static inline bool next_if(token_kind_t const kind)
+/**
+ * Consume the current token, if it is of the expected kind.
+ *
+ * @param  kind  The kind of token to consume.
+ * @return Whether the token was consumed.
+ */
+static inline bool accept(token_kind_t const kind)
 {
        if (token.kind == kind) {
                eat(kind);
@@ -596,7 +590,7 @@ static void eat_until_anchor(void)
 static void eat_block(void)
 {
        eat_until_matching_token('{');
-       next_if('}');
+       accept('}');
 }
 
 /**
@@ -621,10 +615,9 @@ void parse_error_expected(const char *message, ...)
  * Report an incompatible type.
  */
 static void type_error_incompatible(const char *msg,
-               const source_position_t *source_position, type_t *type1, type_t *type2)
+               const position_t *pos, type_t *type1, type_t *type2)
 {
-       errorf(source_position, "%s, incompatible types: '%T' - '%T'",
-              msg, type1, type2);
+       errorf(pos, "%s, incompatible types: '%T' - '%T'", msg, type1, type2);
 }
 
 static bool skip_till(token_kind_t const expected, char const *const context)
@@ -650,7 +643,8 @@ static void expect(token_kind_t const expected)
                eat(expected);
 }
 
-static symbol_t *expect_identifier(char const *const context, source_position_t *const pos)
+static symbol_t *expect_identifier(char const *const context,
+                                   position_t *const pos)
 {
        if (!skip_till(T_IDENTIFIER, context))
                return NULL;
@@ -708,7 +702,7 @@ static entity_t *get_tag(symbol_t const *const symbol,
        if (entity != NULL && (entity_kind_tag_t)entity->kind != kind) {
                errorf(HERE,
                                "'%Y' defined as wrong kind of tag (previous definition %P)",
-                               symbol, &entity->base.source_position);
+                               symbol, &entity->base.pos);
                entity = NULL;
        }
        return entity;
@@ -753,7 +747,7 @@ static void stack_push(stack_entry_t **stack_ptr, entity_t *entity)
  */
 static void environment_push(entity_t *entity)
 {
-       assert(entity->base.source_position.input_name != NULL);
+       assert(entity->base.pos.input_name != NULL);
        assert(entity->base.parent_scope != NULL);
        stack_push(&environment_stack, entity);
 }
@@ -836,13 +830,6 @@ static void label_pop_to(size_t new_top)
        stack_pop_to(&label_stack, new_top);
 }
 
-static atomic_type_kind_t get_akind(const type_t *type)
-{
-       assert(type->kind == TYPE_ATOMIC || type->kind == TYPE_COMPLEX
-              || type->kind == TYPE_IMAGINARY || type->kind == TYPE_ENUM);
-       return type->atomic.akind;
-}
-
 /**
  * §6.3.1.1:2  Do integer promotion for a given type.
  *
@@ -851,7 +838,8 @@ static atomic_type_kind_t get_akind(const type_t *type)
  */
 static type_t *promote_integer(type_t *type)
 {
-       if (get_akind_rank(get_akind(type)) < get_akind_rank(ATOMIC_TYPE_INT))
+       atomic_type_kind_t akind = get_arithmetic_akind(type);
+       if (get_akind_rank(akind) < get_akind_rank(ATOMIC_TYPE_INT))
                type = type_int;
 
        return type;
@@ -867,18 +855,17 @@ static bool is_null_pointer_constant(const expression_t *expression)
        /* skip void* cast */
        if (expression->kind == EXPR_UNARY_CAST) {
                type_t *const type = skip_typeref(expression->base.type);
-               if (types_compatible(type, type_void_ptr))
+               if (type == type_void_ptr)
                        expression = expression->unary.value;
        }
 
-       type_t *const type = skip_typeref(expression->base.type);
-       if (!is_type_integer(type))
-               return false;
        switch (is_constant_expression(expression)) {
-               case EXPR_CLASS_ERROR:    return true;
-               case EXPR_CLASS_CONSTANT: return !fold_constant_to_bool(expression);
-               default:                  return false;
+               case EXPR_CLASS_VARIABLE:         return false;
+               case EXPR_CLASS_ERROR:            return true;
+               case EXPR_CLASS_CONSTANT:         return false;
+               case EXPR_CLASS_INTEGER_CONSTANT: return !fold_constant_to_bool(expression);
        }
+       panic("invalid expression classification");
 }
 
 /**
@@ -890,9 +877,8 @@ static bool is_null_pointer_constant(const expression_t *expression)
 static expression_t *create_implicit_cast(expression_t *expression,
                                           type_t *dest_type)
 {
-       type_t *const source_type = expression->base.type;
-
-       if (source_type == dest_type)
+       type_t *const source_type = skip_typeref(expression->base.type);
+       if (source_type == skip_typeref(dest_type))
                return expression;
 
        expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
@@ -912,7 +898,7 @@ typedef enum assign_error_t {
        ASSIGN_WARNING_INT_FROM_POINTER
 } assign_error_t;
 
-static void report_assign_error(assign_error_t error, type_t *orig_type_left, expression_t const *const right, char const *const context, source_position_t const *const pos)
+static void report_assign_error(assign_error_t error, type_t *orig_type_left, expression_t const *const right, char const *const context, position_t const *const pos)
 {
        type_t *const orig_type_right = right->base.type;
        type_t *const type_left       = skip_typeref(orig_type_left);
@@ -1021,8 +1007,7 @@ static expression_t *parse_constant_expression(void)
        expression_t *result = parse_subexpression(PREC_CONDITIONAL);
 
        if (is_constant_expression(result) == EXPR_CLASS_VARIABLE) {
-               errorf(&result->base.source_position,
-                      "expression '%E' is not constant", result);
+               errorf(&result->base.pos, "expression '%E' is not constant", result);
        }
 
        return result;
@@ -1059,8 +1044,13 @@ static string_t concat_string_literals(void)
                warningf(WARN_TRADITIONAL, HERE, "traditional C rejects string constant concatenation");
                string_encoding_t enc = token.literal.string.encoding;
                do {
-                       if (token.literal.string.encoding != STRING_ENCODING_CHAR) {
-                               enc = token.literal.string.encoding;
+                       string_encoding_t const new_enc = token.literal.string.encoding;
+                       if (new_enc != enc && new_enc != STRING_ENCODING_CHAR) {
+                               if (enc == STRING_ENCODING_CHAR) {
+                                       enc = new_enc;
+                               } else {
+                                       errorf(HERE, "concatenating string literals with encodings %s and %s", get_string_encoding_prefix(enc), get_string_encoding_prefix(new_enc));
+                               }
                        }
                        append_string(&token.literal.string);
                        eat(T_STRING_LITERAL);
@@ -1079,11 +1069,11 @@ static string_t parse_string_literals(char const *const context)
        if (!skip_till(T_STRING_LITERAL, context))
                return (string_t){ "", 0, STRING_ENCODING_CHAR };
 
-       source_position_t const pos = *HERE;
-       string_t          const res = concat_string_literals();
+       position_t const pos = *HERE;
+       string_t   const res = concat_string_literals();
 
        if (res.encoding != STRING_ENCODING_CHAR) {
-               errorf(&pos, "expected plain string literal, got wide string literal");
+               errorf(&pos, "expected plain string literal, got %s string literal", get_string_encoding_prefix(res.encoding));
        }
 
        return res;
@@ -1092,8 +1082,8 @@ static string_t parse_string_literals(char const *const context)
 static attribute_t *allocate_attribute_zero(attribute_kind_t kind)
 {
        attribute_t *attribute = allocate_ast_zero(sizeof(*attribute));
-       attribute->kind            = kind;
-       attribute->source_position = *HERE;
+       attribute->kind = kind;
+       attribute->pos  = *HERE;
        return attribute;
 }
 
@@ -1149,7 +1139,7 @@ static attribute_argument_t *parse_attribute_arguments(void)
                /* append argument */
                *anchor = argument;
                anchor  = &argument->next;
-       } while (next_if(','));
+       } while (accept(','));
        expect(')');
        return first;
 }
@@ -1197,7 +1187,7 @@ static attribute_t *parse_attribute_gnu_single(void)
        next_token();
 
        /* parse arguments */
-       if (next_if('('))
+       if (accept('('))
                attribute->a.arguments = parse_attribute_arguments();
 
        return attribute;
@@ -1220,7 +1210,7 @@ static attribute_t *parse_attribute_gnu(void)
                        *anchor = attribute;
                        anchor  = &attribute->next;
                }
-       } while (next_if(','));
+       } while (accept(','));
        rem_anchor_token(',');
        rem_anchor_token(')');
 
@@ -1429,7 +1419,7 @@ static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent)
 
                case EXPR_UNARY_NEGATE:
                case EXPR_UNARY_PLUS:
-               case EXPR_UNARY_BITWISE_NEGATE:
+               case EXPR_UNARY_COMPLEMENT:
                case EXPR_UNARY_NOT:
                case EXPR_UNARY_TAKE_ADDRESS:
                case EXPR_UNARY_POSTFIX_INCREMENT:
@@ -1437,6 +1427,8 @@ static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent)
                case EXPR_UNARY_PREFIX_INCREMENT:
                case EXPR_UNARY_PREFIX_DECREMENT:
                case EXPR_UNARY_ASSUME:
+               case EXPR_UNARY_IMAG:
+               case EXPR_UNARY_REAL:
 unary:
                        mark_vars_read(expr->unary.value, lhs_ent);
                        return;
@@ -1522,17 +1514,23 @@ static designator_t *parse_designation(void)
                designator_t *designator;
                switch (token.kind) {
                case '[':
-                       designator = allocate_ast_zero(sizeof(designator[0]));
-                       designator->source_position = *HERE;
+                       designator      = allocate_ast_zero(sizeof(designator[0]));
+                       designator->pos = *HERE;
                        eat('[');
                        add_anchor_token(']');
+                       add_anchor_token(T_DOTDOTDOT);
                        designator->array_index = parse_constant_expression();
+                       if (accept(T_DOTDOTDOT)) {
+                               designator->range_last = parse_constant_expression();
+                               errorf(&designator->pos, "range initializer not supported");
+                       }
+                       rem_anchor_token(T_DOTDOTDOT);
                        rem_anchor_token(']');
                        expect(']');
                        break;
                case '.':
-                       designator = allocate_ast_zero(sizeof(designator[0]));
-                       designator->source_position = *HERE;
+                       designator      = allocate_ast_zero(sizeof(designator[0]));
+                       designator->pos = *HERE;
                        eat('.');
                        designator->symbol = expect_identifier("while parsing designator", NULL);
                        if (!designator->symbol)
@@ -1564,7 +1562,8 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
                array_type_t *const array_type   = &type->array;
                type_t       *const element_type = skip_typeref(array_type->element_type);
                switch (expression->string_literal.value.encoding) {
-               case STRING_ENCODING_CHAR: {
+               case STRING_ENCODING_CHAR:
+               case STRING_ENCODING_UTF8: {
                        if (is_type_atomic(element_type, ATOMIC_TYPE_CHAR)  ||
                            is_type_atomic(element_type, ATOMIC_TYPE_SCHAR) ||
                            is_type_atomic(element_type, ATOMIC_TYPE_UCHAR)) {
@@ -1573,9 +1572,12 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
                        break;
                }
 
+               case STRING_ENCODING_CHAR16:
+               case STRING_ENCODING_CHAR32:
                case STRING_ENCODING_WIDE: {
-                       type_t *bare_wchar_type = skip_typeref(type_wchar_t);
-                       if (get_unqualified_type(element_type) == bare_wchar_type) {
+                       assert(is_type_pointer(expression->base.type));
+                       type_t *const init_type = get_unqualified_type(expression->base.type->pointer.points_to);
+                       if (types_compatible(get_unqualified_type(element_type), init_type)) {
 make_string_init:;
                                initializer_t *const init = allocate_initializer_zero(INITIALIZER_STRING);
                                init->value.value = expression;
@@ -1590,7 +1592,7 @@ make_string_init:;
        if (error == ASSIGN_ERROR_INCOMPATIBLE)
                return NULL;
        report_assign_error(error, type, expression, "initializer",
-                           &expression->base.source_position);
+                           &expression->base.pos);
 
        initializer_t *const result = allocate_initializer_zero(INITIALIZER_VALUE);
        result->value.value = create_implicit_cast(expression, type);
@@ -1619,7 +1621,7 @@ static initializer_t *parse_scalar_initializer(type_t *type,
        expression_t *expression = parse_assignment_expression();
        mark_vars_read(expression, NULL);
        if (must_be_constant && !is_linker_constant(expression)) {
-               errorf(&expression->base.source_position,
+               errorf(&expression->base.pos,
                       "initialisation expression '%E' is not constant",
                       expression);
        }
@@ -1627,7 +1629,7 @@ static initializer_t *parse_scalar_initializer(type_t *type,
        initializer_t *initializer = initializer_from_expression(type, expression);
 
        if (initializer == NULL) {
-               errorf(&expression->base.source_position,
+               errorf(&expression->base.pos,
                       "expression '%E' (type '%T') doesn't match expected type '%T'",
                       expression, expression->base.type, type);
                /* TODO */
@@ -1636,7 +1638,7 @@ static initializer_t *parse_scalar_initializer(type_t *type,
 
        bool additional_warning_displayed = false;
        while (braces > 0) {
-               next_if(',');
+               accept(',');
                if (token.kind != '}') {
                        if (!additional_warning_displayed) {
                                warningf(WARN_OTHER, HERE, "additional elements in scalar initializer");
@@ -1706,7 +1708,7 @@ static __attribute__((unused)) void debug_print_type_path(
 }
 
 /**
- * Return the top type path entry, ie. in a path
+ * Return the top type path entry, i.e. in a path
  * (type).a.b returns the b.
  */
 static type_path_entry_t *get_type_path_top(const type_path_t *path)
@@ -1759,7 +1761,7 @@ static void descend_into_subtype(type_path_t *path)
 }
 
 /**
- * Pop an entry from the given type path, ie. returning from
+ * Pop an entry from the given type path, i.e. returning from
  * (type).a.b to (type).a
  */
 static void ascend_from_subtype(type_path_t *path)
@@ -1799,7 +1801,7 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                        symbol_t *symbol = designator->symbol;
                        if (!is_type_compound(type)) {
                                if (is_type_valid(type)) {
-                                       errorf(&designator->source_position,
+                                       errorf(&designator->pos,
                                               "'.%Y' designator used for non-compound type '%T'",
                                               symbol, orig_type);
                                }
@@ -1816,13 +1818,13 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                                        }
                                }
                                if (iter == NULL) {
-                                       errorf(&designator->source_position,
+                                       errorf(&designator->pos,
                                               "'%T' has no member named '%Y'", orig_type, symbol);
                                        return false;
                                }
                                assert(iter->kind == ENTITY_COMPOUND_MEMBER);
                                if (used_in_offsetof && iter->compound_member.bitfield) {
-                                       errorf(&designator->source_position,
+                                       errorf(&designator->pos,
                                                   "offsetof designator '%Y' must not specify bitfield",
                                                   symbol);
                                        return false;
@@ -1834,12 +1836,12 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                        }
                } else {
                        expression_t *array_index = designator->array_index;
-                       if (is_constant_expression(array_index) != EXPR_CLASS_CONSTANT)
+                       if (is_constant_expression(array_index) < EXPR_CLASS_CONSTANT)
                                return true;
 
                        if (!is_type_array(type)) {
                                if (is_type_valid(type)) {
-                                       errorf(&designator->source_position,
+                                       errorf(&designator->pos,
                                               "[%E] designator used for non-array type '%T'",
                                               array_index, orig_type);
                                }
@@ -1849,12 +1851,12 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                        long index = fold_constant_to_int(array_index);
                        if (!used_in_offsetof) {
                                if (index < 0) {
-                                       errorf(&designator->source_position,
+                                       errorf(&designator->pos,
                                               "array index [%E] must be positive", array_index);
                                } else if (type->array.size_constant) {
                                        long array_size = type->array.size;
                                        if (index >= array_size) {
-                                               errorf(&designator->source_position,
+                                               errorf(&designator->pos,
                                                       "designator [%E] (%d) exceeds array size %d",
                                                       array_index, index, array_size);
                                        }
@@ -1928,7 +1930,7 @@ static void advance_current_object(type_path_t *path, size_t top_path_level)
  */
 static void skip_initializers(void)
 {
-       next_if('{');
+       accept('{');
 
        while (token.kind != '}') {
                if (token.kind == T_EOF)
@@ -1980,9 +1982,9 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                        goto finish_designator;
                } else if (token.kind == T_IDENTIFIER && look_ahead(1)->kind == ':') {
                        /* GNU-style designator ("identifier: value") */
-                       designator = allocate_ast_zero(sizeof(designator[0]));
-                       designator->source_position = *HERE;
-                       designator->symbol          = token.base.symbol;
+                       designator         = allocate_ast_zero(sizeof(designator[0]));
+                       designator->pos    = *HERE;
+                       designator->symbol = token.base.symbol;
                        eat(T_IDENTIFIER);
                        eat(':');
 
@@ -2039,7 +2041,7 @@ finish_designator:
                        mark_vars_read(expression, NULL);
 
                        if (env->must_be_constant && !is_linker_constant(expression)) {
-                               errorf(&expression->base.source_position,
+                               errorf(&expression->base.pos,
                                       "Initialisation expression '%E' is not constant",
                                       expression);
                        }
@@ -2054,7 +2056,7 @@ finish_designator:
                                        goto error_parse_next;
                                }
 
-                               source_position_t const* const pos = &expression->base.source_position;
+                               position_t const* const pos = &expression->base.pos;
                                if (env->entity != NULL) {
                                        warningf(WARN_OTHER, pos, "excess elements in initializer for '%N'", env->entity);
                                } else {
@@ -2067,7 +2069,7 @@ finish_designator:
                        if (expression->kind == EXPR_STRING_LITERAL && outer_type != NULL) {
                                result = initializer_from_expression(outer_type, expression);
                                if (result != NULL) {
-                                       next_if(',');
+                                       accept(',');
                                        if (token.kind != '}') {
                                                warningf(WARN_OTHER, HERE, "excessive elements in initializer for type '%T'", outer_type);
                                        }
@@ -2089,7 +2091,7 @@ finish_designator:
                                        goto end_error;
                                }
                                if (is_type_scalar(type)) {
-                                       errorf(&expression->base.source_position,
+                                       errorf(&expression->base.pos,
                                                        "expression '%E' doesn't match expected type '%T'",
                                                        expression, orig_type);
                                        goto end_error;
@@ -2113,7 +2115,7 @@ finish_designator:
                ARR_APP1(initializer_t*, initializers, sub);
 
 error_parse_next:
-               if (!next_if(','))
+               if (!accept(','))
                        break;
                if (token.kind == '}') {
                        break;
@@ -2247,7 +2249,7 @@ 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;
+       position_t const pos = *HERE;
        eat(is_struct ? T_struct : T_union);
 
        symbol_t    *symbol     = NULL;
@@ -2272,7 +2274,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
                                 * existing definition in outer scope */
                                entity = NULL;
                        } else if (entity->compound.complete && token.kind == '{') {
-                               source_position_t const *const ppos = &entity->base.source_position;
+                               position_t const *const ppos = &entity->base.pos;
                                errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
                                /* clear members in the hope to avoid further errors */
                                entity->compound.members.entities = NULL;
@@ -2308,6 +2310,7 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
        }
 
        if (attributes != NULL) {
+               entity->compound.attributes = attributes;
                handle_entity_attributes(attributes, entity);
        }
 
@@ -2328,13 +2331,13 @@ static void parse_enum_entries(type_t *const enum_type)
        add_anchor_token(',');
        do {
                add_anchor_token('=');
-               source_position_t pos;
+               position_t pos;
                symbol_t *const symbol = expect_identifier("while parsing enum entry", &pos);
                entity_t *const entity = allocate_entity_zero(ENTITY_ENUM_VALUE, NAMESPACE_NORMAL, symbol, &pos);
                entity->enum_value.enum_type = enum_type;
                rem_anchor_token('=');
 
-               if (next_if('=')) {
+               if (accept('=')) {
                        expression_t *value = parse_constant_expression();
 
                        value = create_implicit_cast(value, enum_type);
@@ -2344,7 +2347,7 @@ static void parse_enum_entries(type_t *const enum_type)
                }
 
                record_entity(entity, false);
-       } while (next_if(',') && token.kind != '}');
+       } while (accept(',') && token.kind != '}');
        rem_anchor_token(',');
        rem_anchor_token('}');
 
@@ -2353,9 +2356,9 @@ static void parse_enum_entries(type_t *const enum_type)
 
 static type_t *parse_enum_specifier(void)
 {
-       source_position_t const pos = *HERE;
-       entity_t               *entity;
-       symbol_t               *symbol;
+       position_t const pos = *HERE;
+       entity_t        *entity;
+       symbol_t        *symbol;
 
        eat(T_enum);
        switch (token.kind) {
@@ -2371,7 +2374,7 @@ static type_t *parse_enum_specifier(void)
                                         * existing definition in outer scope */
                                        entity = NULL;
                                } else if (entity->enume.complete && token.kind == '{') {
-                                       source_position_t const *const ppos = &entity->base.source_position;
+                                       position_t const *const ppos = &entity->base.pos;
                                        errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
                                }
                        }
@@ -2507,7 +2510,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
 
        do {
                add_anchor_token('=');
-               source_position_t pos;
+               position_t pos;
                symbol_t *const prop_sym = expect_identifier("while parsing property declspec", &pos);
                rem_anchor_token('=');
 
@@ -2529,7 +2532,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
                symbol_t *const sym = expect_identifier("while parsing property declspec", NULL);
                if (prop != NULL)
                        *prop = sym ? sym : sym_anonymous;
-       } while (next_if(','));
+       } while (accept(','));
        rem_anchor_token(',');
        rem_anchor_token(')');
 
@@ -2542,7 +2545,7 @@ static attribute_t *parse_attribute_ms_property(attribute_t *attribute)
 static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
 {
        attribute_kind_t kind = ATTRIBUTE_UNKNOWN;
-       if (next_if(T_restrict)) {
+       if (accept(T_restrict)) {
                kind = ATTRIBUTE_MS_RESTRICT;
        } else if (token.kind == T_IDENTIFIER) {
                char const *const name = token.base.symbol->string;
@@ -2571,7 +2574,7 @@ static attribute_t *parse_microsoft_extended_decl_modifier_single(void)
        }
 
        /* parse arguments */
-       if (next_if('('))
+       if (accept('('))
                attribute->a.arguments = parse_attribute_arguments();
 
        return attribute;
@@ -2596,7 +2599,7 @@ static attribute_t *parse_microsoft_extended_decl_modifier(attribute_t *first)
 
                        *anchor = attribute;
                        anchor  = &attribute->next;
-               } while (next_if(','));
+               } while (accept(','));
        }
        rem_anchor_token(')');
        expect(')');
@@ -2627,7 +2630,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
        bool               saw_error       = false;
 
        memset(specifiers, 0, sizeof(*specifiers));
-       specifiers->source_position = *HERE;
+       specifiers->pos = *HERE;
 
        while (true) {
                specifiers->attributes = parse_attributes(specifiers->attributes);
@@ -2846,11 +2849,19 @@ finish_specifiers:
        specifiers->attributes = parse_attributes(specifiers->attributes);
 
        if (type == NULL || (saw_error && type_specifiers != 0)) {
+               position_t const* const pos = &specifiers->pos;
                atomic_type_kind_t atomic_type;
 
                /* match valid basic types */
-               switch (type_specifiers) {
+               switch (type_specifiers & ~(SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY)) {
                case SPECIFIER_VOID:
+                       if (type_specifiers & (SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY)) {
+                               if (type_specifiers & SPECIFIER_COMPLEX)
+                                       errorf(pos, "_Complex specifier is invalid for void");
+                               if (type_specifiers & SPECIFIER_IMAGINARY)
+                                       errorf(pos, "_Imaginary specifier is invalid for void");
+                               type_specifiers &= ~(SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY);
+                       }
                        atomic_type = ATOMIC_TYPE_VOID;
                        break;
                case SPECIFIER_WCHAR_T:
@@ -2908,7 +2919,7 @@ finish_specifiers:
                        | SPECIFIER_INT:
                        atomic_type = ATOMIC_TYPE_ULONGLONG;
 warn_about_long_long:
-                       warningf(WARN_LONG_LONG, &specifiers->source_position, "ISO C90 does not support 'long long'");
+                       warningf(WARN_LONG_LONG, &specifiers->pos, "ISO C90 does not support 'long long'");
                        break;
 
                case SPECIFIER_UNSIGNED | SPECIFIER_INT8:
@@ -2966,23 +2977,17 @@ warn_about_long_long:
                        atomic_type = ATOMIC_TYPE_LONG_DOUBLE;
                        break;
                case SPECIFIER_BOOL:
+                       if (type_specifiers & (SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY)) {
+                               if (type_specifiers & SPECIFIER_COMPLEX)
+                                       errorf(pos, "_Complex specifier is invalid for _Bool");
+                               if (type_specifiers & SPECIFIER_IMAGINARY)
+                                       errorf(pos, "_Imaginary specifier is invalid for _Bool");
+                               type_specifiers &= ~(SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY);
+                       }
                        atomic_type = ATOMIC_TYPE_BOOL;
                        break;
-               case SPECIFIER_FLOAT | SPECIFIER_COMPLEX:
-               case SPECIFIER_FLOAT | SPECIFIER_IMAGINARY:
-                       atomic_type = ATOMIC_TYPE_FLOAT;
-                       break;
-               case SPECIFIER_DOUBLE | SPECIFIER_COMPLEX:
-               case SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY:
-                       atomic_type = ATOMIC_TYPE_DOUBLE;
-                       break;
-               case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_COMPLEX:
-               case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY:
-                       atomic_type = ATOMIC_TYPE_LONG_DOUBLE;
-                       break;
                default: {
                        /* invalid specifier combination, give an error message */
-                       source_position_t const* const pos = &specifiers->source_position;
                        if (type_specifiers == 0) {
                                if (!saw_error) {
                                        /* ISO/IEC 14882:1998(E) §C.1.5:4 */
@@ -2994,6 +2999,10 @@ warn_about_long_long:
                                                errorf(pos, "no type specifiers given in declaration");
                                        }
                                }
+                       } else if (type_specifiers == SPECIFIER_COMPLEX) {
+                               warningf(WARN_OTHER, pos, "_Complex requires a type specifier; assuming '_Complex double'");
+                               atomic_type = ATOMIC_TYPE_DOUBLE;
+                               break;
                        } else if ((type_specifiers & SPECIFIER_SIGNED) &&
                                  (type_specifiers & SPECIFIER_UNSIGNED)) {
                                errorf(pos, "signed and unsigned specifiers given");
@@ -3017,7 +3026,7 @@ warn_about_long_long:
                type->atomic.akind = atomic_type;
                newtype = true;
        } else if (type_specifiers != 0) {
-               errorf(&specifiers->source_position, "multiple datatypes in declaration");
+               errorf(&specifiers->pos, "multiple datatypes in declaration");
        }
 
        /* FIXME: check type qualifiers here */
@@ -3070,7 +3079,7 @@ static void parse_identifier_list(scope_t *scope)
 
                if (scope != NULL)
                        append_entity(scope, entity);
-       } while (next_if(',') && token.kind == T_IDENTIFIER);
+       } while (accept(',') && token.kind == T_IDENTIFIER);
 }
 
 static entity_t *parse_parameter(void)
@@ -3094,7 +3103,7 @@ static void semantic_parameter_incomplete(const entity_t *entity)
         *             incomplete type. */
        type_t *type = skip_typeref(entity->declaration.type);
        if (is_type_incomplete(type)) {
-               errorf(&entity->base.source_position, "'%N' has incomplete type", entity);
+               errorf(&entity->base.pos, "'%N' has incomplete type", entity);
        }
 }
 
@@ -3160,7 +3169,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
                        {
                                entity_t *entity = parse_parameter();
                                if (entity->kind == ENTITY_TYPEDEF) {
-                                       errorf(&entity->base.source_position,
+                                       errorf(&entity->base.pos,
                                                        "typedef not allowed as function parameter");
                                        break;
                                }
@@ -3183,7 +3192,7 @@ static void parse_parameters(function_type_t *type, scope_t *scope)
                        default:
                                goto parameters_finished;
                        }
-               } while (next_if(','));
+               } while (accept(','));
 parameters_finished:
                rem_anchor_token(',');
        }
@@ -3202,9 +3211,9 @@ typedef enum construct_type_kind_t {
 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_kind_t kind;
+       position_t            pos;
+       construct_type_t     *next;
 } construct_type_base_t;
 
 typedef struct parsed_pointer_t {
@@ -3280,12 +3289,12 @@ static construct_type_t *parse_array_declarator(void)
        eat('[');
        add_anchor_token(']');
 
-       bool is_static = next_if(T_static);
+       bool is_static = accept(T_static);
 
        type_qualifiers_t type_qualifiers = parse_type_qualifiers();
 
        if (!is_static)
-               is_static = next_if(T_static);
+               is_static = accept(T_static);
 
        array->type_qualifiers = type_qualifiers;
        array->is_static       = is_static;
@@ -3301,7 +3310,7 @@ static construct_type_t *parse_array_declarator(void)
                type_t *const orig_type = size->base.type;
                type_t *const type      = skip_typeref(orig_type);
                if (!is_type_integer(type) && is_type_valid(type)) {
-                       errorf(&size->base.source_position,
+                       errorf(&size->base.pos,
                               "array size '%E' must have integer type but has type '%T'",
                               size, orig_type);
                }
@@ -3337,13 +3346,13 @@ static construct_type_t *parse_function_declarator(scope_t *scope)
 }
 
 typedef struct parse_declarator_env_t {
-       bool               may_be_abstract : 1;
-       bool               must_be_abstract : 1;
-       decl_modifiers_t   modifiers;
-       symbol_t          *symbol;
-       source_position_t  source_position;
-       scope_t            parameters;
-       attribute_t       *attributes;
+       bool              may_be_abstract : 1;
+       bool              must_be_abstract : 1;
+       decl_modifiers_t  modifiers;
+       symbol_t         *symbol;
+       position_t        pos;
+       scope_t           parameters;
+       attribute_t      *attributes;
 } parse_declarator_env_t;
 
 /* §6.7.5 */
@@ -3392,8 +3401,8 @@ ptr_operator_end: ;
                if (env->must_be_abstract) {
                        errorf(HERE, "no identifier expected in typename");
                } else {
-                       env->symbol          = token.base.symbol;
-                       env->source_position = *HERE;
+                       env->symbol = token.base.symbol;
+                       env->pos    = *HERE;
                }
                eat(T_IDENTIFIER);
                break;
@@ -3484,7 +3493,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;
+               position_t const* const pos = &iter->base.pos;
                switch (iter->kind) {
                case CONSTRUCT_FUNCTION: {
                        construct_function_type_t *function      = &iter->function;
@@ -3547,22 +3556,23 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
 
                        if (size_expression != NULL) {
                                switch (is_constant_expression(size_expression)) {
-                               case EXPR_CLASS_CONSTANT: {
+                               case EXPR_CLASS_INTEGER_CONSTANT: {
                                        long const size = fold_constant_to_int(size_expression);
                                        array_type->array.size          = size;
                                        array_type->array.size_constant = true;
                                        /* §6.7.5.2:1  If the expression is a constant expression,
                                         * it shall have a value greater than zero. */
                                        if (size < 0) {
-                                               errorf(&size_expression->base.source_position,
+                                               errorf(&size_expression->base.pos,
                                                           "size of array must be greater than zero");
                                        } else if (size == 0 && !GNU_MODE) {
-                                               errorf(&size_expression->base.source_position,
+                                               errorf(&size_expression->base.pos,
                                                           "size of array must be greater than zero (zero length arrays are a GCC extension)");
                                        }
                                        break;
                                }
 
+                               case EXPR_CLASS_CONSTANT:
                                case EXPR_CLASS_VARIABLE:
                                        array_type->array.is_vla = true;
                                        break;
@@ -3591,8 +3601,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
 
 static type_t *automatic_type_conversion(type_t *orig_type);
 
-static type_t *semantic_parameter(const source_position_t *pos,
-                                  type_t *type,
+static type_t *semantic_parameter(const position_t *pos, type_t *type,
                                   const declaration_specifiers_t *specifiers,
                                   entity_t const *const param)
 {
@@ -3650,7 +3659,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
 
        entity_t *entity;
        if (specifiers->storage_class == STORAGE_CLASS_TYPEDEF) {
-               entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol, &env.source_position);
+               entity = allocate_entity_zero(ENTITY_TYPEDEF, NAMESPACE_NORMAL, env.symbol, &env.pos);
                entity->typedefe.type = orig_type;
 
                if (anonymous_entity != NULL) {
@@ -3669,23 +3678,23 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                }
        } else {
                /* create a declaration type entity */
-               source_position_t const *const pos = env.symbol ? &env.source_position : &specifiers->source_position;
+               position_t const *const pos = env.symbol ? &env.pos : &specifiers->pos;
                if (flags & DECL_CREATE_COMPOUND_MEMBER) {
                        entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, env.symbol, pos);
 
                        if (env.symbol != NULL) {
                                if (specifiers->is_inline && is_type_valid(type)) {
-                                       errorf(&env.source_position, "'%N' declared 'inline'", entity);
+                                       errorf(&env.pos, "'%N' declared 'inline'", entity);
                                }
 
                                if (specifiers->thread_local ||
                                                specifiers->storage_class != STORAGE_CLASS_NONE) {
-                                       errorf(&env.source_position, "'%N' must have no storage class", entity);
+                                       errorf(&env.pos, "'%N' must have no storage class", entity);
                                }
                        }
                } else if (flags & DECL_IS_PARAMETER) {
                        entity    = allocate_entity_zero(ENTITY_PARAMETER, NAMESPACE_NORMAL, env.symbol, pos);
-                       orig_type = semantic_parameter(&env.source_position, orig_type, specifiers, entity);
+                       orig_type = semantic_parameter(&env.pos, orig_type, specifiers, entity);
                } else if (is_type_function(type)) {
                        entity = allocate_entity_zero(ENTITY_FUNCTION, NAMESPACE_NORMAL, env.symbol, pos);
                        entity->function.is_inline      = specifiers->is_inline;
@@ -3701,7 +3710,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                                        specifiers->storage_class != STORAGE_CLASS_NONE   &&
                                                        (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC)
                                                )) {
-                                       errorf(&env.source_position, "invalid storage class for '%N'", entity);
+                                       errorf(&env.pos, "invalid storage class for '%N'", entity);
                                }
                        }
                } else {
@@ -3711,7 +3720,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
 
                        if (env.symbol != NULL) {
                                if (specifiers->is_inline && is_type_valid(type)) {
-                                       errorf(&env.source_position, "'%N' declared 'inline'", entity);
+                                       errorf(&env.pos, "'%N' declared 'inline'", entity);
                                }
 
                                bool invalid_storage_class = false;
@@ -3728,7 +3737,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                        }
                                }
                                if (invalid_storage_class) {
-                                       errorf(&env.source_position, "invalid storage class for '%N'", entity);
+                                       errorf(&env.pos, "invalid storage class for '%N'", entity);
                                }
                        }
                }
@@ -3787,7 +3796,7 @@ static type_t *parse_abstract_declarator(type_t *base_type)
  */
 static void check_main(const entity_t *entity)
 {
-       const source_position_t *pos = &entity->base.source_position;
+       const position_t *pos = &entity->base.pos;
        if (entity->kind != ENTITY_FUNCTION) {
                warningf(WARN_MAIN, pos, "'main' is not a function");
                return;
@@ -3839,11 +3848,11 @@ warn_arg_count:
        }
 }
 
-static void error_redefined_as_different_kind(const source_position_t *pos,
+static void error_redefined_as_different_kind(const position_t *pos,
                const entity_t *old, entity_kind_t new_kind)
 {
-       char              const *const what = get_entity_kind_name(new_kind);
-       source_position_t const *const ppos = &old->base.source_position;
+       char       const *const what = get_entity_kind_name(new_kind);
+       position_t const *const ppos = &old->base.pos;
        errorf(pos, "redeclaration of '%N' as %s (declared %P)", old, what, ppos);
 }
 
@@ -3867,7 +3876,7 @@ static bool contains_attribute(const attribute_t *list, const attribute_t *attr)
 }
 
 /**
- * test wether new_list contains any attributes not included in old_list
+ * Tests whether new_list contains any attributes not included in old_list
  */
 static bool has_new_attributes(const attribute_t *old_list,
                                const attribute_t *new_list)
@@ -3906,9 +3915,9 @@ static bool is_main(entity_t*);
  */
 entity_t *record_entity(entity_t *entity, const bool is_definition)
 {
-       const symbol_t *const    symbol  = entity->base.symbol;
-       const namespace_tag_t    namespc = (namespace_tag_t)entity->base.namespc;
-       const source_position_t *pos     = &entity->base.source_position;
+       const symbol_t *const symbol  = entity->base.symbol;
+       const namespace_tag_t namespc = (namespace_tag_t)entity->base.namespc;
+       const position_t     *pos     = &entity->base.pos;
 
        /* can happen in error cases */
        if (symbol == NULL)
@@ -3946,7 +3955,7 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
        }
 
        if (previous_entity != NULL) {
-               source_position_t const *const ppos = &previous_entity->base.source_position;
+               position_t const *const ppos = &previous_entity->base.pos;
 
                if (previous_entity->base.parent_scope == &current_function->parameters &&
                                previous_entity->base.parent_scope->depth + 1 == current_scope->depth) {
@@ -4061,9 +4070,7 @@ warn_redundant_declaration: ;
                                                                     decl->attributes);
                                        if (has_new_attrs) {
                                                merge_in_attributes(decl, prev_decl->attributes);
-                                       } else if (!is_definition        &&
-                                                       is_type_valid(prev_type) &&
-                                                       !pos->is_system_header) {
+                                       } else if (!is_definition && is_type_valid(prev_type)) {
                                                warningf(WARN_REDUNDANT_DECLS, pos, "redundant declaration for '%N' (declared %P)", entity, ppos);
                                        }
                                } else if (current_function == NULL) {
@@ -4116,10 +4123,11 @@ error_redeclaration:
                }
        } else if (entity->kind == ENTITY_VARIABLE) {
                if (current_scope                     == file_scope &&
-                               entity->declaration.storage_class == STORAGE_CLASS_NONE &&
-                               !entity->declaration.implicit) {
+                   entity->declaration.storage_class == STORAGE_CLASS_NONE &&
+                   !entity->declaration.implicit) {
 warn_missing_declaration:
-                       warningf(WARN_MISSING_DECLARATIONS, pos, "no previous declaration for '%#N'", entity);
+                       if (is_type_valid(skip_typeref(entity->declaration.type)))
+                               warningf(WARN_MISSING_DECLARATIONS, pos, "no previous declaration for '%#N'", entity);
                }
        }
 
@@ -4131,18 +4139,18 @@ finish:
 }
 
 static void parser_error_multiple_definition(entity_t *entity,
-               const source_position_t *source_position)
+                                             const position_t *pos)
 {
-       errorf(source_position, "redefinition of '%N' (declared %P)", entity, &entity->base.source_position);
+       errorf(pos, "redefinition of '%N' (declared %P)", entity, &entity->base.pos);
 }
 
-static bool is_declaration_specifier(const token_t *token)
+static bool is_declaration_specifier(token_t const *const tk)
 {
-       switch (token->kind) {
+       switch (tk->kind) {
                DECLARATION_START
                        return true;
                case T_IDENTIFIER:
-                       return is_typedef_symbol(token->base.symbol);
+                       return is_typedef_symbol(tk->base.symbol);
 
                default:
                        return false;
@@ -4154,7 +4162,7 @@ static void parse_init_declarator_rest(entity_t *entity)
        type_t *orig_type = type_error_type;
 
        if (entity->base.kind == ENTITY_TYPEDEF) {
-               source_position_t const *const pos = &entity->base.source_position;
+               position_t const *const pos = &entity->base.pos;
                errorf(pos, "'%N' is initialized (use __typeof__ instead)", entity);
        } else {
                assert(is_declaration(entity));
@@ -4177,7 +4185,7 @@ static void parse_init_declarator_rest(entity_t *entity)
        }
 
        if (is_type_function(type)) {
-               source_position_t const *const pos = &entity->base.source_position;
+               position_t const *const pos = &entity->base.pos;
                errorf(pos, "'%N' is initialized like a variable", entity);
                orig_type = type_error_type;
        }
@@ -4204,7 +4212,7 @@ static void parse_anonymous_declaration_rest(
        eat(';');
        anonymous_entity = NULL;
 
-       source_position_t const *const pos = &specifiers->source_position;
+       position_t const *const pos = &specifiers->pos;
        if (specifiers->storage_class != STORAGE_CLASS_NONE ||
                        specifiers->thread_local) {
                warningf(WARN_OTHER, pos, "useless storage class in empty declaration");
@@ -4252,7 +4260,7 @@ static void check_variable_type_complete(entity_t *ent)
                return;
        }
 
-       errorf(&ent->base.source_position, "variable '%#N' has incomplete type", ent);
+       errorf(&ent->base.pos, "variable '%#N' has incomplete type", ent);
 }
 
 
@@ -4274,14 +4282,14 @@ static void parse_declaration_rest(entity_t *ndeclaration,
                        declaration_t *decl = &entity->declaration;
                        if (decl->storage_class != STORAGE_CLASS_EXTERN &&
                            is_type_reference(skip_typeref(decl->type))) {
-                               source_position_t const *const pos = &entity->base.source_position;
+                               position_t const *const pos = &entity->base.pos;
                                errorf(pos, "reference '%#N' must be initialized", entity);
                        }
                }
 
                check_variable_type_complete(entity);
 
-               if (!next_if(','))
+               if (!accept(','))
                        break;
 
                add_anchor_token('=');
@@ -4305,7 +4313,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(&entity->base.source_position, "expected declaration of a function parameter, found '%Y'",
+               errorf(&entity->base.pos, "expected declaration of a function parameter, found '%Y'",
                       symbol);
                return entity;
        }
@@ -4422,7 +4430,7 @@ decl_list_end:
 
                type_t *parameter_type = parameter->declaration.type;
                if (parameter_type == NULL) {
-                       source_position_t const* const pos = &parameter->base.source_position;
+                       position_t const* const pos = &parameter->base.pos;
                        if (strict_mode) {
                                errorf(pos, "no type specified for function '%N'", parameter);
                                parameter_type = type_error_type;
@@ -4463,9 +4471,9 @@ decl_list_end:
        new_type = identify_new_type(new_type);
 
        if (need_incompatible_warning) {
-               symbol_t          const *const sym  = entity->base.symbol;
-               source_position_t const *const pos  = &entity->base.source_position;
-               source_position_t const *const ppos = &proto_type->base.source_position;
+               symbol_t   const *const sym  = entity->base.symbol;
+               position_t const *const pos  = &entity->base.pos;
+               position_t const *const ppos = &proto_type->base.pos;
                warningf(WARN_OTHER, pos, "declaration '%#N' is incompatible with '%#T' (declared %P)", proto_type, new_type, sym, ppos);
        }
        entity->declaration.type = new_type;
@@ -4483,7 +4491,7 @@ static void print_in_function(void)
 {
        if (first_err) {
                first_err = false;
-               char const *const file = current_function->base.base.source_position.input_name;
+               char const *const file = current_function->base.base.pos.input_name;
                diagnosticf("%s: In '%N':\n", file, (entity_t const*)current_function);
        }
 }
@@ -4498,9 +4506,9 @@ static void check_labels(void)
            goto_statement != NULL;
            goto_statement = goto_statement->next) {
                label_t *label = goto_statement->label;
-               if (label->base.source_position.input_name == NULL) {
+               if (label->base.pos.input_name == NULL) {
                        print_in_function();
-                       source_position_t const *const pos = &goto_statement->base.source_position;
+                       position_t const *const pos = &goto_statement->base.pos;
                        errorf(pos, "'%N' used but not defined", (entity_t const*)label);
                 }
        }
@@ -4513,7 +4521,7 @@ static void check_labels(void)
 
                        if (! label->used) {
                                print_in_function();
-                               source_position_t const *const pos = &label_statement->base.source_position;
+                               position_t const *const pos = &label_statement->base.pos;
                                warningf(WARN_UNUSED_LABEL, pos, "'%N' defined but not used", (entity_t const*)label);
                        }
                }
@@ -4533,10 +4541,10 @@ static void warn_unused_entity(warning_t const why, entity_t *entity, entity_t *
 
                if (!declaration->used) {
                        print_in_function();
-                       warningf(why, &entity->base.source_position, "'%N' is unused", entity);
+                       warningf(why, &entity->base.pos, "'%N' is unused", entity);
                } else if (entity->kind == ENTITY_VARIABLE && !entity->variable.read) {
                        print_in_function();
-                       warningf(why, &entity->base.source_position, "'%N' is never read", entity);
+                       warningf(why, &entity->base.pos, "'%N' is never read", entity);
                }
        }
 }
@@ -4571,16 +4579,15 @@ static void check_declarations(void)
                warn_unused_entity(WARN_UNUSED_PARAMETER, scope->entities, NULL);
        }
        if (is_warn_on(WARN_UNUSED_VARIABLE)) {
-               walk_statements(current_function->statement, check_unused_variables,
-                               NULL);
+               walk_statements(current_function->body, check_unused_variables, NULL);
        }
 }
 
 static int determine_truth(expression_t const* const cond)
 {
        return
-               is_constant_expression(cond) != EXPR_CLASS_CONSTANT ? 0 :
-               fold_constant_to_bool(cond)                         ? 1 :
+               is_constant_expression(cond) < EXPR_CLASS_CONSTANT ? 0 :
+               fold_constant_to_bool(cond)                        ? 1 :
                -1;
 }
 
@@ -4788,8 +4795,8 @@ static void check_reachable(statement_t *const stmt)
                        if (!expression_returns(expr))
                                return;
 
-                       if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) {
-                               long                    const val      = fold_constant_to_int(expr);
+                       if (is_constant_expression(expr) >= EXPR_CLASS_CONSTANT) {
+                               ir_tarval              *const val      = fold_constant_to_tarval(expr);
                                case_label_statement_t *      defaults = NULL;
                                for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
                                        if (i->expression == NULL) {
@@ -4797,7 +4804,9 @@ static void check_reachable(statement_t *const stmt)
                                                continue;
                                        }
 
-                                       if (i->first_case <= val && val <= i->last_case) {
+                                       if (i->first_case == val || i->last_case == val ||
+                                               ((tarval_cmp(i->first_case, val) & ir_relation_less_equal)
+                                           && (tarval_cmp(val, i->last_case) & ir_relation_less_equal))) {
                                                check_reachable((statement_t*)i);
                                                return;
                                        }
@@ -4842,7 +4851,6 @@ static void check_reachable(statement_t *const stmt)
 
                                next = parent;
                                switch (parent->kind) {
-                                       case STATEMENT_WHILE:    goto continue_while;
                                        case STATEMENT_DO_WHILE: goto continue_do_while;
                                        case STATEMENT_FOR:      goto continue_for;
 
@@ -4858,7 +4866,6 @@ static void check_reachable(statement_t *const stmt)
 
                                switch (parent->kind) {
                                        case STATEMENT_SWITCH:
-                                       case STATEMENT_WHILE:
                                        case STATEMENT_DO_WHILE:
                                        case STATEMENT_FOR:
                                                last = parent;
@@ -4896,25 +4903,6 @@ found_break_parent:
                        next = stmt->case_label.statement;
                        break;
 
-               case STATEMENT_WHILE: {
-                       while_statement_t const *const whiles = &stmt->whiles;
-                       expression_t      const *const cond   = whiles->condition;
-
-                       if (!expression_returns(cond))
-                               return;
-
-                       int const val = determine_truth(cond);
-
-                       if (val >= 0)
-                               check_reachable(whiles->body);
-
-                       if (val > 0)
-                               return;
-
-                       next = stmt->base.next;
-                       break;
-               }
-
                case STATEMENT_DO_WHILE:
                        next = stmt->do_while.body;
                        break;
@@ -4985,7 +4973,7 @@ found_break_parent:
                        if (!is_type_void(ret) &&
                            is_type_valid(ret) &&
                            !is_main(current_entity)) {
-                               source_position_t const *const pos = &stmt->base.source_position;
+                               position_t const *const pos = &stmt->base.pos;
                                warningf(WARN_RETURN_TYPE, pos, "control reaches end of non-void function");
                        }
                        return;
@@ -5019,31 +5007,6 @@ found_break_parent:
                                next = next->base.next;
                                break;
 
-                       case STATEMENT_WHILE: {
-continue_while:
-                               if (next->base.reachable)
-                                       return;
-                               next->base.reachable = true;
-
-                               while_statement_t const *const whiles = &next->whiles;
-                               expression_t      const *const cond   = whiles->condition;
-
-                               if (!expression_returns(cond))
-                                       return;
-
-                               int const val = determine_truth(cond);
-
-                               if (val >= 0)
-                                       check_reachable(whiles->body);
-
-                               if (val > 0)
-                                       return;
-
-                               last = next;
-                               next = next->base.next;
-                               break;
-                       }
-
                        case STATEMENT_DO_WHILE: {
 continue_do_while:
                                if (next->base.reachable)
@@ -5120,7 +5083,7 @@ static void check_unreachable(statement_t* const stmt, void *const env)
                        if (!stmt->base.reachable) {
                                expression_t const *const cond = stmt->do_while.condition;
                                if (determine_truth(cond) >= 0) {
-                                       source_position_t const *const pos = &cond->base.source_position;
+                                       position_t const *const pos = &cond->base.pos;
                                        warningf(WARN_UNREACHABLE_CODE, pos, "condition of do-while-loop is unreachable");
                                }
                        }
@@ -5134,17 +5097,17 @@ static void check_unreachable(statement_t* const stmt, void *const env)
                                goto warn_unreachable;
                        } else {
                                if (!stmt->base.reachable && fors->initialisation != NULL) {
-                                       source_position_t const *const pos = &fors->initialisation->base.source_position;
+                                       position_t const *const pos = &fors->initialisation->base.pos;
                                        warningf(WARN_UNREACHABLE_CODE, pos, "initialisation of for-statement is unreachable");
                                }
 
                                if (!fors->condition_reachable && fors->condition != NULL) {
-                                       source_position_t const *const pos = &fors->condition->base.source_position;
+                                       position_t const *const pos = &fors->condition->base.pos;
                                        warningf(WARN_UNREACHABLE_CODE, pos, "condition of for-statement is unreachable");
                                }
 
                                if (!fors->step_reachable && fors->step != NULL) {
-                                       source_position_t const *const pos = &fors->step->base.source_position;
+                                       position_t const *const pos = &fors->step->base.pos;
                                        warningf(WARN_UNREACHABLE_CODE, pos, "step of for-statement is unreachable");
                                }
                        }
@@ -5177,7 +5140,7 @@ static void check_unreachable(statement_t* const stmt, void *const env)
                default:
 warn_unreachable:
                        if (!stmt->base.reachable) {
-                               source_position_t const *const pos = &stmt->base.source_position;
+                               position_t const *const pos = &stmt->base.pos;
                                warningf(WARN_UNREACHABLE_CODE, pos, "statement is unreachable");
                        }
                        return;
@@ -5249,42 +5212,42 @@ static void parse_external_declaration(void)
                return;
        }
 
-       assert(is_declaration(ndeclaration));
-       type_t *const orig_type = ndeclaration->declaration.type;
-       type_t *      type      = skip_typeref(orig_type);
+       {
+               assert(is_declaration(ndeclaration));
+               type_t *const orig_type = ndeclaration->declaration.type;
+               type_t *const type      = skip_typeref(orig_type);
 
-       if (!is_type_function(type)) {
-               if (is_type_valid(type)) {
-                       errorf(HERE, "declarator '%#N' has a body but is not a function type", ndeclaration);
+               if (!is_type_function(type)) {
+                       if (is_type_valid(type)) {
+                               errorf(HERE, "declarator '%#N' has a body but is not a function type", ndeclaration);
+                       }
+                       eat_block();
+                       return;
                }
-               eat_block();
-               return;
-       }
 
-       source_position_t const *const pos = &ndeclaration->base.source_position;
-       if (is_typeref(orig_type)) {
-               /* §6.9.1:2 */
-               errorf(pos, "type of function definition '%#N' is a typedef", ndeclaration);
-       }
-
-       if (is_type_compound(skip_typeref(type->function.return_type))) {
-               warningf(WARN_AGGREGATE_RETURN, pos, "'%N' returns an aggregate", ndeclaration);
-       }
-       if (type->function.unspecified_parameters) {
-               warningf(WARN_OLD_STYLE_DEFINITION, pos, "old-style definition of '%N'", ndeclaration);
-       } else {
-               warningf(WARN_TRADITIONAL, pos, "traditional C rejects ISO C style definition of '%N'", ndeclaration);
-       }
+               position_t const *const pos = &ndeclaration->base.pos;
+               if (is_typeref(orig_type)) {
+                       /* §6.9.1:2 */
+                       errorf(pos, "type of function definition '%#N' is a typedef", ndeclaration);
+               }
 
-       /* §6.7.5.3:14 a function definition with () means no
-        * parameters (and not unspecified parameters) */
-       if (type->function.unspecified_parameters &&
-                       type->function.parameters == NULL) {
-               type_t *copy                          = duplicate_type(type);
-               copy->function.unspecified_parameters = false;
-               type                                  = identify_new_type(copy);
+               if (is_type_compound(skip_typeref(type->function.return_type))) {
+                       warningf(WARN_AGGREGATE_RETURN, pos, "'%N' returns an aggregate", ndeclaration);
+               }
+               if (type->function.unspecified_parameters) {
+                       warningf(WARN_OLD_STYLE_DEFINITION, pos, "old-style definition of '%N'", ndeclaration);
+               } else {
+                       warningf(WARN_TRADITIONAL, pos, "traditional C rejects ISO C style definition of '%N'", ndeclaration);
+               }
 
-               ndeclaration->declaration.type = type;
+               /* §6.7.5.3:14 a function definition with () means no
+                * parameters (and not unspecified parameters) */
+               if (type->function.unspecified_parameters &&
+                               type->function.parameters == NULL) {
+                       type_t *copy                          = duplicate_type(type);
+                       copy->function.unspecified_parameters = false;
+                       ndeclaration->declaration.type = identify_new_type(copy);
+               }
        }
 
        entity_t *const entity = record_entity(ndeclaration, true);
@@ -5307,13 +5270,13 @@ static void parse_external_declaration(void)
                                || parameter->base.parent_scope == current_scope);
                parameter->base.parent_scope = current_scope;
                if (parameter->base.symbol == NULL) {
-                       errorf(&parameter->base.source_position, "parameter name omitted");
+                       errorf(&parameter->base.pos, "parameter name omitted");
                        continue;
                }
                environment_push(parameter);
        }
 
-       if (function->statement != NULL) {
+       if (function->body != NULL) {
                parser_error_multiple_definition(entity, HERE);
                eat_block();
        } else {
@@ -5330,7 +5293,7 @@ static void parse_external_declaration(void)
                label_anchor = &label_first;
 
                statement_t *const body = parse_compound_statement(false);
-               function->statement = body;
+               function->body = body;
                first_err = true;
                check_labels();
                check_declarations();
@@ -5343,8 +5306,7 @@ static void parse_external_declaration(void)
                                walk_statements(body, check_unreachable, NULL);
                        if (noreturn_candidate &&
                            !(function->base.modifiers & DM_NORETURN)) {
-                               source_position_t const *const pos = &body->base.source_position;
-                               warningf(WARN_MISSING_NORETURN, pos, "function '%#N' is candidate for attribute 'noreturn'", entity);
+                               warningf(WARN_MISSING_NORETURN, &body->base.pos, "function '%#N' is candidate for attribute 'noreturn'", entity);
                        }
                }
 
@@ -5396,26 +5358,24 @@ static entity_t *find_compound_entry(compound_t *compound, symbol_t *symbol)
        return NULL;
 }
 
-static void check_deprecated(const source_position_t *source_position,
-                             const entity_t *entity)
+static void check_deprecated(const position_t *pos, const entity_t *entity)
 {
        if (!is_declaration(entity))
                return;
        if ((entity->declaration.modifiers & DM_DEPRECATED) == 0)
                return;
 
-       source_position_t const *const epos = &entity->base.source_position;
-       char              const *const msg  = get_deprecated_string(entity->declaration.attributes);
+       position_t const *const epos = &entity->base.pos;
+       char       const *const msg  = get_deprecated_string(entity->declaration.attributes);
        if (msg != NULL) {
-               warningf(WARN_DEPRECATED_DECLARATIONS, source_position, "'%N' is deprecated (declared %P): \"%s\"", entity, epos, msg);
+               warningf(WARN_DEPRECATED_DECLARATIONS, pos, "'%N' is deprecated (declared %P): \"%s\"", entity, epos, msg);
        } else {
-               warningf(WARN_DEPRECATED_DECLARATIONS, source_position, "'%N' is deprecated (declared %P)", entity, epos);
+               warningf(WARN_DEPRECATED_DECLARATIONS, pos, "'%N' is deprecated (declared %P)", entity, epos);
        }
 }
 
 
-static expression_t *create_select(const source_position_t *pos,
-                                   expression_t *addr,
+static expression_t *create_select(const position_t *pos, expression_t *addr,
                                    type_qualifiers_t qualifiers,
                                                                   entity_t *entry)
 {
@@ -5424,6 +5384,7 @@ static expression_t *create_select(const source_position_t *pos,
        check_deprecated(pos, entry);
 
        expression_t *select          = allocate_expression_zero(EXPR_SELECT);
+       select->base.pos              = *pos;
        select->select.compound       = addr;
        select->select.compound_entry = entry;
 
@@ -5452,7 +5413,7 @@ static expression_t *create_select(const source_position_t *pos,
  * creates implicit select expressions for them.
  * Returns the adress for the innermost compound.
  */
-static expression_t *find_create_select(const source_position_t *pos,
+static expression_t *find_create_select(const position_t *pos,
                                         expression_t *addr,
                                         type_qualifiers_t qualifiers,
                                         compound_t *compound, symbol_t *symbol)
@@ -5474,8 +5435,7 @@ static expression_t *find_create_select(const source_position_t *pos,
                                continue;
 
                        expression_t *sub_addr = create_select(pos, addr, qualifiers, iter);
-                       sub_addr->base.source_position = *pos;
-                       sub_addr->base.implicit        = true;
+                       sub_addr->base.implicit = true;
                        return find_create_select(pos, sub_addr, qualifiers, sub_compound,
                                                  symbol);
                }
@@ -5502,7 +5462,7 @@ static void parse_bitfield_member(entity_t *entity)
                           type);
        }
 
-       if (is_constant_expression(size) != EXPR_CLASS_CONSTANT) {
+       if (is_constant_expression(size) < EXPR_CLASS_CONSTANT) {
                /* error already reported by parse_constant_expression */
                size_long = get_type_size(type) * 8;
        } else {
@@ -5537,74 +5497,49 @@ static void parse_compound_declarators(compound_t *compound,
        add_anchor_token(';');
        add_anchor_token(',');
        do {
-               entity_t *entity;
-
-               if (token.kind == ':') {
-                       /* anonymous bitfield */
-                       type_t *type = specifiers->type;
-                       entity_t *const entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, NULL, HERE);
-                       entity->declaration.declared_storage_class = STORAGE_CLASS_NONE;
-                       entity->declaration.storage_class          = STORAGE_CLASS_NONE;
-                       entity->declaration.type                   = type;
+               entity_t         *const entity = parse_declarator(specifiers, DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER);
+               position_t const *const pos    = &entity->base.pos;
+               if (entity->kind == ENTITY_TYPEDEF) {
+                       errorf(pos, "typedef not allowed as compound member");
+                       continue;
+               }
 
-                       parse_bitfield_member(entity);
+               assert(entity->kind == ENTITY_COMPOUND_MEMBER);
 
-                       attribute_t  *attributes = parse_attributes(NULL);
-                       attribute_t **anchor     = &attributes;
-                       while (*anchor != NULL)
-                               anchor = &(*anchor)->next;
-                       *anchor = specifiers->attributes;
-                       if (attributes != NULL) {
-                               handle_entity_attributes(attributes, entity);
+               /* make sure we don't define a symbol multiple times */
+               symbol_t *symbol = entity->base.symbol;
+               if (symbol != NULL) {
+                       entity_t *prev = find_compound_entry(compound, symbol);
+                       if (prev != NULL) {
+                               position_t const *const ppos = &prev->base.pos;
+                               errorf(pos, "multiple declarations of '%N' (declared %P)", entity, ppos);
                        }
-                       entity->declaration.attributes = attributes;
-
-                       append_entity(&compound->members, entity);
-               } else {
-                       entity = parse_declarator(specifiers,
-                                       DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER);
-                       source_position_t const *const pos = &entity->base.source_position;
-                       if (entity->kind == ENTITY_TYPEDEF) {
-                               errorf(pos, "typedef not allowed as compound member");
-                       } else {
-                               assert(entity->kind == ENTITY_COMPOUND_MEMBER);
-
-                               /* make sure we don't define a symbol multiple times */
-                               symbol_t *symbol = entity->base.symbol;
-                               if (symbol != NULL) {
-                                       entity_t *prev = find_compound_entry(compound, symbol);
-                                       if (prev != NULL) {
-                                               source_position_t const *const ppos = &prev->base.source_position;
-                                               errorf(pos, "multiple declarations of '%N' (declared %P)", entity, ppos);
-                                       }
-                               }
+               }
 
-                               if (token.kind == ':') {
-                                       parse_bitfield_member(entity);
+               if (token.kind == ':') {
+                       parse_bitfield_member(entity);
 
-                                       attribute_t *attributes = parse_attributes(NULL);
-                                       handle_entity_attributes(attributes, entity);
-                               } else {
-                                       type_t *orig_type = entity->declaration.type;
-                                       type_t *type      = skip_typeref(orig_type);
-                                       if (is_type_function(type)) {
-                                               errorf(pos, "'%N' must not have function type '%T'", entity, orig_type);
-                                       } else if (is_type_incomplete(type)) {
-                                               /* §6.7.2.1:16 flexible array member */
-                                               if (!is_type_array(type)       ||
-                                                               token.kind          != ';' ||
-                                                               look_ahead(1)->kind != '}') {
-                                                       errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type);
-                                               } else if (compound->members.entities == NULL) {
-                                                       errorf(pos, "flexible array member in otherwise empty struct");
-                                               }
-                                       }
+                       attribute_t *attributes = parse_attributes(NULL);
+                       handle_entity_attributes(attributes, entity);
+               } else {
+                       type_t *orig_type = entity->declaration.type;
+                       type_t *type      = skip_typeref(orig_type);
+                       if (is_type_function(type)) {
+                               errorf(pos, "'%N' must not have function type '%T'", entity, orig_type);
+                       } else if (is_type_incomplete(type)) {
+                               /* §6.7.2.1:16 flexible array member */
+                               if (!is_type_array(type)       ||
+                                               token.kind          != ';' ||
+                                               look_ahead(1)->kind != '}') {
+                                       errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type);
+                               } else if (compound->members.entities == NULL) {
+                                       errorf(pos, "flexible array member in otherwise empty struct");
                                }
-
-                               append_entity(&compound->members, entity);
                        }
                }
-       } while (next_if(','));
+
+               append_entity(&compound->members, entity);
+       } while (accept(','));
        rem_anchor_token(',');
        rem_anchor_token(';');
        expect(';');
@@ -5649,7 +5584,7 @@ static type_t *parse_typename(void)
                /* TODO: improve error message, user does probably not know what a
                 * storage class is...
                 */
-               errorf(&specifiers.source_position, "typename must not have a storage class");
+               errorf(&specifiers.pos, "typename must not have a storage class");
        }
 
        type_t *result = parse_abstract_declarator(specifiers.type);
@@ -5676,8 +5611,11 @@ static type_t *get_string_type(string_encoding_t const enc)
 {
        bool const warn = is_warn_on(WARN_WRITE_STRINGS);
        switch (enc) {
-       case STRING_ENCODING_CHAR: return warn ? type_const_char_ptr    : type_char_ptr;
-       case STRING_ENCODING_WIDE: return warn ? type_const_wchar_t_ptr : type_wchar_t_ptr;
+       case STRING_ENCODING_CHAR:
+       case STRING_ENCODING_UTF8:   return warn ? type_const_char_ptr     : type_char_ptr;
+       case STRING_ENCODING_CHAR16: return warn ? type_char16_t_const_ptr : type_char16_t_ptr;
+       case STRING_ENCODING_CHAR32: return warn ? type_char32_t_const_ptr : type_char32_t_ptr;
+       case STRING_ENCODING_WIDE:   return warn ? type_const_wchar_t_ptr  : type_wchar_t_ptr;
        }
        panic("invalid string encoding");
 }
@@ -5707,78 +5645,77 @@ static expression_t *parse_boolean_literal(bool value)
        return literal;
 }
 
-static void warn_traditional_suffix(char const *const suffix)
+static void check_number_suffix(expression_t *const expr, char const *const suffix, bool const is_float)
 {
-       warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%s' suffix", suffix);
-}
-
-static void check_integer_suffix(expression_t *const expr, char const *const suffix)
-{
-       unsigned     spec = SPECIFIER_NONE;
-       char const  *c    = suffix;
-       for (;;) {
+       unsigned spec = SPECIFIER_NONE;
+       for (char const *c = suffix; *c != '\0'; ++c) {
                specifiers_t add;
-               if (*c == 'L' || *c == 'l') {
+               switch (*c) {
+               case 'F': case 'f':
+                       add = SPECIFIER_FLOAT;
+                       break;
+
+               case 'L': case 'l':
                        add = SPECIFIER_LONG;
-                       if (*c == c[1]) {
+                       if (*c == c[1] && !is_float) {
                                add |= SPECIFIER_LONG_LONG;
                                ++c;
                        }
-               } else if (*c == 'U' || *c == 'u') {
+                       break;
+
+               case 'U': case 'u':
                        add = SPECIFIER_UNSIGNED;
-               } else {
                        break;
+
+               case 'I': case 'i':
+               case 'J': case 'j':
+                       add = SPECIFIER_COMPLEX;
+                       break;
+
+               default:
+                       goto error;
                }
-               ++c;
                if (spec & add)
                        goto error;
                spec |= add;
        }
 
-       if (*c == '\0') {
-               type_t *type;
-               switch (spec) {
-               case SPECIFIER_NONE:                                            type = type_int;                break;
-               case                      SPECIFIER_LONG:                       type = type_long;               break;
-               case                      SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_long_long;          break;
-               case SPECIFIER_UNSIGNED:                                        type = type_unsigned_int;       break;
-               case SPECIFIER_UNSIGNED | SPECIFIER_LONG:                       type = type_unsigned_long;      break;
-               case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_unsigned_long_long; break;
-               default: panic("inconsistent suffix");
-               }
-               if (spec != SPECIFIER_NONE && spec != SPECIFIER_LONG) {
-                       warn_traditional_suffix(suffix);
-               }
-               expr->base.type = type;
-               /* Integer type depends on the size of the number and the size
-                * representable by the types. The backend/codegeneration has to
-                * determine that. */
-               determine_literal_type(&expr->literal);
-       } else {
+       if (!(spec & SPECIFIER_FLOAT) && is_float)
+               spec |= SPECIFIER_DOUBLE;
+
+       if (!(spec & (SPECIFIER_FLOAT | SPECIFIER_DOUBLE)) == is_float)
+               goto error;
+
+       type_t *type;
+       switch (spec & ~SPECIFIER_COMPLEX) {
+       case SPECIFIER_NONE:                                            type = type_int;                break;
+       case                      SPECIFIER_LONG:                       type = type_long;               break;
+       case                      SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_long_long;          break;
+       case SPECIFIER_UNSIGNED:                                        type = type_unsigned_int;       break;
+       case SPECIFIER_UNSIGNED | SPECIFIER_LONG:                       type = type_unsigned_long;      break;
+       case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_unsigned_long_long; break;
+       case SPECIFIER_FLOAT:                                           type = type_float;              break;
+       case SPECIFIER_DOUBLE:                                          type = type_double;             break;
+       case SPECIFIER_DOUBLE   | SPECIFIER_LONG:                       type = type_long_double;        break;
+
+       default:
 error:
-               errorf(HERE, "invalid suffix '%s' on integer constant", suffix);
+               errorf(HERE, "invalid suffix '%s' on %s constant", suffix, is_float ? "floatingpoint" : "integer");
+               return;
        }
-}
 
-static void check_floatingpoint_suffix(expression_t *const expr, char const *const suffix)
-{
-       type_t     *type;
-       char const *c    = suffix;
-       switch (*c) {
-       case 'F':
-       case 'f': type = type_float;       ++c; break;
-       case 'L':
-       case 'l': type = type_long_double; ++c; break;
-       default:  type = type_double;           break;
-       }
+       if (spec != SPECIFIER_NONE && spec != SPECIFIER_LONG && spec != SPECIFIER_DOUBLE)
+               warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%s' suffix", suffix);
 
-       if (*c == '\0') {
-               expr->base.type = type;
-               if (suffix[0] != '\0') {
-                       warn_traditional_suffix(suffix);
-               }
-       } else {
-               errorf(HERE, "invalid suffix '%s' on floatingpoint constant", suffix);
+       if (spec & SPECIFIER_COMPLEX)
+               type = make_complex_type(get_arithmetic_akind(type), TYPE_QUALIFIER_NONE);
+
+       expr->base.type = type;
+       if (!is_float) {
+               /* Integer type depends on the size of the number and the size
+                * representable by the types. The backend/codegeneration has to
+                * determine that. */
+               determine_literal_type(&expr->literal);
        }
 }
 
@@ -5895,11 +5832,7 @@ done:;
                        errorf(HERE, "invalid digit in %K", &token);
                } else {
                        expr->literal.suffix = i;
-                       if (is_float) {
-                               check_floatingpoint_suffix(expr, i);
-                       } else {
-                               check_integer_suffix(expr, i);
-                       }
+                       check_number_suffix(expr, i, is_float);
                }
        }
 
@@ -5918,6 +5851,7 @@ static expression_t *parse_character_constant(void)
        size_t const size = get_string_len(&token.literal.string);
        switch (token.literal.string.encoding) {
        case STRING_ENCODING_CHAR:
+       case STRING_ENCODING_UTF8:
                literal->base.type = c_mode & _CXX ? type_char : type_int;
                if (size > 1) {
                        if (!GNU_MODE && !(c_mode & _C99)) {
@@ -5929,8 +5863,10 @@ static expression_t *parse_character_constant(void)
                }
                break;
 
-       case STRING_ENCODING_WIDE:
-               literal->base.type = type_int;
+       case STRING_ENCODING_CHAR16: literal->base.type = type_char16_t; goto warn_multi;
+       case STRING_ENCODING_CHAR32: literal->base.type = type_char32_t; goto warn_multi;
+       case STRING_ENCODING_WIDE:   literal->base.type = type_wchar_t;  goto warn_multi;
+warn_multi:
                if (size > 1) {
                        warningf(WARN_MULTICHAR, HERE, "multi-character character constant");
                }
@@ -5941,7 +5877,7 @@ static expression_t *parse_character_constant(void)
        return literal;
 }
 
-static entity_t *create_implicit_function(symbol_t *symbol, source_position_t const *const pos)
+static entity_t *create_implicit_function(symbol_t *symbol, position_t const *const pos)
 {
        type_t *ntype                          = allocate_type_zero(TYPE_FUNCTION);
        ntype->function.return_type            = type_int;
@@ -6066,11 +6002,11 @@ static entity_t *lookup_entity(const scope_t *scope, symbol_t *symbol,
 static entity_t *parse_qualified_identifier(void)
 {
        /* namespace containing the symbol */
-       symbol_t          *symbol;
-       source_position_t  pos;
-       const scope_t     *lookup_scope = NULL;
+       symbol_t      *symbol;
+       position_t     pos;
+       const scope_t *lookup_scope = NULL;
 
-       if (next_if(T_COLONCOLON))
+       if (accept(T_COLONCOLON))
                lookup_scope = &unit->scope;
 
        entity_t *entity;
@@ -6082,7 +6018,7 @@ static entity_t *parse_qualified_identifier(void)
                /* lookup entity */
                entity = lookup_entity(lookup_scope, symbol, NAMESPACE_NORMAL);
 
-               if (!next_if(T_COLONCOLON))
+               if (!accept(T_COLONCOLON))
                        break;
 
                switch (entity->kind) {
@@ -6099,7 +6035,7 @@ static entity_t *parse_qualified_identifier(void)
                               symbol, get_entity_kind_name(entity->kind));
 
                        /* skip further qualifications */
-                       while (next_if(T_IDENTIFIER) && next_if(T_COLONCOLON)) {}
+                       while (accept(T_IDENTIFIER) && accept(T_COLONCOLON)) {}
 
                        return create_error_entity(sym_anonymous, ENTITY_VARIABLE);
                }
@@ -6121,8 +6057,8 @@ static entity_t *parse_qualified_identifier(void)
 
 static expression_t *parse_reference(void)
 {
-       source_position_t const pos    = *HERE;
-       entity_t         *const entity = parse_qualified_identifier();
+       position_t const pos    = *HERE;
+       entity_t  *const entity = parse_qualified_identifier();
 
        type_t *orig_type;
        if (is_declaration(entity)) {
@@ -6141,10 +6077,10 @@ static expression_t *parse_reference(void)
        if (entity->kind == ENTITY_ENUM_VALUE)
                kind = EXPR_ENUM_CONSTANT;
 
-       expression_t *expression         = allocate_expression_zero(kind);
-       expression->base.source_position = pos;
-       expression->base.type            = type;
-       expression->reference.entity     = entity;
+       expression_t *expression     = allocate_expression_zero(kind);
+       expression->base.pos         = pos;
+       expression->base.type        = type;
+       expression->reference.entity = entity;
 
        /* this declaration is used */
        if (is_declaration(entity)) {
@@ -6167,14 +6103,15 @@ static expression_t *parse_reference(void)
 
 static bool semantic_cast(expression_t *cast)
 {
-       expression_t            *expression      = cast->unary.value;
-       type_t                  *orig_dest_type  = cast->base.type;
-       type_t                  *orig_type_right = expression->base.type;
-       type_t            const *dst_type        = skip_typeref(orig_dest_type);
-       type_t            const *src_type        = skip_typeref(orig_type_right);
-       source_position_t const *pos             = &cast->base.source_position;
+       expression_t     *expression      = cast->unary.value;
+       type_t           *orig_dest_type  = cast->base.type;
+       type_t           *orig_type_right = expression->base.type;
+       type_t     const *dst_type        = skip_typeref(orig_dest_type);
+       type_t     const *src_type        = skip_typeref(orig_type_right);
+       position_t const *pos             = &cast->base.pos;
 
-       /* §6.5.4 A (void) cast is explicitly permitted, more for documentation than for utility. */
+       /* §6.5.4 A (void) cast is explicitly permitted, more for documentation
+        * than for utility. */
        if (is_type_void(dst_type))
                return true;
 
@@ -6209,21 +6146,52 @@ 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 void semantic_complex_extract(unary_expression_t *extract)
+{
+       type_t *orig_value_type = extract->value->base.type;
+       type_t *value_type      = skip_typeref(orig_value_type);
+       if (!is_type_valid(value_type)) {
+               extract->base.type = type_error_type;
+               return;
+       }
+
+       type_t *type = value_type;
+       if (!is_type_complex(type)) {
+               if (!is_type_arithmetic(type)) {
+                       errorf(&extract->base.pos,
+                                  "%s requires an argument with complex or arithmetic type, got '%T'",
+                                  extract->base.kind == EXPR_UNARY_IMAG ? "__imag__" : "__real__",
+                                  orig_value_type);
+                       extract->base.type = type_error_type;
+                       return;
+               }
+               atomic_type_kind_t const akind = get_arithmetic_akind(type);
+               type = make_complex_type(akind, TYPE_QUALIFIER_NONE);
+               extract->value = create_implicit_cast(extract->value, type);
+       }
+       assert(type->kind == TYPE_COMPLEX);
+       type = make_atomic_type(type->atomic.akind, TYPE_QUALIFIER_NONE);
+       extract->base.type = type;
+}
+
+static expression_t *parse_compound_literal(position_t const *const pos,
+                                            type_t *type)
 {
        expression_t *expression = allocate_expression_zero(EXPR_COMPOUND_LITERAL);
-       expression->base.source_position = *pos;
+       expression->base.pos = *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;
 }
@@ -6233,7 +6201,7 @@ static expression_t *parse_compound_literal(source_position_t const *const pos,
  */
 static expression_t *parse_cast(void)
 {
-       source_position_t const pos = *HERE;
+       position_t const pos = *HERE;
 
        eat('(');
        add_anchor_token(')');
@@ -6248,19 +6216,29 @@ static expression_t *parse_cast(void)
        }
 
        expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
-       cast->base.source_position = pos;
+       cast->base.pos     = pos;
 
        expression_t *value = parse_subexpression(PREC_CAST);
        cast->base.type   = type;
        cast->unary.value = value;
 
-       if (! semantic_cast(cast)) {
-               /* TODO: record the error in the AST. else it is impossible to detect it */
+       if (!semantic_cast(cast)) {
+               cast->base.type = type_error_type;
        }
 
        return cast;
 }
 
+static expression_t *parse_complex_extract_expression(expression_kind_t const kind)
+{
+       expression_t *extract = allocate_expression_zero(kind);
+       next_token();
+
+       extract->unary.value = parse_subexpression(PREC_CAST);
+       semantic_complex_extract(&extract->unary);
+       return extract;
+}
+
 /**
  * Parse a statement expression.
  */
@@ -6286,7 +6264,7 @@ static expression_t *parse_statement_expression(void)
                        type = stmt->expression.expression->base.type;
                }
        } else {
-               source_position_t const *const pos = &expression->base.source_position;
+               position_t const *const pos = &expression->base.pos;
                warningf(WARN_OTHER, pos, "empty statement expression ({})");
        }
        expression->base.type = type;
@@ -6327,7 +6305,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);
@@ -6342,15 +6320,15 @@ static expression_t *parse_function_keyword(funcname_kind_t const kind)
 static designator_t *parse_designator(void)
 {
        designator_t *const result = allocate_ast_zero(sizeof(result[0]));
-       result->symbol = expect_identifier("while parsing member designator", &result->source_position);
+       result->symbol = expect_identifier("while parsing member designator", &result->pos);
        if (!result->symbol)
                return NULL;
 
        designator_t *last_designator = result;
        while (true) {
-               if (next_if('.')) {
+               if (accept('.')) {
                        designator_t *const designator = allocate_ast_zero(sizeof(result[0]));
-                       designator->symbol = expect_identifier("while parsing member designator", &designator->source_position);
+                       designator->symbol = expect_identifier("while parsing member designator", &designator->pos);
                        if (!designator->symbol)
                                return NULL;
 
@@ -6358,16 +6336,13 @@ static designator_t *parse_designator(void)
                        last_designator       = designator;
                        continue;
                }
-               if (next_if('[')) {
+               if (accept('[')) {
                        add_anchor_token(']');
-                       designator_t *designator    = allocate_ast_zero(sizeof(result[0]));
-                       designator->source_position = *HERE;
-                       designator->array_index     = parse_expression();
+                       designator_t *designator = allocate_ast_zero(sizeof(result[0]));
+                       designator->pos          = *HERE;
+                       designator->array_index  = parse_expression();
                        rem_anchor_token(']');
                        expect(']');
-                       if (designator->array_index == NULL) {
-                               return NULL;
-                       }
 
                        last_designator->next = designator;
                        last_designator       = designator;
@@ -6456,11 +6431,11 @@ static expression_t *parse_va_start(void)
        expect(')');
 
        if (!current_function) {
-               errorf(&expression->base.source_position, "'va_start' used outside of function");
+               errorf(&expression->base.pos, "'va_start' used outside of function");
        } else if (!current_function->base.type->function.variadic) {
-               errorf(&expression->base.source_position, "'va_start' used in non-variadic function");
+               errorf(&expression->base.pos, "'va_start' used in non-variadic function");
        } else if (!is_last_parameter(param)) {
-               errorf(&param->base.source_position, "second argument of 'va_start' must be last parameter of the current function");
+               errorf(&param->base.pos, "second argument of 'va_start' must be last parameter of the current function");
        }
 
        return expression;
@@ -6507,7 +6482,7 @@ static expression_t *parse_va_copy(void)
        expression_t *dst = parse_assignment_expression();
        assign_error_t error = semantic_assign(type_valist, dst);
        report_assign_error(error, type_valist, dst, "call argument 1",
-                           &dst->base.source_position);
+                           &dst->base.pos);
        expression->va_copye.dst = dst;
 
        rem_anchor_token(',');
@@ -6534,7 +6509,7 @@ static expression_t *parse_builtin_constant(void)
 
        add_anchor_token(')');
        expect('(');
-       expression->builtin_constant.value = parse_assignment_expression();
+       expression->builtin_constant.value = parse_expression();
        rem_anchor_token(')');
        expect(')');
        expression->base.type = type_int;
@@ -6601,10 +6576,10 @@ static expression_t *parse_compare_builtin(void)
        if (!is_type_float(type_left) && !is_type_float(type_right)) {
                if (is_type_valid(type_left) && is_type_valid(type_right)) {
                        type_error_incompatible("invalid operands in comparison",
-                               &expression->base.source_position, orig_type_left, orig_type_right);
+                               &expression->base.pos, orig_type_left, orig_type_right);
                }
        } else {
-               semantic_comparison(&expression->binary);
+               semantic_comparison(&expression->binary, true);
        }
 
        return expression;
@@ -6621,7 +6596,7 @@ static expression_t *parse_assume(void)
 
        add_anchor_token(')');
        expect('(');
-       expression->unary.value = parse_assignment_expression();
+       expression->unary.value = parse_expression();
        rem_anchor_token(')');
        expect(')');
 
@@ -6649,7 +6624,7 @@ static label_t *get_label(char const *const context)
                }
        } else if (label == NULL || label->base.parent_scope != &current_function->parameters) {
                /* There is no matching label in the same function, so create a new one. */
-               source_position_t const nowhere = { NULL, 0, 0, false };
+               position_t const nowhere = { NULL, 0, 0, false };
                label = allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym, &nowhere);
                label_push(label);
        }
@@ -6662,7 +6637,7 @@ static label_t *get_label(char const *const context)
  */
 static expression_t *parse_label_address(void)
 {
-       source_position_t const source_position = *HERE;
+       position_t const pos = *HERE;
        eat(T_ANDAND);
 
        label_t *const label = get_label("while parsing label address");
@@ -6673,7 +6648,7 @@ static expression_t *parse_label_address(void)
        label->address_taken = true;
 
        expression_t *expression = allocate_expression_zero(EXPR_LABEL_ADDRESS);
-       expression->base.source_position = source_position;
+       expression->base.pos     = pos;
 
        /* label address is treated as a void pointer */
        expression->base.type           = type_void_ptr;
@@ -6702,7 +6677,7 @@ static expression_t *parse_noop_expression(void)
 
                if (token.kind != ')') do {
                        (void)parse_assignment_expression();
-               } while (next_if(','));
+               } while (accept(','));
 
                rem_anchor_token(',');
                rem_anchor_token(')');
@@ -6747,6 +6722,8 @@ static expression_t *parse_primary_expression(void)
 
        case '(':                            return parse_parenthesized_expression();
        case T___noop:                       return parse_noop_expression();
+       case T___imag__:                     return parse_complex_extract_expression(EXPR_UNARY_IMAG);
+       case T___real__:                     return parse_complex_extract_expression(EXPR_UNARY_REAL);
 
        /* Gracefully handle type names while parsing expressions. */
        case T_COLONCOLON:
@@ -6757,7 +6734,7 @@ static expression_t *parse_primary_expression(void)
                }
                /* FALLTHROUGH */
        DECLARATION_START {
-               source_position_t const  pos = *HERE;
+               position_t const pos = *HERE;
                declaration_specifiers_t specifiers;
                parse_declaration_specifiers(&specifiers);
                type_t const *const type = parse_abstract_declarator(specifiers.type);
@@ -6806,14 +6783,15 @@ static expression_t *parse_array_expression(expression_t *left)
 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");
+                       if (is_type_valid(idx_type))
+                               errorf(&idx->base.pos, "array subscript must have integer type");
                } else if (is_type_atomic(idx_type, ATOMIC_TYPE_CHAR)) {
-                       source_position_t const *const pos = &idx->base.source_position;
+                       position_t const *const pos = &idx->base.pos;
                        warningf(WARN_CHAR_SUBSCRIPTS, pos, "array subscript has char type");
                }
        } else {
                if (is_type_valid(type_left) && is_type_valid(type_inside)) {
-                       errorf(&expr->base.source_position, "invalid types '%T[%T]' for array access", orig_type_left, orig_type_inside);
+                       errorf(&expr->base.pos, "invalid types '%T[%T]' for array access", orig_type_left, orig_type_inside);
                }
                res_type = type_error_type;
                ref      = left;
@@ -6845,7 +6823,7 @@ static expression_t *parse_typeprop(expression_kind_t const kind)
        type_t       *orig_type;
        expression_t *expression;
        if (token.kind == '(' && is_declaration_specifier(look_ahead(1))) {
-               source_position_t const pos = *HERE;
+               position_t const pos = *HERE;
                eat('(');
                add_anchor_token(')');
                orig_type = parse_typename();
@@ -6864,7 +6842,7 @@ static expression_t *parse_typeprop(expression_kind_t const kind)
 typeprop_expression:
                if (is_bitfield(expression)) {
                        char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
-                       errorf(&tp_expression->base.source_position,
+                       errorf(&tp_expression->base.pos,
                                   "operand of %s expression must not be a bitfield", what);
                }
 
@@ -6883,8 +6861,8 @@ typeprop_expression:
        } else if (type->kind == TYPE_FUNCTION) {
                if (GNU_MODE) {
                        /* function types are allowed (and return 1) */
-                       source_position_t const *const pos  = &tp_expression->base.source_position;
-                       char              const *const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
+                       position_t const *const pos  = &tp_expression->base.pos;
+                       char       const *const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
                        warningf(WARN_OTHER, pos, "%s expression with function argument returns invalid result", what);
                } else {
                        wrong_type = "function";
@@ -6893,7 +6871,7 @@ typeprop_expression:
 
        if (wrong_type != NULL) {
                char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
-               errorf(&tp_expression->base.source_position,
+               errorf(&tp_expression->base.pos,
                                "operand of %s expression must not be of %s type '%T'",
                                what, wrong_type, orig_type);
        }
@@ -6915,7 +6893,7 @@ static expression_t *parse_select_expression(expression_t *addr)
 {
        assert(token.kind == '.' || token.kind == T_MINUSGREATER);
        bool select_left_arrow = (token.kind == T_MINUSGREATER);
-       source_position_t const pos = *HERE;
+       position_t const pos = *HERE;
        next_token();
 
        symbol_t *const symbol = expect_identifier("while parsing select", NULL);
@@ -7013,14 +6991,14 @@ static void check_call_argument(type_t          *expected_type,
                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);
+                                   &arg_expr->base.pos);
        } else {
                type_t *const promoted_type = get_default_promoted_type(arg_type);
                if (!types_compatible(expected_type_skip, promoted_type) &&
                    !types_compatible(expected_type_skip, type_void_ptr) &&
                    !types_compatible(type_void_ptr,      promoted_type)) {
                        /* Deliberately show the skipped types in this warning */
-                       source_position_t const *const apos = &arg_expr->base.source_position;
+                       position_t const *const apos = &arg_expr->base.pos;
                        warningf(WARN_TRADITIONAL, apos, "passing call argument %u as '%T' rather than '%T' due to prototype", pos, expected_type_skip, promoted_type);
                }
        }
@@ -7041,7 +7019,7 @@ static void handle_builtin_argument_restrictions(call_expression_t *call)
                        call_argument_t *argument = call->arguments;
 
                        if (is_constant_expression(argument->expression) == EXPR_CLASS_VARIABLE) {
-                               errorf(&call->base.source_position,
+                               errorf(&call->base.pos,
                                           "argument of '%Y' must be a constant expression",
                                           call->function->reference.entity->base.symbol);
                        }
@@ -7056,7 +7034,7 @@ static void handle_builtin_argument_restrictions(call_expression_t *call)
 
                        if (rw != NULL) {
                                if (is_constant_expression(rw->expression) == EXPR_CLASS_VARIABLE) {
-                                       errorf(&call->base.source_position,
+                                       errorf(&call->base.pos,
                                                   "second argument of '%Y' must be a constant expression",
                                                   call->function->reference.entity->base.symbol);
                                }
@@ -7064,11 +7042,10 @@ static void handle_builtin_argument_restrictions(call_expression_t *call)
                        }
                        if (locality != NULL) {
                                if (is_constant_expression(locality->expression) == EXPR_CLASS_VARIABLE) {
-                                       errorf(&call->base.source_position,
+                                       errorf(&call->base.pos,
                                                   "third argument of '%Y' must be a constant expression",
                                                   call->function->reference.entity->base.symbol);
                                }
-                               locality = rw->next;
                        }
                        break;
                default:
@@ -7081,7 +7058,7 @@ static void handle_builtin_argument_restrictions(call_expression_t *call)
 
                call_argument_t *arg = call->arguments->next;
                if (arg != NULL && is_constant_expression(arg->expression) == EXPR_CLASS_VARIABLE) {
-                       errorf(&call->base.source_position,
+                       errorf(&call->base.pos,
                                   "second argument of '%Y' must be a constant expression",
                                   call->function->reference.entity->base.symbol);
                }
@@ -7092,7 +7069,7 @@ static void handle_builtin_argument_restrictions(call_expression_t *call)
 }
 
 /**
- * Parse a call expression, ie. expression '( ... )'.
+ * Parse a call expression, i.e. expression '( ... )'.
  *
  * @param expression  the function address
  */
@@ -7134,7 +7111,7 @@ static expression_t *parse_call_expression(expression_t *expression)
 
                        *anchor = argument;
                        anchor  = &argument->next;
-               } while (next_if(','));
+               } while (accept(','));
        }
        rem_anchor_token(',');
        rem_anchor_token(')');
@@ -7153,9 +7130,11 @@ static expression_t *parse_call_expression(expression_t *expression)
                }
 
                if (parameter != NULL) {
-                       errorf(&expression->base.source_position, "too few arguments to function '%E'", expression);
+                       errorf(&expression->base.pos, "too few arguments to function '%E'",
+                              expression);
                } else if (argument != NULL && !function_type->variadic) {
-                       errorf(&argument->expression->base.source_position, "too many arguments to function '%E'", expression);
+                       errorf(&argument->expression->base.pos,
+                              "too many arguments to function '%E'", expression);
                }
        }
 
@@ -7163,7 +7142,7 @@ static expression_t *parse_call_expression(expression_t *expression)
        for (; argument != NULL; argument = argument->next) {
                type_t *argument_type = argument->expression->base.type;
                if (!is_type_object(skip_typeref(argument_type))) {
-                       errorf(&argument->expression->base.source_position,
+                       errorf(&argument->expression->base.pos,
                               "call argument '%E' must not be void", argument->expression);
                }
 
@@ -7176,7 +7155,7 @@ static expression_t *parse_call_expression(expression_t *expression)
        check_format(call);
 
        if (is_type_compound(skip_typeref(function_type->return_type))) {
-               source_position_t const *const pos = &expression->base.source_position;
+               position_t const *const pos = &expression->base.pos;
                warningf(WARN_AGGREGATE_RETURN, pos, "function call has aggregate value");
        }
 
@@ -7233,8 +7212,8 @@ static void warn_reference_address_as_bool(expression_t const* expr)
 {
        expr = get_reference_address(expr);
        if (expr != NULL) {
-               source_position_t const *const pos = &expr->base.source_position;
-               entity_t          const *const ent = expr->reference.entity;
+               position_t const *const pos = &expr->base.pos;
+               entity_t   const *const ent = expr->reference.entity;
                warningf(WARN_ADDRESS, pos, "the address of '%N' will always evaluate as 'true'", ent);
        }
 }
@@ -7245,7 +7224,7 @@ static void warn_assignment_in_condition(const expression_t *const expr)
                return;
        if (expr->base.parenthesized)
                return;
-       source_position_t const *const pos = &expr->base.source_position;
+       position_t const *const pos = &expr->base.pos;
        warningf(WARN_PARENTHESES, pos, "suggest parentheses around assignment used as truth value");
 }
 
@@ -7257,13 +7236,12 @@ static void semantic_condition(expression_t const *const expr,
                warn_reference_address_as_bool(expr);
                warn_assignment_in_condition(expr);
        } else if (is_type_valid(type)) {
-               errorf(&expr->base.source_position,
-                               "%s must have scalar type", context);
+               errorf(&expr->base.pos, "%s must have scalar type", context);
        }
 }
 
 /**
- * Parse a conditional expression, ie. 'expression ? ... : ...'.
+ * Parse a conditional expression, i.e. 'expression ? ... : ...'.
  *
  * @param expression  the conditional expression
  */
@@ -7298,8 +7276,8 @@ static expression_t *parse_conditional_expression(expression_t *expression)
        type_t *const false_type      = skip_typeref(orig_false_type);
 
        /* 6.5.15.3 */
-       source_position_t const *const pos = &conditional->base.source_position;
-       type_t                        *result_type;
+       position_t const *const pos = &conditional->base.pos;
+       type_t                 *result_type;
        if (is_type_void(true_type) || is_type_void(false_type)) {
                /* ISO/IEC 14882:1998(E) §5.16:2 */
                if (true_expression->kind == EXPR_UNARY_THROW) {
@@ -7417,7 +7395,7 @@ static expression_t *parse_delete(void)
 
        eat(T_delete);
 
-       if (next_if('[')) {
+       if (accept('[')) {
                result->kind = EXPR_UNARY_DELETE_ARRAY;
                expect(']');
        }
@@ -7428,11 +7406,11 @@ static expression_t *parse_delete(void)
        type_t *const type = skip_typeref(value->base.type);
        if (!is_type_pointer(type)) {
                if (is_type_valid(type)) {
-                       errorf(&value->base.source_position,
+                       errorf(&value->base.pos,
                                        "operand of delete must have pointer type");
                }
        } else if (is_type_void(skip_typeref(type->pointer.points_to))) {
-               source_position_t const *const pos = &value->base.source_position;
+               position_t const *const pos = &value->base.pos;
                warningf(WARN_OTHER, pos, "deleting 'void*' is undefined");
        }
 
@@ -7458,12 +7436,12 @@ static expression_t *parse_throw(void)
                        type_t *const orig_type = value->base.type;
                        type_t *const type      = skip_typeref(orig_type);
                        if (is_type_incomplete(type)) {
-                               errorf(&value->base.source_position,
+                               errorf(&value->base.pos,
                                                "cannot throw object of incomplete type '%T'", orig_type);
                        } else if (is_type_pointer(type)) {
                                type_t *const points_to = skip_typeref(type->pointer.points_to);
                                if (is_type_incomplete(points_to) && !is_type_void(points_to)) {
-                                       errorf(&value->base.source_position,
+                                       errorf(&value->base.pos,
                                                        "cannot throw pointer to incomplete type '%T'", orig_type);
                                }
                        }
@@ -7477,7 +7455,7 @@ static expression_t *parse_throw(void)
        return result;
 }
 
-static bool check_pointer_arithmetic(const source_position_t *source_position,
+static bool check_pointer_arithmetic(const position_t *pos,
                                      type_t *pointer_type,
                                      type_t *orig_pointer_type)
 {
@@ -7486,21 +7464,23 @@ static bool check_pointer_arithmetic(const source_position_t *source_position,
 
        if (is_type_incomplete(points_to)) {
                if (!GNU_MODE || !is_type_void(points_to)) {
-                       errorf(source_position,
+                       errorf(pos,
                               "arithmetic with pointer to incomplete type '%T' not allowed",
                               orig_pointer_type);
                        return false;
                } else {
-                       warningf(WARN_POINTER_ARITH, source_position, "pointer of type '%T' used in arithmetic", orig_pointer_type);
+                       warningf(WARN_POINTER_ARITH, pos, "pointer of type '%T' used in arithmetic", orig_pointer_type);
                }
        } else if (is_type_function(points_to)) {
                if (!GNU_MODE) {
-                       errorf(source_position,
+                       errorf(pos,
                               "arithmetic with pointer to function type '%T' not allowed",
                               orig_pointer_type);
                        return false;
                } else {
-                       warningf(WARN_POINTER_ARITH, source_position, "pointer to a function '%T' used in arithmetic", orig_pointer_type);
+                       warningf(WARN_POINTER_ARITH, pos,
+                                "pointer to a function '%T' used in arithmetic",
+                                orig_pointer_type);
                }
        }
        return true;
@@ -7532,29 +7512,38 @@ static bool is_lvalue(const expression_t *expression)
 
 static void semantic_incdec(unary_expression_t *expression)
 {
-       type_t *const orig_type = expression->value->base.type;
-       type_t *const type      = skip_typeref(orig_type);
+       type_t *orig_type = expression->value->base.type;
+       type_t *type      = skip_typeref(orig_type);
        if (is_type_pointer(type)) {
-               if (!check_pointer_arithmetic(&expression->base.source_position,
-                                             type, orig_type)) {
+               if (!check_pointer_arithmetic(&expression->base.pos, type, orig_type)) {
                        return;
                }
-       } else if (!is_type_real(type) && is_type_valid(type)) {
+       } else if (!is_type_real(type) &&
+                  (!GNU_MODE || !is_type_complex(type)) && is_type_valid(type)) {
                /* TODO: improve error message */
-               errorf(&expression->base.source_position,
+               errorf(&expression->base.pos,
                       "operation needs an arithmetic or pointer type");
-               return;
+               orig_type = type = type_error_type;
        }
        if (!is_lvalue(expression->value)) {
                /* TODO: improve error message */
-               errorf(&expression->base.source_position, "lvalue required as operand");
+               errorf(&expression->base.pos, "lvalue required as operand");
        }
        expression->base.type = orig_type;
 }
 
 static void promote_unary_int_expr(unary_expression_t *const expr, type_t *const type)
 {
-       type_t *const res_type = promote_integer(type);
+       atomic_type_kind_t akind = get_arithmetic_akind(type);
+       type_t *res_type;
+       if (get_akind_rank(akind) < get_akind_rank(ATOMIC_TYPE_INT)) {
+               if (type->kind == TYPE_COMPLEX)
+                       res_type = make_complex_type(ATOMIC_TYPE_INT, TYPE_QUALIFIER_NONE);
+               else
+                       res_type = type_int;
+       } else {
+               res_type = type;
+       }
        expr->base.type = res_type;
        expr->value     = create_implicit_cast(expr->value, res_type);
 }
@@ -7565,9 +7554,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");
+                       position_t const *const pos = &expression->base.pos;
+                       errorf(pos, "operand of unary expression must have arithmetic type, but is '%T'", orig_type);
                }
                return;
        } else if (is_type_integer(type)) {
@@ -7580,7 +7568,7 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression)
 static void semantic_unexpr_plus(unary_expression_t *expression)
 {
        semantic_unexpr_arithmetic(expression);
-       source_position_t const *const pos = &expression->base.source_position;
+       position_t const *const pos = &expression->base.pos;
        warningf(WARN_TRADITIONAL, pos, "traditional C rejects the unary plus operator");
 }
 
@@ -7591,19 +7579,22 @@ static void semantic_not(unary_expression_t *expression)
        expression->base.type = c_mode & _CXX ? type_bool : type_int;
 }
 
-static void semantic_unexpr_integer(unary_expression_t *expression)
+static void semantic_complement(unary_expression_t *expression)
 {
        type_t *const orig_type = expression->value->base.type;
        type_t *const type      = skip_typeref(orig_type);
-       if (!is_type_integer(type)) {
+       if (!is_type_integer(type) && (!GNU_MODE || !is_type_complex(type))) {
                if (is_type_valid(type)) {
-                       errorf(&expression->base.source_position,
-                              "operand of ~ must be of integer type");
+                       errorf(&expression->base.pos, "operand of ~ must be of integer type");
                }
                return;
        }
 
-       promote_unary_int_expr(expression, type);
+       if (is_type_integer(type)) {
+               promote_unary_int_expr(expression, type);
+       } else {
+               expression->base.type = orig_type;
+       }
 }
 
 static void semantic_dereference(unary_expression_t *expression)
@@ -7612,7 +7603,7 @@ static void semantic_dereference(unary_expression_t *expression)
        type_t *const type      = skip_typeref(orig_type);
        if (!is_type_pointer(type)) {
                if (is_type_valid(type)) {
-                       errorf(&expression->base.source_position,
+                       errorf(&expression->base.pos,
                               "Unary '*' needs pointer or array type, but type '%T' given", orig_type);
                }
                return;
@@ -7641,7 +7632,7 @@ static void set_address_taken(expression_t *expression, bool may_be_register)
 
        if (entity->declaration.storage_class == STORAGE_CLASS_REGISTER
                        && !may_be_register) {
-               source_position_t const *const pos = &expression->base.source_position;
+               position_t const *const pos = &expression->base.pos;
                errorf(pos, "address of register '%N' requested", entity);
        }
 
@@ -7663,11 +7654,10 @@ static void semantic_take_addr(unary_expression_t *expression)
 
        /* §6.5.3.2 */
        if (!is_lvalue(value)) {
-               errorf(&expression->base.source_position, "'&' requires an lvalue");
+               errorf(&expression->base.pos, "'&' requires an lvalue");
        }
        if (is_bitfield(value)) {
-               errorf(&expression->base.source_position,
-                      "'&' not allowed on bitfield");
+               errorf(&expression->base.pos, "'&' not allowed on bitfield");
        }
 
        set_address_taken(value, false);
@@ -7698,8 +7688,8 @@ CREATE_UNARY_EXPRESSION_PARSER('*', EXPR_UNARY_DEREFERENCE,
                                semantic_dereference)
 CREATE_UNARY_EXPRESSION_PARSER('&', EXPR_UNARY_TAKE_ADDRESS,
                                semantic_take_addr)
-CREATE_UNARY_EXPRESSION_PARSER('~', EXPR_UNARY_BITWISE_NEGATE,
-                               semantic_unexpr_integer)
+CREATE_UNARY_EXPRESSION_PARSER('~', EXPR_UNARY_COMPLEMENT,
+                               semantic_complement)
 CREATE_UNARY_EXPRESSION_PARSER(T_PLUSPLUS,   EXPR_UNARY_PREFIX_INCREMENT,
                                semantic_incdec)
 CREATE_UNARY_EXPRESSION_PARSER(T_MINUSMINUS, EXPR_UNARY_PREFIX_DECREMENT,
@@ -7726,67 +7716,78 @@ CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(T_MINUSMINUS,
                                        EXPR_UNARY_POSTFIX_DECREMENT,
                                        semantic_incdec)
 
-static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right)
+static atomic_type_kind_t semantic_arithmetic_(atomic_type_kind_t kind_left,
+                                               atomic_type_kind_t kind_right)
 {
-       /* TODO: handle complex + imaginary types */
-
-       type_left  = get_unqualified_type(type_left);
-       type_right = get_unqualified_type(type_right);
-
        /* §6.3.1.8 Usual arithmetic conversions */
-       if (type_left == type_long_double || type_right == type_long_double) {
-               return type_long_double;
-       } else if (type_left == type_double || type_right == type_double) {
-               return type_double;
-       } else if (type_left == type_float || type_right == type_float) {
-               return type_float;
-       }
-
-       type_left  = promote_integer(type_left);
-       type_right = promote_integer(type_right);
-
-       if (type_left == type_right)
-               return type_left;
-
-       bool     const signed_left  = is_type_signed(type_left);
-       bool     const signed_right = is_type_signed(type_right);
-       unsigned const rank_left    = get_akind_rank(get_akind(type_left));
-       unsigned const rank_right   = get_akind_rank(get_akind(type_right));
-
+       if (kind_left == ATOMIC_TYPE_LONG_DOUBLE
+        || kind_right == ATOMIC_TYPE_LONG_DOUBLE) {
+               return ATOMIC_TYPE_LONG_DOUBLE;
+       } else if (kind_left == ATOMIC_TYPE_DOUBLE
+               || kind_right == ATOMIC_TYPE_DOUBLE) {
+           return ATOMIC_TYPE_DOUBLE;
+       } else if (kind_left == ATOMIC_TYPE_FLOAT
+               || kind_right == ATOMIC_TYPE_FLOAT) {
+               return ATOMIC_TYPE_FLOAT;
+       }
+
+       unsigned       rank_left  = get_akind_rank(kind_left);
+       unsigned       rank_right = get_akind_rank(kind_right);
+       unsigned const rank_int   = get_akind_rank(ATOMIC_TYPE_INT);
+       if (rank_left < rank_int) {
+               kind_left = ATOMIC_TYPE_INT;
+               rank_left = rank_int;
+       }
+       if (rank_right < rank_int) {
+               kind_right = ATOMIC_TYPE_INT;
+               rank_right = rank_int;
+       }
+       if (kind_left == kind_right)
+               return kind_left;
+
+       bool const signed_left  = is_akind_signed(kind_left);
+       bool const signed_right = is_akind_signed(kind_right);
        if (signed_left == signed_right)
-               return rank_left >= rank_right ? type_left : type_right;
+               return rank_left >= rank_right ? kind_left : kind_right;
 
        unsigned           s_rank;
        unsigned           u_rank;
-       atomic_type_kind_t s_akind;
-       atomic_type_kind_t u_akind;
-       type_t *s_type;
-       type_t *u_type;
+       atomic_type_kind_t s_kind;
+       atomic_type_kind_t u_kind;
        if (signed_left) {
-               s_type = type_left;
-               u_type = type_right;
+               s_kind = kind_left;
+               s_rank = rank_left;
+               u_kind = kind_right;
+               u_rank = rank_right;
        } else {
-               s_type = type_right;
-               u_type = type_left;
+               s_kind = kind_right;
+               s_rank = rank_right;
+               u_kind = kind_left;
+               u_rank = rank_left;
        }
-       s_akind = get_akind(s_type);
-       u_akind = get_akind(u_type);
-       s_rank  = get_akind_rank(s_akind);
-       u_rank  = get_akind_rank(u_akind);
-
        if (u_rank >= s_rank)
-               return u_type;
-
-       if (get_atomic_type_size(s_akind) > get_atomic_type_size(u_akind))
-               return s_type;
+               return u_kind;
+       if (get_atomic_type_size(s_kind) > get_atomic_type_size(u_kind))
+               return s_kind;
+
+       switch (s_kind) {
+       case ATOMIC_TYPE_INT:      return ATOMIC_TYPE_UINT;
+       case ATOMIC_TYPE_LONG:     return ATOMIC_TYPE_ULONG;
+       case ATOMIC_TYPE_LONGLONG: return ATOMIC_TYPE_ULONGLONG;
+       default: panic("invalid atomic type");
+       }
+}
 
-       switch (s_akind) {
-       case ATOMIC_TYPE_INT:      return type_unsigned_int;
-       case ATOMIC_TYPE_LONG:     return type_unsigned_long;
-       case ATOMIC_TYPE_LONGLONG: return type_unsigned_long_long;
+static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right)
+{
+       atomic_type_kind_t kind_left  = get_arithmetic_akind(type_left);
+       atomic_type_kind_t kind_right = get_arithmetic_akind(type_right);
+       atomic_type_kind_t kind_res   = semantic_arithmetic_(kind_left, kind_right);
 
-       default: panic("invalid atomic type");
+       if (type_left->kind == TYPE_COMPLEX || type_right->kind == TYPE_COMPLEX) {
+               return make_complex_type(kind_res, TYPE_QUALIFIER_NONE);
        }
+       return make_atomic_type(kind_res, TYPE_QUALIFIER_NONE);
 }
 
 /**
@@ -7802,10 +7803,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");
+                       position_t const *const pos = &expression->base.pos;
+                       errorf(pos, "operands of binary expression must have arithmetic types, but are '%T' and '%T'", orig_type_left, orig_type_right);
                }
                return;
        }
@@ -7825,11 +7825,11 @@ static void semantic_binexpr_integer(binary_expression_t *const expression)
        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_integer(type_left) || !is_type_integer(type_right)
+         || is_type_complex(type_left) || is_type_complex(type_right)) {
                if (is_type_valid(type_left) && is_type_valid(type_right)) {
-                       errorf(&expression->base.source_position,
-                              "operation needs integer types");
+                       position_t const *const pos = &expression->base.pos;
+                       errorf(pos, "operands of binary expression must have integer types, but are '%T' and '%T'", orig_type_left, orig_type_right);
                }
                return;
        }
@@ -7847,23 +7847,32 @@ static void warn_div_by_zero(binary_expression_t const *const expression)
 
        expression_t const *const right = expression->right;
        /* The type of the right operand can be different for /= */
-       if (is_type_integer(right->base.type)                    &&
-           is_constant_expression(right) == EXPR_CLASS_CONSTANT &&
+       if (is_type_integer(skip_typeref(right->base.type))      &&
+           is_constant_expression(right) >= EXPR_CLASS_CONSTANT &&
            !fold_constant_to_bool(right)) {
-               source_position_t const *const pos = &expression->base.source_position;
+               position_t const *const pos = &expression->base.pos;
                warningf(WARN_DIV_BY_ZERO, pos, "division by zero");
        }
 }
 
 /**
- * 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)
@@ -7876,7 +7885,7 @@ static void warn_addsub_in_shift(const expression_t *const expr)
                default:              return;
        }
 
-       source_position_t const *const pos = &expr->base.source_position;
+       position_t const *const pos = &expr->base.pos;
        warningf(WARN_PARENTHESES, pos, "suggest parentheses around '%c' inside shift", op);
 }
 
@@ -7890,19 +7899,18 @@ 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");
+                       position_t const *const pos = &expression->base.pos;
+                       errorf(pos, "operands of shift expression must have integer types, but are '%T' and '%T'", orig_type_left, orig_type_right);
                }
                return false;
        }
 
        type_left = promote_integer(type_left);
 
-       if (is_constant_expression(right) == EXPR_CLASS_CONSTANT) {
-               source_position_t const *const pos   = &right->base.source_position;
-               long                     const count = fold_constant_to_int(right);
+       if (is_constant_expression(right) >= EXPR_CLASS_CONSTANT) {
+               position_t const *const pos   = &right->base.pos;
+               long              const count = fold_constant_to_int(right);
                if (count < 0) {
                        warningf(WARN_OTHER, pos, "shift count must be non-negative");
                } else if ((unsigned long)count >=
@@ -7952,15 +7960,15 @@ static void semantic_add(binary_expression_t *expression)
                expression->right = create_implicit_cast(right, arithmetic_type);
                expression->base.type = arithmetic_type;
        } else if (is_type_pointer(type_left) && is_type_integer(type_right)) {
-               check_pointer_arithmetic(&expression->base.source_position,
-                                        type_left, orig_type_left);
+               check_pointer_arithmetic(&expression->base.pos, type_left,
+                                        orig_type_left);
                expression->base.type = type_left;
        } else if (is_type_pointer(type_right) && is_type_integer(type_left)) {
-               check_pointer_arithmetic(&expression->base.source_position,
-                                        type_right, orig_type_right);
+               check_pointer_arithmetic(&expression->base.pos, type_right,
+                                        orig_type_right);
                expression->base.type = type_right;
        } else if (is_type_valid(type_left) && is_type_valid(type_right)) {
-               errorf(&expression->base.source_position,
+               errorf(&expression->base.pos,
                       "invalid operands to binary + ('%T', '%T')",
                       orig_type_left, orig_type_right);
        }
@@ -7968,13 +7976,13 @@ static void semantic_add(binary_expression_t *expression)
 
 static void semantic_sub(binary_expression_t *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);
-       source_position_t const *const pos             = &expression->base.source_position;
+       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);
+       position_t const *const pos             = &expression->base.pos;
 
        /* §5.6.5 */
        if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
@@ -7983,8 +7991,8 @@ static void semantic_sub(binary_expression_t *expression)
                expression->right       = create_implicit_cast(right, arithmetic_type);
                expression->base.type =  arithmetic_type;
        } else if (is_type_pointer(type_left) && is_type_integer(type_right)) {
-               check_pointer_arithmetic(&expression->base.source_position,
-                                        type_left, orig_type_left);
+               check_pointer_arithmetic(&expression->base.pos, type_left,
+                                        orig_type_left);
                expression->base.type = type_left;
        } else if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
                type_t *const unqual_left  = get_unqualified_type(skip_typeref(type_left->pointer.points_to));
@@ -8018,7 +8026,7 @@ static void warn_string_literal_address(expression_t const* expr)
        }
 
        if (expr->kind == EXPR_STRING_LITERAL) {
-               source_position_t const *const pos = &expr->base.source_position;
+               position_t const *const pos = &expr->base.pos;
                warningf(WARN_ADDRESS, pos, "comparison with string literal results in unspecified behaviour");
        }
 }
@@ -8026,13 +8034,15 @@ static void warn_string_literal_address(expression_t const* expr)
 static bool maybe_negative(expression_t const *const expr)
 {
        switch (is_constant_expression(expr)) {
-               case EXPR_CLASS_ERROR:    return false;
-               case EXPR_CLASS_CONSTANT: return constant_is_negative(expr);
-               default:                  return true;
+               case EXPR_CLASS_VARIABLE:         return true;
+               case EXPR_CLASS_ERROR:            return false;
+               case EXPR_CLASS_CONSTANT:
+               case EXPR_CLASS_INTEGER_CONSTANT: return constant_is_negative(expr);
        }
+       panic("invalid expression classification");
 }
 
-static void warn_comparison(source_position_t const *const pos, expression_t const *const expr, expression_t const *const other)
+static void warn_comparison(position_t const *const pos, expression_t const *const expr, expression_t const *const other)
 {
        warn_string_literal_address(expr);
 
@@ -8060,14 +8070,13 @@ static void warn_comparison(source_position_t const *const pos, expression_t con
 
 /**
  * Check the semantics of comparison expressions.
- *
- * @param expression   The expression to check.
  */
-static void semantic_comparison(binary_expression_t *expression)
+static void semantic_comparison(binary_expression_t *expression,
+                                bool is_relational)
 {
-       source_position_t const *const pos   = &expression->base.source_position;
-       expression_t            *const left  = expression->left;
-       expression_t            *const right = expression->right;
+       position_t const *const pos   = &expression->base.pos;
+       expression_t     *const left  = expression->left;
+       expression_t     *const right = expression->right;
 
        warn_comparison(pos, left, right);
        warn_comparison(pos, right, left);
@@ -8095,14 +8104,17 @@ static void semantic_comparison(binary_expression_t *expression)
                        }
                }
 
-               expression->left        = create_implicit_cast(left, arithmetic_type);
-               expression->right       = create_implicit_cast(right, arithmetic_type);
-               expression->base.type   = arithmetic_type;
-               if ((expression->base.kind == EXPR_BINARY_EQUAL ||
-                    expression->base.kind == EXPR_BINARY_NOTEQUAL) &&
-                   is_type_float(arithmetic_type)) {
+               expression->left      = create_implicit_cast(left, arithmetic_type);
+               expression->right     = create_implicit_cast(right, arithmetic_type);
+               expression->base.type = arithmetic_type;
+               if (!is_relational && is_type_float(arithmetic_type)) {
                        warningf(WARN_FLOAT_EQUAL, pos, "comparing floating point with == or != is unsafe");
                }
+               /* for relational ops we need real types, not just arithmetic */
+               if (is_relational
+                   && (!is_type_real(type_left) || !is_type_real(type_right))) {
+                       type_error_incompatible("invalid operands for relational operator", pos, type_left, type_right);
+               }
        } else if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
                /* TODO check compatibility */
        } else if (is_type_pointer(type_left)) {
@@ -8115,6 +8127,16 @@ static void semantic_comparison(binary_expression_t *expression)
        expression->base.type = c_mode & _CXX ? type_bool : type_int;
 }
 
+static void semantic_relational(binary_expression_t *expression)
+{
+       semantic_comparison(expression, true);
+}
+
+static void semantic_equality(binary_expression_t *expression)
+{
+       semantic_comparison(expression, false);
+}
+
 /**
  * Checks if a compound type has constant fields.
  */
@@ -8141,33 +8163,34 @@ 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(&left->base.source_position, "left hand side '%E' of assignment is not an lvalue",
-                      left);
+               errorf(&left->base.pos,
+                      "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(&left->base.source_position, "cannot assign to function '%E'", left);
+               errorf(&left->base.pos, "cannot assign to function '%E'", left);
                return false;
        }
 
        if (is_type_array(type_left)) {
-               errorf(&left->base.source_position, "cannot assign to array '%E'", left);
+               errorf(&left->base.pos, "cannot assign to array '%E'", left);
                return false;
        }
        if (type_left->base.qualifiers & TYPE_QUALIFIER_CONST) {
-               errorf(&left->base.source_position, "assignment to read-only location '%E' (type '%T')", left,
+               errorf(&left->base.pos,
+                      "assignment to read-only location '%E' (type '%T')", left,
                       orig_type_left);
                return false;
        }
        if (is_type_incomplete(type_left)) {
-               errorf(&left->base.source_position, "left-hand side '%E' of assignment has incomplete type '%T'",
+               errorf(&left->base.pos, "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(&left->base.source_position, "cannot assign to '%E' because compound type '%T' has read-only fields",
+               errorf(&left->base.pos, "cannot assign to '%E' because compound type '%T' has read-only fields",
                       left, orig_type_left);
                return false;
        }
@@ -8191,8 +8214,7 @@ static void semantic_arithmetic_assign(binary_expression_t *expression)
        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");
+                       errorf(&expression->base.pos, "operation needs arithmetic types");
                }
                return;
        }
@@ -8233,11 +8255,11 @@ static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression)
                expression->right     = create_implicit_cast(right, arithmetic_type);
                expression->base.type = type_left;
        } else if (is_type_pointer(type_left) && is_type_integer(type_right)) {
-               check_pointer_arithmetic(&expression->base.source_position,
-                                        type_left, orig_type_left);
+               check_pointer_arithmetic(&expression->base.pos, type_left,
+                                        orig_type_left);
                expression->base.type = type_left;
        } else if (is_type_valid(type_left) && is_type_valid(type_right)) {
-               errorf(&expression->base.source_position,
+               errorf(&expression->base.pos,
                       "incompatible types '%T' and '%T' in assignment",
                       orig_type_left, orig_type_right);
        }
@@ -8259,8 +8281,7 @@ static void semantic_integer_assign(binary_expression_t *expression)
        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");
+                       errorf(&expression->base.pos, "operation needs integer types");
                }
                return;
        }
@@ -8293,7 +8314,7 @@ static void warn_logical_and_within_or(const expression_t *const expr)
                return;
        if (expr->base.parenthesized)
                return;
-       source_position_t const *const pos = &expr->base.source_position;
+       position_t const *const pos = &expr->base.pos;
        warningf(WARN_PARENTHESES, pos, "suggest parentheses around && within ||");
 }
 
@@ -8326,7 +8347,7 @@ static void semantic_binexpr_assign(binary_expression_t *expression)
 
        assign_error_t error = semantic_assign(orig_type_left, expression->right);
        report_assign_error(error, orig_type_left, expression->right,
-                       "assignment", &left->base.source_position);
+                           "assignment", &left->base.pos);
        expression->right = create_implicit_cast(expression->right, orig_type_left);
        expression->base.type = orig_type_left;
 }
@@ -8398,10 +8419,12 @@ static bool expression_has_effect(const expression_t *const expr)
 
                case EXPR_UNARY_NEGATE:               return false;
                case EXPR_UNARY_PLUS:                 return false;
-               case EXPR_UNARY_BITWISE_NEGATE:       return false;
+               case EXPR_UNARY_COMPLEMENT:           return false;
                case EXPR_UNARY_NOT:                  return false;
                case EXPR_UNARY_DEREFERENCE:          return false;
                case EXPR_UNARY_TAKE_ADDRESS:         return false;
+               case EXPR_UNARY_REAL:                 return false;
+               case EXPR_UNARY_IMAG:                 return false;
                case EXPR_UNARY_POSTFIX_INCREMENT:    return true;
                case EXPR_UNARY_POSTFIX_DECREMENT:    return true;
                case EXPR_UNARY_PREFIX_INCREMENT:     return true;
@@ -8472,7 +8495,7 @@ static void semantic_comma(binary_expression_t *expression)
 {
        const expression_t *const left = expression->left;
        if (!expression_has_effect(left)) {
-               source_position_t const *const pos = &left->base.source_position;
+               position_t const *const pos = &left->base.pos;
                warningf(WARN_UNUSED_VALUE, pos, "left-hand operand of comma expression has no effect");
        }
        expression->base.type = expression->right->base.type;
@@ -8497,18 +8520,18 @@ 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)
 CREATE_BINEXPR_PARSER(T_GREATERGREATER,       EXPR_BINARY_SHIFTRIGHT,         PREC_ADDITIVE,       semantic_shift_op)
-CREATE_BINEXPR_PARSER('<',                    EXPR_BINARY_LESS,               PREC_SHIFT,          semantic_comparison)
-CREATE_BINEXPR_PARSER('>',                    EXPR_BINARY_GREATER,            PREC_SHIFT,          semantic_comparison)
-CREATE_BINEXPR_PARSER(T_LESSEQUAL,            EXPR_BINARY_LESSEQUAL,          PREC_SHIFT,          semantic_comparison)
-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_LESS,               PREC_SHIFT,          semantic_relational)
+CREATE_BINEXPR_PARSER('>',                    EXPR_BINARY_GREATER,            PREC_SHIFT,          semantic_relational)
+CREATE_BINEXPR_PARSER(T_LESSEQUAL,            EXPR_BINARY_LESSEQUAL,          PREC_SHIFT,          semantic_relational)
+CREATE_BINEXPR_PARSER(T_GREATEREQUAL,         EXPR_BINARY_GREATEREQUAL,       PREC_SHIFT,          semantic_relational)
+CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, EXPR_BINARY_NOTEQUAL,           PREC_RELATIONAL,     semantic_equality)
+CREATE_BINEXPR_PARSER(T_EQUALEQUAL,           EXPR_BINARY_EQUAL,              PREC_RELATIONAL,     semantic_equality)
 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)
@@ -8644,7 +8667,7 @@ static void init_expression_parsers(void)
        register_expression_parser(parse_EXPR_UNARY_NEGATE,           '-');
        register_expression_parser(parse_EXPR_UNARY_PLUS,             '+');
        register_expression_parser(parse_EXPR_UNARY_NOT,              '!');
-       register_expression_parser(parse_EXPR_UNARY_BITWISE_NEGATE,   '~');
+       register_expression_parser(parse_EXPR_UNARY_COMPLEMENT,       '~');
        register_expression_parser(parse_EXPR_UNARY_DEREFERENCE,      '*');
        register_expression_parser(parse_EXPR_UNARY_TAKE_ADDRESS,     '&');
        register_expression_parser(parse_EXPR_UNARY_PREFIX_INCREMENT, T_PLUSPLUS);
@@ -8660,120 +8683,132 @@ static void init_expression_parsers(void)
 /**
  * Parse a asm statement arguments specification.
  */
-static asm_argument_t *parse_asm_arguments(bool is_out)
+static void parse_asm_arguments(asm_argument_t **anchor, bool const is_out)
 {
-       asm_argument_t  *result = NULL;
-       asm_argument_t **anchor = &result;
-
-       while (token.kind == T_STRING_LITERAL || token.kind == '[') {
-               asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
+       if (token.kind == T_STRING_LITERAL || token.kind == '[') {
+               add_anchor_token(',');
+               do {
+                       asm_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
 
-               if (next_if('[')) {
-                       add_anchor_token(']');
-                       argument->symbol = expect_identifier("while parsing asm argument", NULL);
-                       rem_anchor_token(']');
-                       expect(']');
-                       if (!argument->symbol)
-                               return NULL;
-               }
+                       add_anchor_token(')');
+                       add_anchor_token('(');
+                       add_anchor_token(T_STRING_LITERAL);
 
-               argument->constraints = parse_string_literals("asm argument");
-               add_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
-                        * int -> float is not) */
-                       if (expression->kind == EXPR_UNARY_CAST) {
-                               type_t      *const type = expression->base.type;
-                               type_kind_t  const kind = type->kind;
-                               if (kind == TYPE_ATOMIC || kind == TYPE_POINTER) {
-                                       unsigned flags;
-                                       unsigned size;
-                                       if (kind == TYPE_ATOMIC) {
-                                               atomic_type_kind_t const akind = type->atomic.akind;
-                                               flags = get_atomic_type_flags(akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
-                                               size  = get_atomic_type_size(akind);
-                                       } else {
-                                               flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
-                                               size  = get_type_size(type_void_ptr);
-                                       }
+                       if (accept('[')) {
+                               add_anchor_token(']');
+                               argument->symbol = expect_identifier("while parsing asm argument", NULL);
+                               rem_anchor_token(']');
+                               expect(']');
+                       }
 
-                                       do {
-                                               expression_t *const value      = expression->unary.value;
-                                               type_t       *const value_type = value->base.type;
-                                               type_kind_t   const value_kind = value_type->kind;
-
-                                               unsigned value_flags;
-                                               unsigned value_size;
-                                               if (value_kind == TYPE_ATOMIC) {
-                                                       atomic_type_kind_t const value_akind = value_type->atomic.akind;
-                                                       value_flags = get_atomic_type_flags(value_akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
-                                                       value_size  = get_atomic_type_size(value_akind);
-                                               } else if (value_kind == TYPE_POINTER) {
-                                                       value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
-                                                       value_size  = get_type_size(type_void_ptr);
+                       rem_anchor_token(T_STRING_LITERAL);
+                       argument->constraints = parse_string_literals("asm argument");
+                       rem_anchor_token('(');
+                       expect('(');
+                       expression_t *expression = parse_expression();
+                       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
+                                * int -> float is not) */
+                               if (expression->kind == EXPR_UNARY_CAST) {
+                                       type_t      *const type = expression->base.type;
+                                       type_kind_t  const kind = type->kind;
+                                       if (kind == TYPE_ATOMIC || kind == TYPE_POINTER) {
+                                               unsigned flags;
+                                               unsigned size;
+                                               if (kind == TYPE_ATOMIC) {
+                                                       atomic_type_kind_t const akind = type->atomic.akind;
+                                                       flags = get_atomic_type_flags(akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
+                                                       size  = get_atomic_type_size(akind);
                                                } else {
-                                                       break;
+                                                       flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
+                                                       size  = get_type_size(type_void_ptr);
                                                }
 
-                                               if (value_flags != flags || value_size != size)
-                                                       break;
+                                               do {
+                                                       expression_t *const value      = expression->unary.value;
+                                                       type_t       *const value_type = value->base.type;
+                                                       type_kind_t   const value_kind = value_type->kind;
+
+                                                       unsigned value_flags;
+                                                       unsigned value_size;
+                                                       if (value_kind == TYPE_ATOMIC) {
+                                                               atomic_type_kind_t const value_akind = value_type->atomic.akind;
+                                                               value_flags = get_atomic_type_flags(value_akind) & ~ATOMIC_TYPE_FLAG_SIGNED;
+                                                               value_size  = get_atomic_type_size(value_akind);
+                                                       } else if (value_kind == TYPE_POINTER) {
+                                                               value_flags = ATOMIC_TYPE_FLAG_INTEGER | ATOMIC_TYPE_FLAG_ARITHMETIC;
+                                                               value_size  = get_type_size(type_void_ptr);
+                                                       } else {
+                                                               break;
+                                                       }
 
-                                               expression = value;
-                                       } while (expression->kind == EXPR_UNARY_CAST);
+                                                       if (value_flags != flags || value_size != size)
+                                                               break;
+
+                                                       expression = value;
+                                               } while (expression->kind == EXPR_UNARY_CAST);
+                                       }
                                }
-                       }
 
-                       if (!is_lvalue(expression)) {
-                               errorf(&expression->base.source_position,
-                                      "asm output argument is not an lvalue");
-                       }
+                               if (!is_lvalue(expression))
+                                       errorf(&expression->base.pos,
+                                              "asm output argument is not an lvalue");
 
-                       if (argument->constraints.begin[0] == '=')
-                               determine_lhs_ent(expression, NULL);
-                       else
+                               if (argument->constraints.begin[0] == '=')
+                                       determine_lhs_ent(expression, NULL);
+                               else
+                                       mark_vars_read(expression, NULL);
+                       } else {
                                mark_vars_read(expression, NULL);
-               } else {
-                       mark_vars_read(expression, NULL);
-               }
-               argument->expression = expression;
-               expect(')');
+                       }
+                       argument->expression = expression;
+                       rem_anchor_token(')');
+                       expect(')');
 
-               set_address_taken(expression, true);
+                       set_address_taken(expression, true);
 
-               *anchor = argument;
-               anchor  = &argument->next;
-
-               if (!next_if(','))
-                       break;
+                       *anchor = argument;
+                       anchor  = &argument->next;
+               } while (accept(','));
+               rem_anchor_token(',');
        }
-
-       return result;
 }
 
 /**
  * Parse a asm statement clobber specification.
  */
-static asm_clobber_t *parse_asm_clobbers(void)
+static void parse_asm_clobbers(asm_clobber_t **anchor)
 {
-       asm_clobber_t *result  = NULL;
-       asm_clobber_t **anchor = &result;
+       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);
 
-       while (token.kind == T_STRING_LITERAL) {
-               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(',');
+       }
+}
 
-               *anchor = clobber;
-               anchor  = &clobber->next;
+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;
 
-               if (!next_if(','))
-                       break;
+                               *anchor = asm_label;
+                               anchor  = &asm_label->next;
+                       }
+               } while (accept(','));
+               rem_anchor_token(',');
        }
-
-       return result;
 }
 
 /**
@@ -8789,22 +8824,30 @@ static statement_t *parse_asm_statement(void)
        add_anchor_token(':');
        add_anchor_token(T_STRING_LITERAL);
 
-       if (next_if(T_volatile))
+       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 (next_if(':'))
-               asm_statement->outputs = parse_asm_arguments(true);
-
-       if (next_if(':'))
-               asm_statement->inputs = parse_asm_arguments(false);
+       if (accept(':')) parse_asm_arguments(&asm_statement->outputs, true);
+       if (accept(':')) parse_asm_arguments(&asm_statement->inputs, false);
+       if (accept(':')) parse_asm_clobbers( &asm_statement->clobbers);
 
        rem_anchor_token(':');
-       if (next_if(':'))
-               asm_statement->clobbers = parse_asm_clobbers();
+       if (accept(':')) {
+               if (!asm_goto)
+                       warningf(WARN_OTHER, &statement->base.pos, "assembler statement with labels should be 'asm goto'");
+               parse_asm_labels(&asm_statement->labels);
+               if (asm_statement->labels)
+                       errorf(&statement->base.pos, "'asm goto' not supported");
+       } else {
+               if (asm_goto)
+                       warningf(WARN_OTHER, &statement->base.pos, "'asm goto' without labels");
+       }
 
        rem_anchor_token(')');
        expect(')');
@@ -8824,7 +8867,7 @@ static statement_t *parse_label_inner_statement(statement_t const *const label,
        statement_t *inner_stmt;
        switch (token.kind) {
                case '}':
-                       errorf(&label->base.source_position, "%s at end of compound statement", label_kind);
+                       errorf(&label->base.pos, "%s at end of compound statement", label_kind);
                        inner_stmt = create_error_statement();
                        break;
 
@@ -8844,7 +8887,7 @@ static statement_t *parse_label_inner_statement(statement_t const *const label,
                        /* ISO/IEC  9899:1999(E) §6.8:1/6.8.2:1  Declarations are no statements */
                        /* 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);
+                               errorf(&inner_stmt->base.pos, "declaration after %s", label_kind);
                        }
                        break;
        }
@@ -8856,8 +8899,8 @@ static statement_t *parse_label_inner_statement(statement_t const *const label,
  */
 static statement_t *parse_case_statement(void)
 {
-       statement_t       *const statement = allocate_statement_zero(STATEMENT_CASE_LABEL);
-       source_position_t *const pos       = &statement->base.source_position;
+       statement_t *const statement = allocate_statement_zero(STATEMENT_CASE_LABEL);
+       position_t  *const pos       = &statement->base.pos;
 
        eat(T_case);
        add_anchor_token(':');
@@ -8873,26 +8916,26 @@ static statement_t *parse_case_statement(void)
        type_t *type = expression_type;
        if (current_switch != NULL) {
                type_t *switch_type = current_switch->expression->base.type;
-               if (is_type_valid(switch_type)) {
+               if (is_type_valid(skip_typeref(switch_type))) {
                        expression = create_implicit_cast(expression, switch_type);
                }
        }
 
        statement->case_label.expression = expression;
        expression_classification_t const expr_class = is_constant_expression(expression);
-       if (expr_class != EXPR_CLASS_CONSTANT) {
+       if (expr_class < EXPR_CLASS_CONSTANT) {
                if (expr_class != EXPR_CLASS_ERROR) {
                        errorf(pos, "case label does not reduce to an integer constant");
                }
                statement->case_label.is_bad = true;
        } else {
-               long const val = fold_constant_to_int(expression);
+               ir_tarval *val = fold_constant_to_tarval(expression);
                statement->case_label.first_case = val;
                statement->case_label.last_case  = val;
        }
 
        if (GNU_MODE) {
-               if (next_if(T_DOTDOTDOT)) {
+               if (accept(T_DOTDOTDOT)) {
                        expression_t *end_range = parse_expression();
                        expression_type = expression->base.type;
                        skipped         = skip_typeref(expression_type);
@@ -8904,16 +8947,17 @@ static statement_t *parse_case_statement(void)
                        end_range = create_implicit_cast(end_range, type);
                        statement->case_label.end_range = end_range;
                        expression_classification_t const end_class = is_constant_expression(end_range);
-                       if (end_class != EXPR_CLASS_CONSTANT) {
+                       if (end_class < EXPR_CLASS_CONSTANT) {
                                if (end_class != EXPR_CLASS_ERROR) {
                                        errorf(pos, "case range does not reduce to an integer constant");
                                }
                                statement->case_label.is_bad = true;
                        } else {
-                               long const val = fold_constant_to_int(end_range);
+                               ir_tarval *val = fold_constant_to_tarval(end_range);
                                statement->case_label.last_case = val;
 
-                               if (val < statement->case_label.first_case) {
+                               if (tarval_cmp(val, statement->case_label.first_case)
+                                   == ir_relation_less) {
                                        statement->case_label.is_empty_range = true;
                                        warningf(WARN_OTHER, pos, "empty range specified");
                                }
@@ -8938,7 +8982,7 @@ static statement_t *parse_case_statement(void)
                                        continue;
 
                                errorf(pos, "duplicate case value (previously used %P)",
-                                      &l->base.source_position);
+                                      &l->base.pos);
                                break;
                        }
                }
@@ -8975,7 +9019,7 @@ static statement_t *parse_default_statement(void)
        if (current_switch != NULL) {
                const case_label_statement_t *def_label = current_switch->default_label;
                if (def_label != NULL) {
-                       errorf(&statement->base.source_position, "multiple default labels in one switch (previous declared %P)", &def_label->base.source_position);
+                       errorf(&statement->base.pos, "multiple default labels in one switch (previous declared %P)", &def_label->base.pos);
                } else {
                        current_switch->default_label = &statement->case_label;
 
@@ -8988,8 +9032,8 @@ static statement_t *parse_default_statement(void)
                        current_switch->last_case = &statement->case_label;
                }
        } else {
-               errorf(&statement->base.source_position,
-                       "'default' label not within a switch statement");
+               errorf(&statement->base.pos,
+                      "'default' label not within a switch statement");
        }
 
        statement->case_label.statement = parse_label_inner_statement(statement, "default label");
@@ -9012,12 +9056,13 @@ static statement_t *parse_label_statement(void)
        /* if statement is already set then the label is defined twice,
         * otherwise it was just mentioned in a goto/local label declaration so far
         */
-       source_position_t const* const pos = &statement->base.source_position;
+       position_t const* const pos = &statement->base.pos;
        if (label->statement != NULL) {
-               errorf(pos, "duplicate '%N' (declared %P)", (entity_t const*)label, &label->base.source_position);
+               errorf(pos, "duplicate '%N' (declared %P)", (entity_t const*)label, &label->base.pos);
        } else {
-               label->base.source_position = *pos;
-               label->statement            = statement;
+               label->base.pos  = *pos;
+               label->statement = statement;
+               label->n_users  += 1;
        }
 
        eat(':');
@@ -9042,7 +9087,7 @@ static statement_t *parse_inner_statement(void)
        /* ISO/IEC  9899:1999(E) §6.8:1/6.8.2:1  Declarations are no statements */
        /* ISO/IEC 14882:1998(E) §6:1/§6.7       Declarations are statements */
        if (stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
-               errorf(&stmt->base.source_position, "declaration as inner statement, use {}");
+               errorf(&stmt->base.pos, "declaration as inner statement, use {}");
        }
        return stmt;
 }
@@ -9090,7 +9135,7 @@ static statement_t *parse_if(void)
                        "suggest braces around empty body in an ‘if’ statement");
        }
 
-       if (next_if(T_else)) {
+       if (accept(T_else)) {
                statement->ifs.false_statement = parse_inner_statement();
 
                if (statement->ifs.false_statement->kind == STATEMENT_EMPTY) {
@@ -9099,7 +9144,7 @@ static statement_t *parse_if(void)
                }
        } else if (true_stmt->kind == STATEMENT_IF &&
                        true_stmt->ifs.false_statement != NULL) {
-               source_position_t const *const pos = &true_stmt->base.source_position;
+               position_t const *const pos = &true_stmt->base.pos;
                warningf(WARN_PARENTHESES, pos, "suggest explicit braces to avoid ambiguous 'else'");
        }
 
@@ -9117,37 +9162,40 @@ static void check_enum_cases(const switch_statement_t *statement)
 {
        if (!is_warn_on(WARN_SWITCH_ENUM))
                return;
-       const type_t *type = skip_typeref(statement->expression->base.type);
+       type_t *type = skip_typeref(statement->expression->base.type);
        if (! is_type_enum(type))
                return;
-       const enum_type_t *enumt = &type->enumt;
+       enum_type_t *enumt = &type->enumt;
 
        /* if we have a default, no warnings */
        if (statement->default_label != NULL)
                return;
 
+       determine_enum_values(enumt);
+
        /* FIXME: calculation of value should be done while parsing */
        /* TODO: quadratic algorithm here. Change to an n log n one */
-       long            last_value = -1;
-       const entity_t *entry      = enumt->enume->base.next;
+       const entity_t *entry = enumt->enume->base.next;
        for (; entry != NULL && entry->kind == ENTITY_ENUM_VALUE;
             entry = entry->base.next) {
-               const expression_t *expression = entry->enum_value.value;
-               long                value      = expression != NULL ? fold_constant_to_int(expression) : last_value + 1;
-               bool                found      = false;
-               for (const case_label_statement_t *l = statement->first_case; l != NULL; l = l->next) {
+               ir_tarval *value = entry->enum_value.tv;
+               bool       found = false;
+               for (const case_label_statement_t *l = statement->first_case; l != NULL;
+                    l = l->next) {
                        if (l->expression == NULL)
                                continue;
-                       if (l->first_case <= value && value <= l->last_case) {
+                       if (l->first_case == l->last_case && l->first_case != value)
+                               continue;
+                       if ((tarval_cmp(l->first_case, value) & ir_relation_less_equal)
+                        && (tarval_cmp(value, l->last_case) & ir_relation_less_equal)) {
                                found = true;
                                break;
                        }
                }
                if (!found) {
-                       source_position_t const *const pos = &statement->base.source_position;
+                       position_t const *const pos = &statement->base.pos;
                        warningf(WARN_SWITCH_ENUM, pos, "'%N' not handled in switch", entry);
                }
-               last_value = value;
        }
 }
 
@@ -9167,12 +9215,14 @@ static statement_t *parse_switch(void)
        type_t       *      type = skip_typeref(expr->base.type);
        if (is_type_integer(type)) {
                type = promote_integer(type);
-               if (get_akind_rank(get_akind(type)) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
-                       warningf(WARN_TRADITIONAL, &expr->base.source_position, "'%T' switch expression not converted to '%T' in ISO C", type, type_int);
+               if (get_akind_rank(get_arithmetic_akind(type)) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
+                       warningf(WARN_TRADITIONAL, &expr->base.pos,
+                                "'%T' switch expression not converted to '%T' in ISO C",
+                                type, type_int);
                }
        } else if (is_type_valid(type)) {
-               errorf(&expr->base.source_position,
-                      "switch quantity is not an integer, but '%T'", type);
+               errorf(&expr->base.pos, "switch quantity is not an integer, but '%T'",
+                      type);
                type = type_error_type;
        }
        statement->switchs.expression = create_implicit_cast(expr, type);
@@ -9183,7 +9233,7 @@ static statement_t *parse_switch(void)
        current_switch          = rem;
 
        if (statement->switchs.default_label == NULL) {
-               warningf(WARN_SWITCH_DEFAULT, &statement->base.source_position, "switch has no default case");
+               warningf(WARN_SWITCH_DEFAULT, &statement->base.pos, "switch has no default case");
        }
        check_enum_cases(&statement->switchs);
 
@@ -9208,20 +9258,20 @@ static statement_t *parse_loop_body(statement_t *const loop)
  */
 static statement_t *parse_while(void)
 {
-       statement_t *statement = allocate_statement_zero(STATEMENT_WHILE);
+       statement_t *statement = allocate_statement_zero(STATEMENT_FOR);
 
        eat(T_while);
 
        PUSH_PARENT(statement);
-       PUSH_SCOPE_STATEMENT(&statement->whiles.scope);
+       PUSH_SCOPE_STATEMENT(&statement->fors.scope);
 
        expression_t *const cond = parse_condition();
-       statement->whiles.condition = cond;
+       statement->fors.condition = cond;
        /* §6.8.5:2    The controlling expression of an iteration statement shall
         *             have scalar type. */
        semantic_condition(cond, "condition of 'while'-statement");
 
-       statement->whiles.body = parse_loop_body(statement);
+       statement->fors.body = parse_loop_body(statement);
 
        POP_SCOPE();
        POP_PARENT();
@@ -9274,7 +9324,7 @@ static statement_t *parse_for(void)
 
        PUSH_EXTENSION();
 
-       if (next_if(';')) {
+       if (accept(';')) {
        } else if (is_declaration_specifier(&token)) {
                parse_declaration(record_entity, DECL_FLAGS_NONE);
        } else {
@@ -9283,7 +9333,7 @@ static statement_t *parse_for(void)
                statement->fors.initialisation = init;
                mark_vars_read(init, ENT_ANY);
                if (!expression_has_effect(init)) {
-                       warningf(WARN_UNUSED_VALUE, &init->base.source_position, "initialisation of 'for'-statement has no effect");
+                       warningf(WARN_UNUSED_VALUE, &init->base.pos, "initialisation of 'for'-statement has no effect");
                }
                rem_anchor_token(';');
                expect(';');
@@ -9307,7 +9357,7 @@ static statement_t *parse_for(void)
                statement->fors.step = step;
                mark_vars_read(step, ENT_ANY);
                if (!expression_has_effect(step)) {
-                       warningf(WARN_UNUSED_VALUE, &step->base.source_position, "step of 'for'-statement has no effect");
+                       warningf(WARN_UNUSED_VALUE, &step->base.pos, "step of 'for'-statement has no effect");
                }
        }
        rem_anchor_token(')');
@@ -9339,10 +9389,9 @@ static statement_t *parse_goto(void)
 
                if (type != type_error_type) {
                        if (!is_type_pointer(type) && !is_type_integer(type)) {
-                               errorf(&expression->base.source_position,
-                                       "cannot convert to a pointer type");
+                               errorf(&expression->base.pos, "cannot convert to a pointer type");
                        } else if (type != type_void_ptr) {
-                               warningf(WARN_OTHER, &expression->base.source_position, "type of computed goto expression should be 'void*' not '%T'", type);
+                               warningf(WARN_OTHER, &expression->base.pos, "type of computed goto expression should be 'void*' not '%T'", type);
                        }
                        expression = create_implicit_cast(expression, type_void_ptr);
                }
@@ -9354,6 +9403,7 @@ static statement_t *parse_goto(void)
 
                label_t *const label = get_label("while parsing goto");
                if (label) {
+                       label->n_users        += 1;
                        label->used            = true;
                        statement->gotos.label = label;
 
@@ -9361,7 +9411,7 @@ static statement_t *parse_goto(void)
                        *goto_anchor = &statement->gotos;
                        goto_anchor  = &statement->gotos.next;
                } else {
-                       statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous, &builtin_source_position)->label;
+                       statement->gotos.label = &allocate_entity_zero(ENTITY_LABEL, NAMESPACE_LABEL, sym_anonymous, &builtin_position)->label;
                }
        }
 
@@ -9452,7 +9502,7 @@ static bool expression_is_local_variable(const expression_t *expression)
        return is_local_variable(entity);
 }
 
-static void err_or_warn(source_position_t const *const pos, char const *const msg)
+static void err_or_warn(position_t const *const pos, char const *const msg)
 {
        if (c_mode & _CXX || strict_mode) {
                errorf(pos, msg);
@@ -9479,7 +9529,7 @@ static statement_t *parse_return(void)
        assert(is_type_function(func_type));
        type_t *const return_type = skip_typeref(func_type->function.return_type);
 
-       source_position_t const *const pos = &statement->base.source_position;
+       position_t const *const pos = &statement->base.pos;
        if (return_value != NULL) {
                type_t *return_value_type = skip_typeref(return_value->base.type);
 
@@ -9539,7 +9589,7 @@ static statement_t *parse_declaration_statement(void)
 }
 
 /**
- * Parse an expression statement, ie. expr ';'.
+ * Parse an expression statement, i.e. expr ';'.
  */
 static statement_t *parse_expression_statement(void)
 {
@@ -9571,18 +9621,18 @@ static statement_t *parse_ms_try_statment(void)
 
        POP_PARENT();
 
-       if (next_if(T___except)) {
+       if (accept(T___except)) {
                expression_t *const expr = parse_condition();
                type_t       *      type = skip_typeref(expr->base.type);
                if (is_type_integer(type)) {
                        type = promote_integer(type);
                } else if (is_type_valid(type)) {
-                       errorf(&expr->base.source_position,
+                       errorf(&expr->base.pos,
                               "__expect expression is not an integer, but '%T'", type);
                        type = type_error_type;
                }
                statement->ms_try.except_expression = create_implicit_cast(expr, type);
-       } else if (!next_if(T__finally)) {
+       } else if (!accept(T__finally)) {
                parse_error_expected("while parsing __try statement", T___except, T___finally, NULL);
        }
        statement->ms_try.final_statement = parse_compound_statement(false);
@@ -9609,12 +9659,12 @@ static statement_t *parse_local_label_declaration(void)
        add_anchor_token(';');
        add_anchor_token(',');
        do {
-               source_position_t pos;
+               position_t pos;
                symbol_t *const symbol = expect_identifier("while parsing local label declaration", &pos);
                if (symbol) {
                        entity_t *entity = get_entity(symbol, NAMESPACE_LABEL);
                        if (entity != NULL && entity->base.parent_scope == current_scope) {
-                               source_position_t const *const ppos = &entity->base.source_position;
+                               position_t const *const ppos = &entity->base.pos;
                                errorf(&pos, "multiple definitions of '%N' (previous definition %P)", entity, ppos);
                        } else {
                                entity = allocate_entity_zero(ENTITY_LOCAL_LABEL, NAMESPACE_LABEL, symbol, &pos);
@@ -9627,7 +9677,7 @@ static statement_t *parse_local_label_declaration(void)
                                environment_push(entity);
                        }
                }
-       } while (next_if(','));
+       } while (accept(','));
        rem_anchor_token(',');
        rem_anchor_token(';');
        expect(';');
@@ -9780,7 +9830,8 @@ static statement_t *parse_statement(void)
        if (statement->kind == STATEMENT_EXPRESSION) {
                expression_t *expression = statement->expression.expression;
                if (!expression_has_effect(expression)) {
-                       warningf(WARN_UNUSED_VALUE, &expression->base.source_position, "statement has no effect");
+                       warningf(WARN_UNUSED_VALUE, &expression->base.pos,
+                                "statement has no effect");
                }
        }
 
@@ -9896,7 +9947,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
                if (sub_statement->kind != STATEMENT_DECLARATION) {
                        only_decls_so_far = false;
                } else if (!only_decls_so_far) {
-                       source_position_t const *const pos = &sub_statement->base.source_position;
+                       position_t const *const pos = &sub_statement->base.pos;
                        warningf(WARN_DECLARATION_AFTER_STATEMENT, pos, "ISO C90 forbids mixed declarations and code");
                }
 
@@ -9918,7 +9969,8 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
 
                        expression_t *expression = sub_statement->expression.expression;
                        if (!expression_has_effect(expression)) {
-                               warningf(WARN_UNUSED_VALUE, &expression->base.source_position, "statement has no effect");
+                               warningf(WARN_UNUSED_VALUE, &expression->base.pos,
+                                        "statement has no effect");
                        }
                }
        }
@@ -10041,13 +10093,13 @@ static void check_unused_globals(void)
                                continue;
 
                        why = WARN_UNUSED_FUNCTION;
-                       s   = entity->function.statement != NULL ? "defined" : "declared";
+                       s   = entity->function.body != NULL ? "defined" : "declared";
                } else {
                        why = WARN_UNUSED_VARIABLE;
                        s   = "defined";
                }
 
-               warningf(why, &declaration->base.source_position, "'%#N' %s but not used", entity, s);
+               warningf(why, &declaration->base.pos, "'%#N' %s but not used", entity, s);
        }
 }
 
@@ -10076,8 +10128,8 @@ static void parse_linkage_specification(void)
 {
        eat(T_extern);
 
-       source_position_t const pos     = *HERE;
-       char const       *const linkage = parse_string_literals(NULL).begin;
+       position_t  const pos     = *HERE;
+       char const *const linkage = parse_string_literals(NULL).begin;
 
        linkage_kind_t old_linkage = current_linkage;
        linkage_kind_t new_linkage;
@@ -10091,7 +10143,7 @@ static void parse_linkage_specification(void)
        }
        current_linkage = new_linkage;
 
-       if (next_if('{')) {
+       if (accept('{')) {
                parse_externals();
                expect('}');
        } else {
@@ -10261,7 +10313,7 @@ static void complete_incomplete_arrays(void)
                if (!is_type_incomplete(type))
                        continue;
 
-               source_position_t const *const pos = &decl->base.source_position;
+               position_t const *const pos = &decl->base.pos;
                warningf(WARN_OTHER, pos, "array '%#N' assumed to have one element", (entity_t const*)decl);
 
                type_t *const new_type = duplicate_type(type);
@@ -10277,31 +10329,31 @@ static void complete_incomplete_arrays(void)
 
 static void prepare_main_collect2(entity_t *const entity)
 {
-       PUSH_SCOPE(&entity->function.statement->compound.scope);
+       PUSH_SCOPE(&entity->function.body->compound.scope);
 
        // create call to __main
        symbol_t *symbol         = symbol_table_insert("__main");
        entity_t *subsubmain_ent
-               = create_implicit_function(symbol, &builtin_source_position);
+               = create_implicit_function(symbol, &builtin_position);
 
-       expression_t *ref         = allocate_expression_zero(EXPR_REFERENCE);
-       type_t       *ftype       = subsubmain_ent->declaration.type;
-       ref->base.source_position = builtin_source_position;
-       ref->base.type            = make_pointer_type(ftype, TYPE_QUALIFIER_NONE);
-       ref->reference.entity     = subsubmain_ent;
+       expression_t *ref     = allocate_expression_zero(EXPR_REFERENCE);
+       type_t       *ftype   = subsubmain_ent->declaration.type;
+       ref->base.pos         = builtin_position;
+       ref->base.type        = make_pointer_type(ftype, TYPE_QUALIFIER_NONE);
+       ref->reference.entity = subsubmain_ent;
 
-       expression_t *call = allocate_expression_zero(EXPR_CALL);
-       call->base.source_position = builtin_source_position;
-       call->base.type            = type_void;
-       call->call.function        = ref;
+       expression_t *call  = allocate_expression_zero(EXPR_CALL);
+       call->base.pos      = builtin_position;
+       call->base.type     = type_void;
+       call->call.function = ref;
 
        statement_t *expr_statement = allocate_statement_zero(STATEMENT_EXPRESSION);
-       expr_statement->base.source_position  = builtin_source_position;
+       expr_statement->base.pos              = builtin_position;
        expr_statement->expression.expression = call;
 
-       statement_t *statement = entity->function.statement;
-       assert(statement->kind == STATEMENT_COMPOUND);
-       compound_statement_t *compounds = &statement->compound;
+       statement_t *const body = entity->function.body;
+       assert(body->kind == STATEMENT_COMPOUND);
+       compound_statement_t *compounds = &body->compound;
 
        expr_statement->base.next = compounds->statements;
        compounds->statements     = expr_statement;