Report an error on empty character constants, i.e. ''.
[cparser] / parser.c
index 7becd99..500c1ad 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -130,7 +130,7 @@ static unsigned char token_anchor_set[T_LAST_TOKEN];
 static statement_t *parse_compound_statement(bool inside_expression_statement);
 static statement_t *parse_statement(void);
 
-static expression_t *parse_sub_expression(precedence_t);
+static expression_t *parse_subexpression(precedence_t);
 static expression_t *parse_expression(void);
 static type_t       *parse_typename(void);
 static void          parse_externals(void);
@@ -658,7 +658,7 @@ static void type_error_incompatible(const char *msg,
 /**
  * Expect the current token is the expected token.
  * If not, generate an error, eat the current statement,
- * and goto the end_error label.
+ * and goto the error_label label.
  */
 #define expect(expected, error_label)                     \
        do {                                                  \
@@ -702,6 +702,7 @@ static void scope_pop(scope_t *old_scope)
 static entity_t *get_entity(const symbol_t *const symbol,
                             namespace_tag_t namespc)
 {
+       assert(namespc != NAMESPACE_INVALID);
        entity_t *entity = symbol->entity;
        for (; entity != NULL; entity = entity->base.symbol_next) {
                if (entity->base.namespc == namespc)
@@ -823,7 +824,7 @@ static void stack_pop_to(stack_entry_t **stack_ptr, size_t new_top)
                }
        }
 
-       ARR_SHRINKLEN(*stack_ptr, (int) new_top);
+       ARR_SHRINKLEN(*stack_ptr, new_top);
 }
 
 /**
@@ -916,10 +917,13 @@ static bool is_null_pointer_constant(const expression_t *expression)
        }
 
        type_t *const type = skip_typeref(expression->base.type);
-       return
-               is_type_integer(type)              &&
-               is_constant_expression(expression) &&
-               !fold_constant_to_bool(expression);
+       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;
+       }
 }
 
 /**
@@ -1055,11 +1059,10 @@ static assign_error_t semantic_assign(type_t *orig_type_left,
                        return ASSIGN_WARNING_POINTER_FROM_INT;
                }
        } else if ((is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) ||
-           (is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
-               && is_type_pointer(type_right))) {
+                       (is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
+                               && is_type_pointer(type_right))) {
                return ASSIGN_SUCCESS;
-       } else if ((is_type_compound(type_left)  && is_type_compound(type_right))
-                       || (is_type_builtin(type_left) && is_type_builtin(type_right))) {
+       } else if (is_type_compound(type_left) && is_type_compound(type_right)) {
                type_t *const unqual_type_left  = get_unqualified_type(type_left);
                type_t *const unqual_type_right = get_unqualified_type(type_right);
                if (types_compatible(unqual_type_left, unqual_type_right)) {
@@ -1077,9 +1080,9 @@ static assign_error_t semantic_assign(type_t *orig_type_left,
 
 static expression_t *parse_constant_expression(void)
 {
-       expression_t *result = parse_sub_expression(PREC_CONDITIONAL);
+       expression_t *result = parse_subexpression(PREC_CONDITIONAL);
 
-       if (!is_constant_expression(result)) {
+       if (is_constant_expression(result) == EXPR_CLASS_VARIABLE) {
                errorf(&result->base.source_position,
                       "expression '%E' is not constant", result);
        }
@@ -1089,7 +1092,7 @@ static expression_t *parse_constant_expression(void)
 
 static expression_t *parse_assignment_expression(void)
 {
-       return parse_sub_expression(PREC_ASSIGNMENT);
+       return parse_subexpression(PREC_ASSIGNMENT);
 }
 
 static void warn_string_concat(const source_position_t *pos)
@@ -1261,7 +1264,7 @@ static attribute_t *parse_attribute_gnu_single(void)
        symbol_t *symbol = get_symbol_from_token();
        if (symbol == NULL) {
                parse_error_expected("while parsing attribute((", T_IDENTIFIER, NULL);
-               goto end_error;
+               return NULL;
        }
 
        const char *name = symbol->string;
@@ -1290,9 +1293,6 @@ static attribute_t *parse_attribute_gnu_single(void)
                attribute->a.arguments = parse_attribute_arguments();
 
        return attribute;
-
-end_error:
-       return NULL;
 }
 
 static attribute_t *parse_attribute_gnu(void)
@@ -1331,6 +1331,8 @@ static attribute_t *parse_attributes(attribute_t *first)
                switch (token.type) {
                case T___attribute__:
                        attribute = parse_attribute_gnu();
+                       if (attribute == NULL)
+                               continue;
                        break;
 
                case T_asm:
@@ -1735,8 +1737,9 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
  */
 static bool is_initializer_constant(const expression_t *expression)
 {
-       return is_constant_expression(expression)
-               || is_address_constant(expression);
+       return
+               is_constant_expression(expression) != EXPR_CLASS_VARIABLE ||
+               is_address_constant(expression)    != EXPR_CLASS_VARIABLE;
 }
 
 /**
@@ -1967,7 +1970,7 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                                        type_t *real_type = skip_typeref(iter->declaration.type);
                                        if (real_type->kind == TYPE_BITFIELD) {
                                                errorf(&designator->source_position,
-                                                      "offsetof designator '%Y' may not specify bitfield",
+                                                      "offsetof designator '%Y' must not specify bitfield",
                                                       symbol);
                                                goto failed;
                                        }
@@ -1999,8 +2002,8 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                                        long array_size = type->array.size;
                                        if (index >= array_size) {
                                                errorf(&designator->source_position,
-                                                      "designator [%E] (%d) exceeds array size %d",
-                                                      array_index, index, array_size);
+                                                      "designator [%E] (%d) exceeds array size %d",
+                                                      array_index, index, array_size);
                                        }
                                }
                        }
@@ -2413,8 +2416,8 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
 {
        eat(is_struct ? T_struct : T_union);
 
-       symbol_t    *symbol   = NULL;
-       compound_t  *compound = NULL;
+       symbol_t    *symbol     = NULL;
+       entity_t    *entity     = NULL;
        attribute_t *attributes = NULL;
 
        if (token.type == T___attribute__) {
@@ -2427,21 +2430,20 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
                symbol = token.symbol;
                next_token();
 
-               entity_t *entity = get_tag(symbol, kind);
+               entity = get_tag(symbol, kind);
                if (entity != NULL) {
-                       compound = &entity->compound;
-                       if (compound->base.parent_scope != current_scope &&
+                       if (entity->base.parent_scope != current_scope &&
                            (token.type == '{' || token.type == ';')) {
                                /* we're in an inner scope and have a definition. Shadow
                                 * existing definition in outer scope */
-                               compound = NULL;
-                       } else if (compound->complete && token.type == '{') {
+                               entity = NULL;
+                       } else if (entity->compound.complete && token.type == '{') {
                                assert(symbol != NULL);
                                errorf(HERE, "multiple definitions of '%s %Y' (previous definition %P)",
                                       is_struct ? "struct" : "union", symbol,
-                                      &compound->base.source_position);
+                                      &entity->base.source_position);
                                /* clear members in the hope to avoid further errors */
-                               compound->members.entities = NULL;
+                               entity->compound.members.entities = NULL;
                        }
                }
        } else if (token.type != '{') {
@@ -2456,15 +2458,14 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
                return NULL;
        }
 
-       if (compound == NULL) {
-               entity_t *entity = allocate_entity_zero(kind);
-               compound         = &entity->compound;
+       if (entity == NULL) {
+               entity = allocate_entity_zero(kind);
 
-               compound->alignment            = 1;
-               compound->base.namespc         = NAMESPACE_TAG;
-               compound->base.source_position = token.source_position;
-               compound->base.symbol          = symbol;
-               compound->base.parent_scope    = current_scope;
+               entity->compound.alignment   = 1;
+               entity->base.namespc         = NAMESPACE_TAG;
+               entity->base.source_position = token.source_position;
+               entity->base.symbol          = symbol;
+               entity->base.parent_scope    = current_scope;
                if (symbol != NULL) {
                        environment_push(entity);
                }
@@ -2472,20 +2473,20 @@ static compound_t *parse_compound_type_specifier(bool is_struct)
        }
 
        if (token.type == '{') {
-               parse_compound_type_entries(compound);
+               parse_compound_type_entries(&entity->compound);
 
                /* ISO/IEC 14882:1998(E) §7.1.3:5 */
                if (symbol == NULL) {
                        assert(anonymous_entity == NULL);
-                       anonymous_entity = (entity_t*)compound;
+                       anonymous_entity = entity;
                }
        }
 
        if (attributes != NULL) {
-               handle_entity_attributes(attributes, (entity_t*) compound);
+               handle_entity_attributes(attributes, entity);
        }
 
-       return compound;
+       return &entity->compound;
 }
 
 static void parse_enum_entries(type_t *const enum_type)
@@ -2509,6 +2510,7 @@ static void parse_enum_entries(type_t *const enum_type)
 
                entity_t *entity             = allocate_entity_zero(ENTITY_ENUM_VALUE);
                entity->enum_value.enum_type = enum_type;
+               entity->base.namespc         = NAMESPACE_NORMAL;
                entity->base.symbol          = token.symbol;
                entity->base.source_position = token.source_position;
                next_token();
@@ -2634,21 +2636,14 @@ static type_t *parse_typeof(void)
        switch (token.type) {
        case T_IDENTIFIER:
                if (is_typedef_symbol(token.symbol)) {
+       TYPENAME_START
                        type = parse_typename();
                } else {
+       default:
                        expression = parse_expression();
                        type       = revert_automatic_type_conversion(expression);
                }
                break;
-
-       TYPENAME_START
-               type = parse_typename();
-               break;
-
-       default:
-               expression = parse_expression();
-               type       = expression->base.type;
-               break;
        }
        in_type_prop     = old_type_prop;
        in_gcc_extension = old_gcc_extension;
@@ -2687,15 +2682,6 @@ typedef enum specifiers_t {
        SPECIFIER_IMAGINARY = 1 << 18,
 } specifiers_t;
 
-static type_t *create_builtin_type(symbol_t *const symbol,
-                                   type_t *const real_type)
-{
-       type_t *type            = allocate_type_zero(TYPE_BUILTIN);
-       type->builtin.symbol    = symbol;
-       type->builtin.real_type = real_type;
-       return identify_new_type(type);
-}
-
 static type_t *get_typedef_type(symbol_t *symbol)
 {
        entity_t *entity = get_entity(symbol, NAMESPACE_NORMAL);
@@ -2830,6 +2816,7 @@ end_error:
 static entity_t *create_error_entity(symbol_t *symbol, entity_kind_tag_t kind)
 {
        entity_t *entity             = allocate_entity_zero(kind);
+       entity->base.namespc         = NAMESPACE_NORMAL;
        entity->base.source_position = *HERE;
        entity->base.symbol          = symbol;
        if (is_declaration(entity)) {
@@ -2895,10 +2882,10 @@ check_thread_storage_class:
                                                break;
 
                                                char const* wrong;
-                                       case STORAGE_CLASS_AUTO:     wrong = "auto";     goto wrong_thread_stoarge_class;
-                                       case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_stoarge_class;
-                                       case STORAGE_CLASS_TYPEDEF:  wrong = "typedef";  goto wrong_thread_stoarge_class;
-wrong_thread_stoarge_class:
+                                       case STORAGE_CLASS_AUTO:     wrong = "auto";     goto wrong_thread_storage_class;
+                                       case STORAGE_CLASS_REGISTER: wrong = "register"; goto wrong_thread_storage_class;
+                                       case STORAGE_CLASS_TYPEDEF:  wrong = "typedef";  goto wrong_thread_storage_class;
+wrong_thread_storage_class:
                                                errorf(HERE, "'__thread' used with '%s'", wrong);
                                                break;
                                }
@@ -3459,6 +3446,7 @@ typedef union construct_type_t construct_type_t;
 
 typedef struct construct_type_base_t {
        construct_type_kind_t  kind;
+       source_position_t      pos;
        construct_type_t      *next;
 } construct_type_base_t;
 
@@ -3494,54 +3482,63 @@ union construct_type_t {
        parsed_array_t            array;
 };
 
+static construct_type_t *allocate_declarator_zero(construct_type_kind_t const kind, size_t const size)
+{
+       construct_type_t *const cons = obstack_alloc(&temp_obst, size);
+       memset(cons, 0, size);
+       cons->kind     = kind;
+       cons->base.pos = *HERE;
+       return cons;
+}
+
+/* §6.7.5.1 */
 static construct_type_t *parse_pointer_declarator(void)
 {
+       construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_POINTER, sizeof(parsed_pointer_t));
        eat('*');
+       cons->pointer.type_qualifiers = parse_type_qualifiers();
+       //cons->pointer.base_variable   = base_variable;
 
-       parsed_pointer_t *pointer = obstack_alloc(&temp_obst, sizeof(pointer[0]));
-       memset(pointer, 0, sizeof(pointer[0]));
-       pointer->base.kind       = CONSTRUCT_POINTER;
-       pointer->type_qualifiers = parse_type_qualifiers();
-       //pointer->base_variable       = base_variable;
-
-       return (construct_type_t*) pointer;
+       return cons;
 }
 
+/* ISO/IEC 14882:1998(E) §8.3.2 */
 static construct_type_t *parse_reference_declarator(void)
 {
-       eat('&');
+       if (!(c_mode & _CXX))
+               errorf(HERE, "references are only available for C++");
 
-       construct_type_t   *cons      = obstack_alloc(&temp_obst, sizeof(cons->reference));
-       parsed_reference_t *reference = &cons->reference;
-       memset(reference, 0, sizeof(*reference));
-       cons->kind = CONSTRUCT_REFERENCE;
+       construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_REFERENCE, sizeof(parsed_reference_t));
+       eat('&');
 
        return cons;
 }
 
+/* §6.7.5.2 */
 static construct_type_t *parse_array_declarator(void)
 {
+       construct_type_t *const cons  = allocate_declarator_zero(CONSTRUCT_ARRAY, sizeof(parsed_array_t));
+       parsed_array_t   *const array = &cons->array;
+
        eat('[');
        add_anchor_token(']');
 
-       construct_type_t *cons  = obstack_alloc(&temp_obst, sizeof(cons->array));
-       parsed_array_t   *array = &cons->array;
-       memset(array, 0, sizeof(*array));
-       cons->kind = CONSTRUCT_ARRAY;
-
-       if (next_if(T_static))
-               array->is_static = true;
+       bool is_static = next_if(T_static);
 
        type_qualifiers_t type_qualifiers = parse_type_qualifiers();
-       if (type_qualifiers != 0 && next_if(T_static))
-                       array->is_static = true;
+
+       if (!is_static)
+               is_static = next_if(T_static);
+
        array->type_qualifiers = type_qualifiers;
+       array->is_static       = is_static;
 
+       expression_t *size = NULL;
        if (token.type == '*' && look_ahead(1)->type == ']') {
                array->is_variable = true;
                next_token();
        } else if (token.type != ']') {
-               expression_t *const size = parse_assignment_expression();
+               size = parse_assignment_expression();
 
                /* §6.7.5.2:1  Array size must have integer type */
                type_t *const orig_type = size->base.type;
@@ -3556,6 +3553,9 @@ static construct_type_t *parse_array_declarator(void)
                mark_vars_read(size, NULL);
        }
 
+       if (is_static && size == NULL)
+               errorf(HERE, "static array parameters require a size");
+
        rem_anchor_token(']');
        expect(']', end_error);
 
@@ -3563,8 +3563,11 @@ end_error:
        return cons;
 }
 
+/* §6.7.5.3 */
 static construct_type_t *parse_function_declarator(scope_t *scope)
 {
+       construct_type_t *const cons = allocate_declarator_zero(CONSTRUCT_FUNCTION, sizeof(construct_function_type_t));
+
        type_t          *type  = allocate_type_zero(TYPE_FUNCTION);
        function_type_t *ftype = &type->function;
 
@@ -3573,11 +3576,7 @@ static construct_type_t *parse_function_declarator(scope_t *scope)
 
        parse_parameters(ftype, scope);
 
-       construct_type_t          *cons     = obstack_alloc(&temp_obst, sizeof(cons->function));
-       construct_function_type_t *function = &cons->function;
-       memset(function, 0, sizeof(*function));
-       cons->kind              = CONSTRUCT_FUNCTION;
-       function->function_type = type;
+       cons->function.function_type = type;
 
        return cons;
 }
@@ -3592,6 +3591,7 @@ typedef struct parse_declarator_env_t {
        attribute_t       *attributes;
 } parse_declarator_env_t;
 
+/* §6.7.5 */
 static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env)
 {
        /* construct a single linked list of construct_type_t's which describe
@@ -3606,8 +3606,6 @@ static construct_type_t *parse_inner_declarator(parse_declarator_env_t *env)
                //variable_t       *based = NULL; /* MS __based extension */
                switch (token.type) {
                        case '&':
-                               if (!(c_mode & _CXX))
-                                       errorf(HERE, "references are only available for C++");
                                type = parse_reference_declarator();
                                break;
 
@@ -3644,26 +3642,49 @@ ptr_operator_end: ;
                }
                next_token();
                break;
-       case '(':
-               /* §6.7.6:2 footnote 126:  Empty parentheses in a type name are
-                * interpreted as ``function with no parameter specification'', rather
-                * than redundant parentheses around the omitted identifier. */
-               if (look_ahead(1)->type != ')') {
-                       next_token();
-                       add_anchor_token(')');
-                       inner_types = parse_inner_declarator(env);
-                       if (inner_types != NULL) {
-                               /* All later declarators only modify the return type */
-                               env->must_be_abstract = true;
-                       }
-                       rem_anchor_token(')');
-                       expect(')', end_error);
+
+       case '(': {
+               /* Parenthesized declarator or function declarator? */
+               token_t const *const la1 = look_ahead(1);
+               switch (la1->type) {
+                       case T_IDENTIFIER:
+                               if (is_typedef_symbol(la1->symbol)) {
+                       case ')':
+                                       /* §6.7.6:2 footnote 126:  Empty parentheses in a type name are
+                                        * interpreted as ``function with no parameter specification'', rather
+                                        * than redundant parentheses around the omitted identifier. */
+                       default:
+                                       /* Function declarator. */
+                                       if (!env->may_be_abstract) {
+                                               errorf(HERE, "function declarator must have a name");
+                                               goto error_out;
+                                       }
+                               } else {
+                       case '(':
+                       case '*':
+                       case '[':
+                       case T___attribute__: /* FIXME __attribute__ might also introduce a parameter of a function declarator. */
+                                       /* Paranthesized declarator. */
+                                       next_token();
+                                       add_anchor_token(')');
+                                       inner_types = parse_inner_declarator(env);
+                                       if (inner_types != NULL) {
+                                               /* All later declarators only modify the return type */
+                                               env->must_be_abstract = true;
+                                       }
+                                       rem_anchor_token(')');
+                                       expect(')', end_error);
+                               }
+                               break;
                }
                break;
+       }
+
        default:
                if (env->may_be_abstract)
                        break;
                parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL);
+error_out:
                eat_until_anchor();
                return NULL;
        }
@@ -3711,6 +3732,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
 {
        construct_type_t *iter = construct_list;
        for (; iter != NULL; iter = iter->base.next) {
+               source_position_t const* const pos = &iter->base.pos;
                switch (iter->kind) {
                case CONSTRUCT_INVALID:
                        break;
@@ -3723,13 +3745,12 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                        type_t *skipped_return_type = skip_typeref(type);
                        /* §6.7.5.3:1 */
                        if (is_type_function(skipped_return_type)) {
-                               errorf(HERE, "function returning function is not allowed");
+                               errorf(pos, "function returning function is not allowed");
                        } else if (is_type_array(skipped_return_type)) {
-                               errorf(HERE, "function returning array is not allowed");
+                               errorf(pos, "function returning array is not allowed");
                        } else {
                                if (skipped_return_type->base.qualifiers != 0 && warning.other) {
-                                       warningf(HERE,
-                                               "type qualifiers in return type of function type are meaningless");
+                                       warningf(pos, "type qualifiers in return type of function type are meaningless");
                                }
                        }
 
@@ -3741,7 +3762,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
 
                case CONSTRUCT_POINTER: {
                        if (is_type_reference(skip_typeref(type)))
-                               errorf(HERE, "cannot declare a pointer to reference");
+                               errorf(pos, "cannot declare a pointer to reference");
 
                        parsed_pointer_t *pointer = &iter->pointer;
                        type = make_based_pointer_type(type, pointer->type_qualifiers, pointer->base_variable);
@@ -3750,14 +3771,14 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
 
                case CONSTRUCT_REFERENCE:
                        if (is_type_reference(skip_typeref(type)))
-                               errorf(HERE, "cannot declare a reference to reference");
+                               errorf(pos, "cannot declare a reference to reference");
 
                        type = make_reference_type(type);
                        continue;
 
                case CONSTRUCT_ARRAY: {
                        if (is_type_reference(skip_typeref(type)))
-                               errorf(HERE, "cannot declare an array of references");
+                               errorf(pos, "cannot declare an array of references");
 
                        parsed_array_t *array      = &iter->array;
                        type_t         *array_type = allocate_type_zero(TYPE_ARRAY);
@@ -3775,39 +3796,46 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                        array_type->array.size_expression = size_expression;
 
                        if (size_expression != NULL) {
-                               if (is_constant_expression(size_expression)) {
-                                       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) {
-                                               if (size < 0 || !GNU_MODE) {
-                                                       errorf(&size_expression->base.source_position,
-                                                                       "size of array must be greater than zero");
-                                               } else if (warning.other) {
-                                                       warningf(&size_expression->base.source_position,
-                                                                       "zero length arrays are a GCC extension");
+                               switch (is_constant_expression(size_expression)) {
+                                       case EXPR_CLASS_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) {
+                                                       if (size < 0 || !GNU_MODE) {
+                                                               errorf(&size_expression->base.source_position,
+                                                                               "size of array must be greater than zero");
+                                                       } else if (warning.other) {
+                                                               warningf(&size_expression->base.source_position,
+                                                                               "zero length arrays are a GCC extension");
+                                                       }
                                                }
+                                               break;
                                        }
-                               } else {
-                                       array_type->array.is_vla = true;
+
+                                       case EXPR_CLASS_VARIABLE:
+                                               array_type->array.is_vla = true;
+                                               break;
+
+                                       case EXPR_CLASS_ERROR:
+                                               break;
                                }
                        }
 
                        type_t *skipped_type = skip_typeref(type);
                        /* §6.7.5.2:1 */
                        if (is_type_incomplete(skipped_type)) {
-                               errorf(HERE, "array of incomplete type '%T' is not allowed", type);
+                               errorf(pos, "array of incomplete type '%T' is not allowed", type);
                        } else if (is_type_function(skipped_type)) {
-                               errorf(HERE, "array of functions is not allowed");
+                               errorf(pos, "array of functions is not allowed");
                        }
                        type = identify_new_type(array_type);
                        continue;
                }
                }
-               internal_errorf(HERE, "invalid type construction found");
+               internal_errorf(pos, "invalid type construction found");
        }
 
        return type;
@@ -3875,6 +3903,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);
+               entity->base.namespc         = NAMESPACE_NORMAL;
                entity->base.symbol          = env.symbol;
                entity->base.source_position = env.source_position;
                entity->typedefe.type        = orig_type;
@@ -3927,10 +3956,10 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                bool in_function_scope = current_function != NULL;
 
                                if (specifiers->thread_local || (
-                                     specifiers->storage_class != STORAGE_CLASS_EXTERN &&
-                                         specifiers->storage_class != STORAGE_CLASS_NONE   &&
-                                         (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC)
-                                  )) {
+                                                       specifiers->storage_class != STORAGE_CLASS_EXTERN &&
+                                                       specifiers->storage_class != STORAGE_CLASS_NONE   &&
+                                                       (in_function_scope || specifiers->storage_class != STORAGE_CLASS_STATIC)
+                                               )) {
                                        errorf(&env.source_position,
                                                        "invalid storage class for function '%Y'", env.symbol);
                                }
@@ -3981,7 +4010,7 @@ static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                storage_class_t storage_class = specifiers->storage_class;
                entity->declaration.declared_storage_class = storage_class;
 
-               if (storage_class == STORAGE_CLASS_NONE && current_function != NULL)
+               if (storage_class == STORAGE_CLASS_NONE && current_function != NULL)
                        storage_class = STORAGE_CLASS_AUTO;
                entity->declaration.storage_class = storage_class;
        }
@@ -4043,23 +4072,30 @@ static void check_main(const entity_t *entity)
        }
        const function_parameter_t *parm = func_type->parameters;
        if (parm != NULL) {
-               type_t *const first_type = parm->type;
-               if (!types_compatible(skip_typeref(first_type), type_int)) {
+               type_t *const first_type        = skip_typeref(parm->type);
+               type_t *const first_type_unqual = get_unqualified_type(first_type);
+               if (!types_compatible(first_type_unqual, type_int)) {
                        warningf(pos,
                                 "first argument of 'main' should be 'int', but is '%T'",
-                                first_type);
+                                parm->type);
                }
                parm = parm->next;
                if (parm != NULL) {
-                       type_t *const second_type = parm->type;
-                       if (!types_compatible(skip_typeref(second_type), type_char_ptr_ptr)) {
-                               warningf(pos, "second argument of 'main' should be 'char**', but is '%T'", second_type);
+                       type_t *const second_type = skip_typeref(parm->type);
+                       type_t *const second_type_unqual
+                               = get_unqualified_type(second_type);
+                       if (!types_compatible(second_type_unqual, type_char_ptr_ptr)) {
+                               warningf(pos, "second argument of 'main' should be 'char**', but is '%T'",
+                                        parm->type);
                        }
                        parm = parm->next;
                        if (parm != NULL) {
-                               type_t *const third_type = parm->type;
-                               if (!types_compatible(skip_typeref(third_type), type_char_ptr_ptr)) {
-                                       warningf(pos, "third argument of 'main' should be 'char**', but is '%T'", third_type);
+                               type_t *const third_type = skip_typeref(parm->type);
+                               type_t *const third_type_unqual
+                                       = get_unqualified_type(third_type);
+                               if (!types_compatible(third_type_unqual, type_char_ptr_ptr)) {
+                                       warningf(pos, "third argument of 'main' should be 'char**', but is '%T'",
+                                                parm->type);
                                }
                                parm = parm->next;
                                if (parm != NULL)
@@ -4088,14 +4124,14 @@ static void error_redefined_as_different_kind(const source_position_t *pos,
               get_entity_kind_name(new_kind), &old->base.source_position);
 }
 
-static bool is_error_entity(entity_t *const ent)
+static bool is_entity_valid(entity_t *const ent)
 {
        if (is_declaration(ent)) {
                return is_type_valid(skip_typeref(ent->declaration.type));
        } else if (ent->kind == ENTITY_TYPEDEF) {
                return is_type_valid(skip_typeref(ent->typedefe.type));
        }
-       return false;
+       return true;
 }
 
 static bool contains_attribute(const attribute_t *list, const attribute_t *attr)
@@ -4197,7 +4233,7 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
 
                if (previous_entity->base.parent_scope == current_scope) {
                        if (previous_entity->kind != entity->kind) {
-                               if (!is_error_entity(previous_entity) && !is_error_entity(entity)) {
+                               if (is_entity_valid(previous_entity) && is_entity_valid(entity)) {
                                        error_redefined_as_different_kind(pos, previous_entity,
                                                        entity->kind);
                                }
@@ -4245,7 +4281,7 @@ entity_t *record_entity(entity_t *entity, const bool is_definition)
                        } else {
                                unsigned old_storage_class = prev_decl->storage_class;
 
-                               if (warning.redundant_decls               &&
+                               if (warning.redundant_decls               &&
                                                is_definition                     &&
                                                !prev_decl->used                  &&
                                                !(prev_decl->modifiers & DM_USED) &&
@@ -4413,19 +4449,26 @@ static bool is_declaration_specifier(const token_t *token,
 
 static void parse_init_declarator_rest(entity_t *entity)
 {
-       assert(is_declaration(entity));
-       declaration_t *const declaration = &entity->declaration;
+       type_t *orig_type = type_error_type;
 
+       if (entity->base.kind == ENTITY_TYPEDEF) {
+               errorf(&entity->base.source_position,
+                      "typedef '%Y' is initialized (use __typeof__ instead)",
+                      entity->base.symbol);
+       } else {
+               assert(is_declaration(entity));
+               orig_type = entity->declaration.type;
+       }
        eat('=');
 
-       type_t *orig_type = declaration->type;
-       type_t *type      = skip_typeref(orig_type);
+       type_t *type = skip_typeref(orig_type);
 
        if (entity->kind == ENTITY_VARIABLE
                        && entity->variable.initializer != NULL) {
                parser_error_multiple_definition(entity, HERE);
        }
 
+       declaration_t *const declaration = &entity->declaration;
        bool must_be_constant = false;
        if (declaration->storage_class == STORAGE_CLASS_STATIC ||
            entity->base.parent_scope  == file_scope) {
@@ -4879,8 +4922,8 @@ static void check_declarations(void)
 static int determine_truth(expression_t const* const cond)
 {
        return
-               !is_constant_expression(cond) ? 0 :
-               fold_constant_to_bool(cond)   ? 1 :
+               is_constant_expression(cond) != EXPR_CLASS_CONSTANT ? 0 :
+               fold_constant_to_bool(cond)                         ? 1 :
                -1;
 }
 
@@ -5090,7 +5133,7 @@ static void check_reachable(statement_t *const stmt)
                        if (!expression_returns(expr))
                                return;
 
-                       if (is_constant_expression(expr)) {
+                       if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) {
                                long                    const val      = fold_constant_to_int(expr);
                                case_label_statement_t *      defaults = NULL;
                                for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
@@ -5579,7 +5622,7 @@ static void parse_external_declaration(void)
        assert(entity->kind == ENTITY_FUNCTION);
        assert(ndeclaration->kind == ENTITY_FUNCTION);
 
-       function_t *function = &entity->function;
+       function_t *const function = &entity->function;
        if (ndeclaration != entity) {
                function->parameters = ndeclaration->function.parameters;
        }
@@ -5614,7 +5657,7 @@ static void parse_external_declaration(void)
                function_t *old_current_function = current_function;
                entity_t   *old_current_entity   = current_entity;
                current_function                 = function;
-               current_entity                   = (entity_t*) function;
+               current_entity                   = entity;
                current_parent                   = NULL;
 
                goto_first   = NULL;
@@ -5646,7 +5689,7 @@ static void parse_external_declaration(void)
 
                assert(current_parent   == NULL);
                assert(current_function == function);
-               assert(current_entity   == (entity_t*) function);
+               assert(current_entity   == entity);
                current_entity   = old_current_entity;
                current_function = old_current_function;
                label_pop_to(label_stack_top);
@@ -5676,7 +5719,7 @@ static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
                bit_size = get_type_size(base_type) * 8;
        }
 
-       if (is_constant_expression(size)) {
+       if (is_constant_expression(size) == EXPR_CLASS_CONSTANT) {
                long v = fold_constant_to_int(size);
                const symbol_t *user_symbol = symbol == NULL ? sym_anonymous : symbol;
 
@@ -5941,7 +5984,7 @@ static type_t *parse_typename(void)
                /* TODO: improve error message, user does probably not know what a
                 * storage class is...
                 */
-               errorf(HERE, "typename may not have a storage class");
+               errorf(HERE, "typename must not have a storage class");
        }
 
        type_t *result = parse_abstract_declarator(specifiers.type);
@@ -6119,14 +6162,17 @@ static expression_t *parse_number_literal(void)
        case T_INTEGER:
                kind = EXPR_LITERAL_INTEGER;
                check_integer_suffix();
+               type = type_int;
                break;
        case T_INTEGER_OCTAL:
                kind = EXPR_LITERAL_INTEGER_OCTAL;
                check_integer_suffix();
+               type = type_int;
                break;
        case T_INTEGER_HEXADECIMAL:
                kind = EXPR_LITERAL_INTEGER_HEXADECIMAL;
                check_integer_suffix();
+               type = type_int;
                break;
        case T_FLOATINGPOINT:
                kind = EXPR_LITERAL_FLOATINGPOINT;
@@ -6166,7 +6212,7 @@ static expression_t *parse_character_constant(void)
        literal->literal.value        = token.literal;
 
        size_t len = literal->literal.value.size;
-       if (len != 1) {
+       if (len > 1) {
                if (!GNU_MODE && !(c_mode & _C99)) {
                        errorf(HERE, "more than 1 character in character constant");
                } else if (warning.multichar) {
@@ -6190,7 +6236,7 @@ static expression_t *parse_wide_character_constant(void)
        literal->literal.value        = token.literal;
 
        size_t len = wstrlen(&literal->literal.value);
-       if (len != 1) {
+       if (len > 1) {
                warningf(HERE, "multi-character character constant");
        }
 
@@ -6212,6 +6258,7 @@ static entity_t *create_implicit_function(symbol_t *symbol,
        entity->declaration.declared_storage_class = STORAGE_CLASS_EXTERN;
        entity->declaration.type                   = type;
        entity->declaration.implicit               = true;
+       entity->base.namespc                       = NAMESPACE_NORMAL;
        entity->base.symbol                        = symbol;
        entity->base.source_position               = *source_position;
 
@@ -6540,7 +6587,7 @@ static expression_t *parse_cast(void)
        expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
        cast->base.source_position = source_position;
 
-       expression_t *value = parse_sub_expression(PREC_CAST);
+       expression_t *value = parse_subexpression(PREC_CAST);
        cast->base.type   = type;
        cast->unary.value = value;
 
@@ -7147,6 +7194,7 @@ static expression_t *parse_primary_expression(void)
        }
 
        errorf(HERE, "unexpected token %K, expected an expression", &token);
+       eat_until_anchor();
        return create_invalid_expression();
 }
 
@@ -7239,7 +7287,7 @@ static expression_t *parse_typeprop(expression_kind_t const kind)
                        goto typeprop_expression;
                }
        } else {
-               expression = parse_sub_expression(PREC_UNARY);
+               expression = parse_subexpression(PREC_UNARY);
 
 typeprop_expression:
                tp_expression->typeprop.tp_expression = expression;
@@ -7250,12 +7298,28 @@ typeprop_expression:
 
        tp_expression->typeprop.type   = orig_type;
        type_t const* const type       = skip_typeref(orig_type);
-       char   const* const wrong_type =
-               GNU_MODE && is_type_atomic(type, ATOMIC_TYPE_VOID) ? NULL                  :
-               is_type_incomplete(type)                           ? "incomplete"          :
-               type->kind == TYPE_FUNCTION                        ? "function designator" :
-               type->kind == TYPE_BITFIELD                        ? "bitfield"            :
-               NULL;
+       char   const*       wrong_type = NULL;
+       if (is_type_incomplete(type)) {
+               if (!is_type_atomic(type, ATOMIC_TYPE_VOID) || !GNU_MODE)
+                       wrong_type = "incomplete";
+       } else if (type->kind == TYPE_FUNCTION) {
+               if (GNU_MODE) {
+                       /* function types are allowed (and return 1) */
+                       if (warning.other) {
+                               char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
+                               warningf(&tp_expression->base.source_position,
+                                        "%s expression with function argument returns invalid result", what);
+                       }
+               } else {
+                       wrong_type = "function";
+               }
+       } else {
+               if (is_type_incomplete(type))
+                       wrong_type = "incomplete";
+       }
+       if (type->kind == TYPE_BITFIELD)
+               wrong_type = "bitfield";
+
        if (wrong_type != NULL) {
                char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
                errorf(&tp_expression->base.source_position,
@@ -7282,6 +7346,7 @@ static expression_t *parse_select_expression(expression_t *addr)
 {
        assert(token.type == '.' || token.type == T_MINUSGREATER);
        bool select_left_arrow = (token.type == T_MINUSGREATER);
+       source_position_t const pos = *HERE;
        next_token();
 
        if (token.type != T_IDENTIFIER) {
@@ -7298,7 +7363,7 @@ static expression_t *parse_select_expression(expression_t *addr)
        bool    saw_error = false;
        if (is_type_pointer(type)) {
                if (!select_left_arrow) {
-                       errorf(HERE,
+                       errorf(&pos,
                               "request for member '%Y' in something not a struct or union, but '%T'",
                               symbol, orig_type);
                        saw_error = true;
@@ -7306,7 +7371,7 @@ static expression_t *parse_select_expression(expression_t *addr)
                type_left = skip_typeref(type->pointer.points_to);
        } else {
                if (select_left_arrow && is_type_valid(type)) {
-                       errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type);
+                       errorf(&pos, "left hand side of '->' is not a pointer, but '%T'", orig_type);
                        saw_error = true;
                }
                type_left = type;
@@ -7316,7 +7381,7 @@ static expression_t *parse_select_expression(expression_t *addr)
            type_left->kind != TYPE_COMPOUND_UNION) {
 
                if (is_type_valid(type_left) && !saw_error) {
-                       errorf(HERE,
+                       errorf(&pos,
                               "request for member '%Y' in something not a struct or union, but '%T'",
                               symbol, type_left);
                }
@@ -7325,17 +7390,17 @@ static expression_t *parse_select_expression(expression_t *addr)
 
        compound_t *compound = type_left->compound.compound;
        if (!compound->complete) {
-               errorf(HERE, "request for member '%Y' in incomplete type '%T'",
+               errorf(&pos, "request for member '%Y' in incomplete type '%T'",
                       symbol, type_left);
                return create_invalid_expression();
        }
 
        type_qualifiers_t  qualifiers = type_left->base.qualifiers;
-       expression_t      *result
-               = find_create_select(HERE, addr, qualifiers, compound, symbol);
+       expression_t      *result     =
+               find_create_select(&pos, addr, qualifiers, compound, symbol);
 
        if (result == NULL) {
-               errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol);
+               errorf(&pos, "'%T' has no member named '%Y'", orig_type, symbol);
                return create_invalid_expression();
        }
 
@@ -7383,8 +7448,8 @@ static void check_call_argument(type_t          *expected_type,
                /* report exact scope in error messages (like "in argument 3") */
                char buf[64];
                snprintf(buf, sizeof(buf), "call argument %u", pos);
-               report_assign_error(error, expected_type, arg_expr,     buf,
-                                                       &arg_expr->base.source_position);
+               report_assign_error(error, expected_type, arg_expr, buf,
+                                   &arg_expr->base.source_position);
        } else if (warning.traditional || warning.conversion) {
                type_t *const promoted_type = get_default_promoted_type(arg_type);
                if (!types_compatible(expected_type_skip, promoted_type) &&
@@ -7408,20 +7473,33 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) {
                        /* argument must be constant */
                        call_argument_t *argument = call->arguments;
 
-                       if (! is_constant_expression(argument->expression)) {
+                       if (is_constant_expression(argument->expression) == EXPR_CLASS_VARIABLE) {
                                errorf(&call->base.source_position,
                                       "argument of '%Y' must be a constant expression",
                                       call->function->reference.entity->base.symbol);
                        }
                        break;
                }
-               case bk_gnu_builtin_prefetch: {
+               case bk_gnu_builtin_object_size:
+                       if (call->arguments == NULL)
+                               break;
+
+                       call_argument_t *arg = call->arguments->next;
+                       if (arg != NULL && is_constant_expression(arg->expression) == EXPR_CLASS_VARIABLE) {
+                               errorf(&call->base.source_position,
+                                          "second argument of '%Y' must be a constant expression",
+                                          call->function->reference.entity->base.symbol);
+                       }
+                       break;
+               case bk_gnu_builtin_prefetch:
                        /* second and third argument must be constant if existent */
+                       if (call->arguments == NULL)
+                               break;
                        call_argument_t *rw = call->arguments->next;
                        call_argument_t *locality = NULL;
 
                        if (rw != NULL) {
-                               if (! is_constant_expression(rw->expression)) {
+                               if (is_constant_expression(rw->expression) == EXPR_CLASS_VARIABLE) {
                                        errorf(&call->base.source_position,
                                               "second argument of '%Y' must be a constant expression",
                                               call->function->reference.entity->base.symbol);
@@ -7429,7 +7507,7 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) {
                                locality = rw->next;
                        }
                        if (locality != NULL) {
-                               if (! is_constant_expression(locality->expression)) {
+                               if (is_constant_expression(locality->expression) == EXPR_CLASS_VARIABLE) {
                                        errorf(&call->base.source_position,
                                               "third argument of '%Y' must be a constant expression",
                                               call->function->reference.entity->base.symbol);
@@ -7437,7 +7515,6 @@ static void handle_builtin_argument_restrictions(call_expression_t *call) {
                                locality = rw->next;
                        }
                        break;
-               }
                default:
                        break;
        }
@@ -7514,6 +7591,10 @@ static expression_t *parse_call_expression(expression_t *expression)
        /* do default promotion for other arguments */
        for (; argument != NULL; argument = argument->next) {
                type_t *type = argument->expression->base.type;
+               if (!is_type_object(skip_typeref(type))) {
+                       errorf(&argument->expression->base.source_position,
+                              "call argument '%E' must not be void", argument->expression);
+               }
 
                type = get_default_promoted_type(type);
 
@@ -7646,7 +7727,7 @@ static expression_t *parse_conditional_expression(expression_t *expression)
        expect(':', end_error);
 end_error:;
        expression_t *false_expression =
-               parse_sub_expression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL);
+               parse_subexpression(c_mode & _CXX ? PREC_ASSIGNMENT : PREC_CONDITIONAL);
 
        type_t *const orig_true_type  = true_expression->base.type;
        type_t *const orig_false_type = false_expression->base.type;
@@ -7675,13 +7756,6 @@ end_error:;
        } else if (is_type_arithmetic(true_type)
                   && is_type_arithmetic(false_type)) {
                result_type = semantic_arithmetic(true_type, false_type);
-
-               true_expression  = create_implicit_cast(true_expression, result_type);
-               false_expression = create_implicit_cast(false_expression, result_type);
-
-               conditional->true_expression  = true_expression;
-               conditional->false_expression = false_expression;
-               conditional->base.type        = result_type;
        } else if (same_compound_type(true_type, false_type)) {
                /* just take 1 of the 2 types */
                result_type = true_type;
@@ -7733,7 +7807,7 @@ end_error:;
                        result_type = pointer_type;
                } else {
                        if (is_type_valid(other_type)) {
-                               type_error_incompatible("while parsing conditional",
+                               type_error_incompatible("while parsing conditional",
                                                &expression->base.source_position, true_type, false_type);
                        }
                        result_type = type_error_type;
@@ -7764,7 +7838,7 @@ static expression_t *parse_extension(void)
 
        bool old_gcc_extension   = in_gcc_extension;
        in_gcc_extension         = true;
-       expression_t *expression = parse_sub_expression(PREC_UNARY);
+       expression_t *expression = parse_subexpression(PREC_UNARY);
        in_gcc_extension         = old_gcc_extension;
        return expression;
 }
@@ -7808,7 +7882,7 @@ static expression_t *parse_delete(void)
 end_error:;
        }
 
-       expression_t *const value = parse_sub_expression(PREC_CAST);
+       expression_t *const value = parse_subexpression(PREC_CAST);
        result->unary.value = value;
 
        type_t *const type = skip_typeref(value->base.type);
@@ -8026,8 +8100,8 @@ static void set_address_taken(expression_t *expression, bool may_be_register)
        if (entity->declaration.storage_class == STORAGE_CLASS_REGISTER
                        && !may_be_register) {
                errorf(&expression->base.source_position,
-                               "address of register %s '%Y' requested",
-                               get_entity_kind_name(entity->kind),     entity->base.symbol);
+                      "address of register %s '%Y' requested",
+                      get_entity_kind_name(entity->kind), entity->base.symbol);
        }
 
        if (entity->kind == ENTITY_VARIABLE) {
@@ -8072,7 +8146,7 @@ static expression_t *parse_##unexpression_type(void)                         \
        expression_t *unary_expression                                           \
                = allocate_expression_zero(unexpression_type);                       \
        eat(token_type);                                                         \
-       unary_expression->unary.value = parse_sub_expression(PREC_UNARY);        \
+       unary_expression->unary.value = parse_subexpression(PREC_UNARY);         \
                                                                                 \
        sfunc(&unary_expression->unary);                                         \
                                                                                 \
@@ -8208,6 +8282,30 @@ static void semantic_binexpr_arithmetic(binary_expression_t *expression)
        expression->base.type = arithmetic_type;
 }
 
+static void semantic_binexpr_integer(binary_expression_t *const expression)
+{
+       expression_t *const left            = expression->left;
+       expression_t *const right           = expression->right;
+       type_t       *const orig_type_left  = left->base.type;
+       type_t       *const orig_type_right = right->base.type;
+       type_t       *const type_left       = skip_typeref(orig_type_left);
+       type_t       *const type_right      = skip_typeref(orig_type_right);
+
+       if (!is_type_integer(type_left) || !is_type_integer(type_right)) {
+               /* TODO: improve error message */
+               if (is_type_valid(type_left) && is_type_valid(type_right)) {
+                       errorf(&expression->base.source_position,
+                              "operation needs integer types");
+               }
+               return;
+       }
+
+       type_t *const result_type = semantic_arithmetic(type_left, type_right);
+       expression->left      = create_implicit_cast(left, result_type);
+       expression->right     = create_implicit_cast(right, result_type);
+       expression->base.type = result_type;
+}
+
 static void warn_div_by_zero(binary_expression_t const *const expression)
 {
        if (!warning.div_by_zero ||
@@ -8216,8 +8314,8 @@ 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)     &&
+       if (is_type_integer(right->base.type)                    &&
+           is_constant_expression(right) == EXPR_CLASS_CONSTANT &&
            !fold_constant_to_bool(right)) {
                warningf(&expression->base.source_position, "division by zero");
        }
@@ -8268,7 +8366,7 @@ static bool semantic_shift(binary_expression_t *expression)
 
        type_left = promote_integer(type_left);
 
-       if (is_constant_expression(right)) {
+       if (is_constant_expression(right) == EXPR_CLASS_CONSTANT) {
                long count = fold_constant_to_int(right);
                if (count < 0) {
                        warningf(&right->base.source_position,
@@ -8416,9 +8514,11 @@ static void warn_comparison_in_comparison(const expression_t *const expr)
 
 static bool maybe_negative(expression_t const *const expr)
 {
-       return
-               !is_constant_expression(expr) ||
-               fold_constant_to_int(expr) < 0;
+       switch (is_constant_expression(expr)) {
+               case EXPR_CLASS_ERROR:    return false;
+               case EXPR_CLASS_CONSTANT: return fold_constant_to_int(expr) < 0;
+               default:                  return true;
+       }
 }
 
 /**
@@ -8886,7 +8986,7 @@ static expression_t *parse_##binexpression_type(expression_t *left)          \
        binexpr->binary.left  = left;                                            \
        eat(token_type);                                                         \
                                                                              \
-       expression_t *right = parse_sub_expression(prec_r);                      \
+       expression_t *right = parse_subexpression(prec_r);                       \
                                                                              \
        binexpr->binary.right = right;                                           \
        sfunc(&binexpr->binary);                                                 \
@@ -8907,9 +9007,9 @@ CREATE_BINEXPR_PARSER(T_LESSEQUAL,            EXPR_BINARY_LESSEQUAL,          PR
 CREATE_BINEXPR_PARSER(T_GREATEREQUAL,         EXPR_BINARY_GREATEREQUAL,       PREC_SHIFT,          semantic_comparison)
 CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, EXPR_BINARY_NOTEQUAL,           PREC_RELATIONAL,     semantic_comparison)
 CREATE_BINEXPR_PARSER(T_EQUALEQUAL,           EXPR_BINARY_EQUAL,              PREC_RELATIONAL,     semantic_comparison)
-CREATE_BINEXPR_PARSER('&',                    EXPR_BINARY_BITWISE_AND,        PREC_EQUALITY,       semantic_binexpr_arithmetic)
-CREATE_BINEXPR_PARSER('^',                    EXPR_BINARY_BITWISE_XOR,        PREC_AND,            semantic_binexpr_arithmetic)
-CREATE_BINEXPR_PARSER('|',                    EXPR_BINARY_BITWISE_OR,         PREC_XOR,            semantic_binexpr_arithmetic)
+CREATE_BINEXPR_PARSER('&',                    EXPR_BINARY_BITWISE_AND,        PREC_EQUALITY,       semantic_binexpr_integer)
+CREATE_BINEXPR_PARSER('^',                    EXPR_BINARY_BITWISE_XOR,        PREC_AND,            semantic_binexpr_integer)
+CREATE_BINEXPR_PARSER('|',                    EXPR_BINARY_BITWISE_OR,         PREC_XOR,            semantic_binexpr_integer)
 CREATE_BINEXPR_PARSER(T_ANDAND,               EXPR_BINARY_LOGICAL_AND,        PREC_OR,             semantic_logical_op)
 CREATE_BINEXPR_PARSER(T_PIPEPIPE,             EXPR_BINARY_LOGICAL_OR,         PREC_LOGICAL_AND,    semantic_logical_op)
 CREATE_BINEXPR_PARSER('=',                    EXPR_BINARY_ASSIGN,             PREC_ASSIGNMENT,     semantic_binexpr_assign)
@@ -8926,7 +9026,7 @@ CREATE_BINEXPR_PARSER(T_CARETEQUAL,           EXPR_BINARY_BITWISE_XOR_ASSIGN, PR
 CREATE_BINEXPR_PARSER(',',                    EXPR_BINARY_COMMA,              PREC_ASSIGNMENT,     semantic_comma)
 
 
-static expression_t *parse_sub_expression(precedence_t precedence)
+static expression_t *parse_subexpression(precedence_t precedence)
 {
        if (token.type < 0) {
                return expected_expression_error();
@@ -8971,7 +9071,7 @@ static expression_t *parse_sub_expression(precedence_t precedence)
  */
 static expression_t *parse_expression(void)
 {
-       return parse_sub_expression(PREC_EXPRESSION);
+       return parse_subexpression(PREC_EXPRESSION);
 }
 
 /**
@@ -9000,7 +9100,7 @@ static void register_expression_parser(parse_expression_function parser,
  * @param precedence  the precedence of the operator
  */
 static void register_infix_parser(parse_expression_infix_function parser,
-               int token_type, precedence_t precedence)
+                                  int token_type, precedence_t precedence)
 {
        expression_parser_function_t *entry = &expression_parsers[token_type];
 
@@ -9152,7 +9252,9 @@ static asm_argument_t *parse_asm_arguments(bool is_out)
                                       "asm output argument is not an lvalue");
                        }
 
-                       if (argument->constraints.begin[0] == '+')
+                       if (argument->constraints.begin[0] == '=')
+                               determine_lhs_ent(expression, NULL);
+                       else
                                mark_vars_read(expression, NULL);
                } else {
                        mark_vars_read(expression, NULL);
@@ -9211,9 +9313,13 @@ static statement_t *parse_asm_statement(void)
 
        expect('(', end_error);
        add_anchor_token(')');
-       add_anchor_token(':');
+       if (token.type != T_STRING_LITERAL) {
+               parse_error_expected("after asm(", T_STRING_LITERAL, NULL);
+               goto end_of_asm;
+       }
        asm_statement->asm_text = parse_string_literals();
 
+       add_anchor_token(':');
        if (!next_if(':')) {
                rem_anchor_token(':');
                goto end_of_asm;
@@ -9250,6 +9356,37 @@ end_error:
        return create_invalid_statement();
 }
 
+static statement_t *parse_label_inner_statement(statement_t const *const label, char const *const label_kind)
+{
+       statement_t *inner_stmt;
+       switch (token.type) {
+               case '}':
+                       errorf(&label->base.source_position, "%s at end of compound statement", label_kind);
+                       inner_stmt = create_invalid_statement();
+                       break;
+
+               case ';':
+                       if (label->kind == STATEMENT_LABEL) {
+                               /* Eat an empty statement here, to avoid the warning about an empty
+                                * statement after a label.  label:; is commonly used to have a label
+                                * before a closing brace. */
+                               inner_stmt = create_empty_statement();
+                               next_token();
+                               break;
+                       }
+                       /* FALLTHROUGH */
+
+               default:
+                       inner_stmt = parse_statement();
+                       /* ISO/IEC 14882:1998(E) §6:1/§6.7  Declarations are statements */
+                       if (inner_stmt->kind == STATEMENT_DECLARATION && !(c_mode & _CXX)) {
+                               errorf(&inner_stmt->base.source_position, "declaration after %s", label_kind);
+                       }
+                       break;
+       }
+       return inner_stmt;
+}
+
 /**
  * Parse a case statement.
  */
@@ -9262,11 +9399,9 @@ static statement_t *parse_case_statement(void)
 
        expression_t *const expression   = parse_expression();
        statement->case_label.expression = expression;
-       if (!is_constant_expression(expression)) {
-               /* This check does not prevent the error message in all cases of an
-                * prior error while parsing the expression.  At least it catches the
-                * common case of a mistyped enum entry. */
-               if (is_type_valid(skip_typeref(expression->base.type))) {
+       expression_classification_t const expr_class = is_constant_expression(expression);
+       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;
@@ -9280,11 +9415,9 @@ static statement_t *parse_case_statement(void)
                if (next_if(T_DOTDOTDOT)) {
                        expression_t *const end_range   = parse_expression();
                        statement->case_label.end_range = end_range;
-                       if (!is_constant_expression(end_range)) {
-                               /* This check does not prevent the error message in all cases of an
-                                * prior error while parsing the expression.  At least it catches the
-                                * common case of a mistyped enum entry. */
-                               if (is_type_valid(skip_typeref(end_range->base.type))) {
+                       expression_classification_t const end_class = is_constant_expression(end_range);
+                       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;
@@ -9332,11 +9465,7 @@ end_error:
                errorf(pos, "case label not within a switch statement");
        }
 
-       statement_t *const inner_stmt = parse_statement();
-       statement->case_label.statement = inner_stmt;
-       if (inner_stmt->kind == STATEMENT_DECLARATION) {
-               errorf(&inner_stmt->base.source_position, "declaration after case label");
-       }
+       statement->case_label.statement = parse_label_inner_statement(statement, "case label");
 
        POP_PARENT;
        return statement;
@@ -9354,6 +9483,8 @@ static statement_t *parse_default_statement(void)
        PUSH_PARENT(statement);
 
        expect(':', end_error);
+end_error:
+
        if (current_switch != NULL) {
                const case_label_statement_t *def_label = current_switch->default_label;
                if (def_label != NULL) {
@@ -9375,17 +9506,10 @@ static statement_t *parse_default_statement(void)
                        "'default' label not within a switch statement");
        }
 
-       statement_t *const inner_stmt = parse_statement();
-       statement->case_label.statement = inner_stmt;
-       if (inner_stmt->kind == STATEMENT_DECLARATION) {
-               errorf(&inner_stmt->base.source_position, "declaration after default label");
-       }
+       statement->case_label.statement = parse_label_inner_statement(statement, "default label");
 
        POP_PARENT;
        return statement;
-end_error:
-       POP_PARENT;
-       return create_invalid_statement();
 }
 
 /**
@@ -9417,28 +9541,7 @@ static statement_t *parse_label_statement(void)
 
        eat(':');
 
-       if (token.type == '}') {
-               /* TODO only warn? */
-               if (warning.other && false) {
-                       warningf(HERE, "label at end of compound statement");
-                       statement->label.statement = create_empty_statement();
-               } else {
-                       errorf(HERE, "label at end of compound statement");
-                       statement->label.statement = create_invalid_statement();
-               }
-       } else if (token.type == ';') {
-               /* Eat an empty statement here, to avoid the warning about an empty
-                * statement after a label.  label:; is commonly used to have a label
-                * before a closing brace. */
-               statement->label.statement = create_empty_statement();
-               next_token();
-       } else {
-               statement_t *const inner_stmt = parse_statement();
-               statement->label.statement = inner_stmt;
-               if (inner_stmt->kind == STATEMENT_DECLARATION) {
-                       errorf(&inner_stmt->base.source_position, "declaration after label");
-               }
-       }
+       statement->label.statement = parse_label_inner_statement(statement, "label");
 
        /* remember the labels in a list for later checking */
        *label_anchor = &statement->label;
@@ -9785,7 +9888,7 @@ static statement_t *parse_goto(void)
                else
                        parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
                eat_until_anchor();
-               goto end_error;
+               return create_invalid_statement();
        }
 
        /* remember the goto's in a list for later checking */
@@ -9794,9 +9897,8 @@ static statement_t *parse_goto(void)
 
        expect(';', end_error);
 
-       return statement;
 end_error:
-       return create_invalid_statement();
+       return statement;
 }
 
 /**
@@ -9950,13 +10052,13 @@ static statement_t *parse_return(void)
                        }
                } else {
                        assign_error_t error = semantic_assign(return_type, return_value);
-                       report_assign_error(error, return_type, return_value, "'return'",
-                                       pos);
+                       report_assign_error(error, return_type, return_value, "'return'",
+                                           pos);
                }
                return_value = create_implicit_cast(return_value, return_type);
                /* check for returning address of a local var */
                if (warning.other && return_value != NULL
-                               && return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
+                   && return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
                        const expression_t *expression = return_value->unary.value;
                        if (expression_is_local_variable(expression)) {
                                warningf(pos, "function returns address of local variable");
@@ -9966,10 +10068,10 @@ static statement_t *parse_return(void)
                /* ISO/IEC 14882:1998(E) §6.6.3:3 */
                if (c_mode & _CXX || strict_mode) {
                        errorf(pos,
-                                       "'return' without value, in function returning non-void");
+                              "'return' without value, in function returning non-void");
                } else {
                        warningf(pos,
-                                       "'return' without value, in function returning non-void");
+                                "'return' without value, in function returning non-void");
                }
        }
        statement->returns.value = return_value;
@@ -10082,8 +10184,9 @@ static statement_t *parse_local_label_declaration(void)
 
        eat(T___label__);
 
-       entity_t *begin = NULL, *end = NULL;
-
+       entity_t *begin   = NULL;
+       entity_t *end     = NULL;
+       entity_t **anchor = &begin;
        do {
                if (token.type != T_IDENTIFIER) {
                        parse_error_expected("while parsing local label declaration",
@@ -10103,17 +10206,15 @@ static statement_t *parse_local_label_declaration(void)
                        entity->base.source_position = token.source_position;
                        entity->base.symbol          = symbol;
 
-                       if (end != NULL)
-                               end->base.next = entity;
-                       end = entity;
-                       if (begin == NULL)
-                               begin = entity;
+                       *anchor = entity;
+                       anchor  = &entity->base.next;
+                       end     = entity;
 
                        environment_push(entity);
                }
                next_token();
        } while (next_if(','));
-       eat(';');
+       expect(';', end_error);
 end_error:
        statement->declaration.declarations_begin = begin;
        statement->declaration.declarations_end   = end;
@@ -10135,7 +10236,7 @@ static void parse_namespace_definition(void)
                if (entity != NULL
                                && entity->kind != ENTITY_NAMESPACE
                                && entity->base.parent_scope == current_scope) {
-                       if (!is_error_entity(entity)) {
+                       if (is_entity_valid(entity)) {
                                error_redefined_as_different_kind(&token.source_position,
                                                entity, ENTITY_NAMESPACE);
                        }
@@ -10203,18 +10304,14 @@ static statement_t *intern_parse_statement(void)
                        switch (la1_type) {
                        case '&':
                        case '*':
-                               if (get_entity(token.symbol, NAMESPACE_NORMAL) != NULL)
-                                       goto expression_statment;
-                               /* FALLTHROUGH */
-
+                               if (get_entity(token.symbol, NAMESPACE_NORMAL) != NULL) {
+                       default:
+                                       statement = parse_expression_statement();
+                               } else {
                        DECLARATION_START
                        case T_IDENTIFIER:
-                               statement = parse_declaration_statement();
-                               break;
-
-                       default:
-expression_statment:
-                               statement = parse_expression_statement();
+                                       statement = parse_declaration_statement();
+                               }
                                break;
                        }
                }
@@ -10605,7 +10702,6 @@ end_error:;
 static void parse_linkage_specification(void)
 {
        eat(T_extern);
-       assert(token.type == T_STRING_LITERAL);
 
        const char *linkage = parse_string_literals().begin;
 
@@ -10687,6 +10783,7 @@ static void parse_externals(void)
        add_anchor_token(T_EOF);
 
 #ifndef NDEBUG
+       /* make a copy of the anchor set, so we can check if it is restored after parsing */
        unsigned char token_anchor_copy[T_LAST_TOKEN];
        memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy));
 #endif
@@ -10694,14 +10791,16 @@ static void parse_externals(void)
        while (token.type != T_EOF && token.type != '}') {
 #ifndef NDEBUG
                bool anchor_leak = false;
-               for (int i = 0; i != T_LAST_TOKEN; ++i) {
+               for (int i = 0; i < T_LAST_TOKEN; ++i) {
                        unsigned char count = token_anchor_set[i] - token_anchor_copy[i];
                        if (count != 0) {
+                               /* the anchor set and its copy differs */
                                errorf(HERE, "Leaked anchor token %k %d times", i, count);
                                anchor_leak = true;
                        }
                }
                if (in_gcc_extension) {
+                       /* an gcc extension scope was not closed */
                        errorf(HERE, "Leaked __extension__");
                        anchor_leak = true;
                }
@@ -10868,9 +10967,6 @@ void init_parser(void)
 
        init_expression_parsers();
        obstack_init(&temp_obst);
-
-       symbol_t *const va_list_sym = symbol_table_insert("__builtin_va_list");
-       type_valist = create_builtin_type(va_list_sym, type_void_ptr);
 }
 
 /**