- when parsing compound types, do NOT destroy old declarations if
[cparser] / parser.c
index 9a35b66..c4523d8 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -103,17 +103,19 @@ typedef struct parse_initializer_env_t {
        bool           must_be_constant;
 } parse_initializer_env_t;
 
-typedef declaration_t* (*parsed_declaration_func) (declaration_t *declaration);
+typedef declaration_t* (*parsed_declaration_func) (declaration_t *declaration, bool is_definition);
 
 static token_t             token;
 static token_t             lookahead_buffer[MAX_LOOKAHEAD];
 static int                 lookahead_bufpos;
 static stack_entry_t      *environment_stack = NULL;
 static stack_entry_t      *label_stack       = NULL;
+static stack_entry_t      *local_label_stack = NULL;
 static scope_t            *global_scope      = NULL;
 static scope_t            *scope             = NULL;
 static declaration_t      *last_declaration  = NULL;
 static declaration_t      *current_function  = NULL;
+static declaration_t      *current_init_decl = NULL;
 static switch_statement_t *current_switch    = NULL;
 static statement_t        *current_loop      = NULL;
 static statement_t        *current_parent    = NULL;
@@ -132,6 +134,9 @@ static struct obstack      temp_obst;
 
 static source_position_t null_position = { NULL, 0 };
 
+/** special symbol used for anonymous entities. */
+static const symbol_t *sym_anonymous = NULL;
+
 /* symbols for Microsoft extended-decl-modifier */
 static const symbol_t *sym_align      = NULL;
 static const symbol_t *sym_allocate   = NULL;
@@ -170,7 +175,7 @@ static type_t       *parse_typename(void);
 static void parse_compound_type_entries(declaration_t *compound_declaration);
 static declaration_t *parse_declarator(
                const declaration_specifiers_t *specifiers, bool may_be_abstract);
-static declaration_t *record_declaration(declaration_t *declaration);
+static declaration_t *record_declaration(declaration_t *declaration, bool is_definition);
 
 static void semantic_comparison(binary_expression_t *expression);
 
@@ -314,6 +319,7 @@ static size_t get_expression_struct_size(expression_kind_t kind)
                [EXPR_VA_START]                = sizeof(va_start_expression_t),
                [EXPR_VA_ARG]                  = sizeof(va_arg_expression_t),
                [EXPR_STATEMENT]               = sizeof(statement_expression_t),
+               [EXPR_LABEL_ADDRESS]           = sizeof(label_address_expression_t),
        };
        if (kind >= EXPR_UNARY_FIRST && kind <= EXPR_UNARY_LAST) {
                return sizes[EXPR_UNARY_FIRST];
@@ -478,13 +484,21 @@ static size_t environment_top(void)
 }
 
 /**
- * Returns the index of the top element of the label stack.
+ * Returns the index of the top element of the global label stack.
  */
 static size_t label_top(void)
 {
        return ARR_LEN(label_stack);
 }
 
+/**
+ * Returns the index of the top element of the local label stack.
+ */
+static size_t local_label_top(void)
+{
+       return ARR_LEN(local_label_stack);
+}
+
 /**
  * Return the next token.
  */
@@ -763,6 +777,11 @@ static void stack_push(stack_entry_t **stack_ptr, declaration_t *declaration)
        ARR_APP1(stack_entry_t, *stack_ptr, entry);
 }
 
+/**
+ * Push a declaration on the environment stack.
+ *
+ * @param declaration  the declaration
+ */
 static void environment_push(declaration_t *declaration)
 {
        assert(declaration->source_position.input_name != NULL);
@@ -771,7 +790,7 @@ static void environment_push(declaration_t *declaration)
 }
 
 /**
- * Push a declaration of the label stack.
+ * Push a declaration on the global label stack.
  *
  * @param declaration  the declaration
  */
@@ -781,6 +800,17 @@ static void label_push(declaration_t *declaration)
        stack_push(&label_stack, declaration);
 }
 
+/**
+ * Push a declaration of the local label stack.
+ *
+ * @param declaration  the declaration
+ */
+static void local_label_push(declaration_t *declaration)
+{
+       assert(declaration->parent_scope != NULL);
+       stack_push(&local_label_stack, declaration);
+}
+
 /**
  * pops symbols from the environment stack until @p new_top is the top element
  */
@@ -831,13 +861,19 @@ static void stack_pop_to(stack_entry_t **stack_ptr, size_t new_top)
        ARR_SHRINKLEN(*stack_ptr, (int) new_top);
 }
 
+/**
+ * Pop all entries from the environment stack until the new_top
+ * is reached.
+ *
+ * @param new_top  the new stack top
+ */
 static void environment_pop_to(size_t new_top)
 {
        stack_pop_to(&environment_stack, new_top);
 }
 
 /**
- * Pop all entries on the label stack until the new_top
+ * Pop all entries from the global label stack until the new_top
  * is reached.
  *
  * @param new_top  the new stack top
@@ -847,6 +883,18 @@ static void label_pop_to(size_t new_top)
        stack_pop_to(&label_stack, new_top);
 }
 
+/**
+ * Pop all entries from the local label stack until the new_top
+ * is reached.
+ *
+ * @param new_top  the new stack top
+ */
+static void local_label_pop_to(size_t new_top)
+{
+       stack_pop_to(&local_label_stack, new_top);
+}
+
+
 static int get_akind_rank(atomic_type_kind_t akind)
 {
        return (int) akind;
@@ -985,7 +1033,7 @@ static void report_assign_error(assign_error_t error, type_t *orig_type_left,
 
        case ASSIGN_WARNING_POINTER_FROM_INT:
                warningf(source_position,
-                        "%s makes integer '%T' from pointer '%T' without a cast",
+                        "%s makes pointer '%T' from integer '%T' without a cast",
                                 context, orig_type_left, orig_type_right);
                return;
 
@@ -1094,7 +1142,7 @@ static type_t *make_global_typedef(const char *name, type_t *type)
        declaration->source_position        = builtin_source_position;
        declaration->implicit               = true;
 
-       record_declaration(declaration);
+       record_declaration(declaration, false);
 
        type_t *typedef_type               = allocate_type_zero(TYPE_TYPEDEF, &builtin_source_position);
        typedef_type->typedeft.declaration = declaration;
@@ -2103,8 +2151,6 @@ static void descend_into_subtype(type_path_t *path)
        type_t *orig_top_type = path->top_type;
        type_t *top_type      = skip_typeref(orig_top_type);
 
-       assert(is_type_compound(top_type) || is_type_array(top_type));
-
        type_path_entry_t *top = append_to_type_path(path);
        top->type              = top_type;
 
@@ -2118,11 +2164,11 @@ static void descend_into_subtype(type_path_t *path)
                } else {
                        path->top_type         = NULL;
                }
-       } else {
-               assert(is_type_array(top_type));
-
+       } else if (is_type_array(top_type)) {
                top->v.index   = 0;
                path->top_type = top_type->array.element_type;
+       } else {
+               assert(!is_type_valid(top_type));
        }
 }
 
@@ -2651,7 +2697,6 @@ static declaration_t *parse_compound_type_specifier(bool is_struct)
                                errorf(HERE, "multiple definitions of '%s %Y' (previous definition at %P)",
                                       is_struct ? "struct" : "union", symbol,
                                       &declaration->source_position);
-                               declaration->scope.declarations = NULL;
                        }
                }
        } else if (token.type != '{') {
@@ -2666,18 +2711,17 @@ static declaration_t *parse_compound_type_specifier(bool is_struct)
                return NULL;
        }
 
-       if (declaration == NULL) {
-               declaration = allocate_declaration_zero();
-               declaration->namespc         =
-                       (is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION);
-               declaration->source_position = token.source_position;
-               declaration->symbol          = symbol;
-               declaration->parent_scope    = scope;
-               if (symbol != NULL) {
-                       environment_push(declaration);
-               }
-               append_declaration(declaration);
+       /* always create a new declaration, do NOT modify old one */
+       declaration = allocate_declaration_zero();
+       declaration->namespc         =
+               (is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION);
+       declaration->source_position = token.source_position;
+       declaration->symbol          = symbol;
+       declaration->parent_scope    = scope;
+       if (symbol != NULL) {
+               environment_push(declaration);
        }
+       append_declaration(declaration);
 
        if (token.type == '{') {
                declaration->init.complete = true;
@@ -2726,7 +2770,7 @@ static void parse_enum_entries(type_t *const enum_type)
                        /* TODO semantic */
                }
 
-               record_declaration(entry);
+               record_declaration(entry, false);
 
                if (token.type != ',')
                        break;
@@ -2740,11 +2784,14 @@ end_error:
        ;
 }
 
+/**
+ * Parse enum specifier and return the enum type or NULL on error.
+ */
 static type_t *parse_enum_specifier(void)
 {
-       gnu_attribute_t *attributes = NULL;
-       declaration_t   *declaration;
-       symbol_t        *symbol;
+       gnu_attribute_t *attributes  = NULL;
+       declaration_t   *declaration = NULL;
+       symbol_t        *symbol      = NULL;
 
        eat(T_enum);
        if (token.type == T_IDENTIFIER) {
@@ -2756,30 +2803,31 @@ static type_t *parse_enum_specifier(void)
                parse_error_expected("while parsing enum type specifier",
                                     T_IDENTIFIER, '{', NULL);
                return NULL;
-       } else {
-               declaration = NULL;
-               symbol      = NULL;
        }
 
-       if (declaration == NULL) {
-               declaration = allocate_declaration_zero();
-               declaration->namespc         = NAMESPACE_ENUM;
-               declaration->source_position = token.source_position;
-               declaration->symbol          = symbol;
-               declaration->parent_scope  = scope;
+       if (token.type == '{' && declaration != NULL && declaration->init.complete) {
+               errorf(HERE, "multiple definitions of enum '%Y' (previous definition at %P)",
+                       symbol, &declaration->source_position);
+       }
+
+       declaration = allocate_declaration_zero();
+       declaration->namespc         = NAMESPACE_ENUM;
+       declaration->source_position = token.source_position;
+       declaration->symbol          = symbol;
+       declaration->parent_scope    = scope;
+       if (symbol != NULL) {
+               environment_push(declaration);
        }
+       append_declaration(declaration);
 
        type_t *const type      = allocate_type_zero(TYPE_ENUM, &declaration->source_position);
        type->enumt.declaration = declaration;
 
        if (token.type == '{') {
                if (declaration->init.complete) {
-                       errorf(HERE, "multiple definitions of enum %Y", symbol);
+                       errorf(HERE, "multiple definitions of enum '%Y' (previous definition at %P)",
+                              symbol, &declaration->source_position);
                }
-               if (symbol != NULL) {
-                       environment_push(declaration);
-               }
-               append_declaration(declaration);
                declaration->init.complete = true;
 
                parse_enum_entries(type);
@@ -3065,16 +3113,112 @@ static declaration_t *create_error_declaration(symbol_t *symbol, storage_class_t
 {
        declaration_t *const decl    = allocate_declaration_zero();
        decl->source_position        = *HERE;
+       decl->declared_storage_class = storage_class;
        decl->storage_class          =
                storage_class != STORAGE_CLASS_NONE || scope == global_scope ?
                        storage_class : STORAGE_CLASS_AUTO;
-       decl->declared_storage_class = decl->storage_class;
        decl->symbol                 = symbol;
        decl->implicit               = true;
-       record_declaration(decl);
+       record_declaration(decl, false);
        return decl;
 }
 
+/**
+ * Finish the construction of a struct type by calculating
+ * its size, offsets, alignment.
+ */
+static void finish_struct_type(compound_type_t *type) {
+       if (type->declaration == NULL)
+               return;
+       declaration_t *struct_decl = type->declaration;
+       if (! struct_decl->init.complete)
+               return;
+
+       il_size_t      size           = 0;
+       il_size_t      offset;
+       il_alignment_t alignment      = 1;
+       bool           need_pad       = false;
+
+       declaration_t *entry = struct_decl->scope.declarations;
+       for (; entry != NULL; entry = entry->next) {
+               if (entry->namespc != NAMESPACE_NORMAL)
+                       continue;
+
+               type_t *m_type = skip_typeref(entry->type);
+               if (! is_type_valid(m_type)) {
+                       /* simply ignore errors here */
+                       continue;
+               }
+               il_alignment_t m_alignment = m_type->base.alignment;
+               if (m_alignment > alignment)
+                       alignment = m_alignment;
+
+               offset = (size + m_alignment - 1) & -m_alignment;
+
+               if (offset > size)
+                       need_pad = true;
+               entry->offset = offset;
+               size = offset + m_type->base.size;
+       }
+       if (type->base.alignment != 0) {
+               alignment = type->base.alignment;
+       }
+
+       offset = (size + alignment - 1) & -alignment;
+       if (offset > size)
+               need_pad = true;
+
+       if (warning.padded && need_pad) {
+               warningf(&struct_decl->source_position,
+                       "'%#T' needs padding", type, struct_decl->symbol);
+       }
+       if (warning.packed && !need_pad) {
+               warningf(&struct_decl->source_position,
+                       "superfluous packed attribute on '%#T'",
+                       type, struct_decl->symbol);
+       }
+
+       type->base.size      = offset;
+       type->base.alignment = alignment;
+}
+
+/**
+ * Finish the construction of an union type by calculating
+ * its size and alignment.
+ */
+static void finish_union_type(compound_type_t *type) {
+       if (type->declaration == NULL)
+               return;
+       declaration_t *union_decl = type->declaration;
+       if (! union_decl->init.complete)
+               return;
+
+       il_size_t      size      = 0;
+       il_alignment_t alignment = 1;
+
+       declaration_t *entry = union_decl->scope.declarations;
+       for (; entry != NULL; entry = entry->next) {
+               if (entry->namespc != NAMESPACE_NORMAL)
+                       continue;
+
+               type_t *m_type = skip_typeref(entry->type);
+               if (! is_type_valid(m_type))
+                       continue;
+
+               entry->offset = 0;
+               if (m_type->base.size > size)
+                       size = m_type->base.size;
+               if (m_type->base.alignment > alignment)
+                       alignment = m_type->base.alignment;
+       }
+       if (type->base.alignment != 0) {
+               alignment = type->base.alignment;
+       }
+       size = (size + alignment - 1) & -alignment;
+       type->base.size      = size;
+       type->base.alignment = alignment;
+}
+
 static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
 {
        type_t            *type            = NULL;
@@ -3214,6 +3358,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        type = allocate_type_zero(TYPE_COMPOUND_STRUCT, HERE);
 
                        type->compound.declaration = parse_compound_type_specifier(true);
+                       finish_struct_type(&type->compound);
                        break;
                }
                case T_union: {
@@ -3222,6 +3367,7 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        if (type->compound.declaration->modifiers & DM_TRANSPARENT_UNION)
                                modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
                        break;
+                       finish_union_type(&type->compound);
                }
                case T_enum:
                        type = parse_enum_specifier();
@@ -3578,7 +3724,7 @@ static void semantic_parameter(declaration_t *declaration)
        declaration->type = type;
 
        if (is_type_incomplete(skip_typeref(type))) {
-               errorf(pos, "incomplete type '%T' not allowed for parameter '%Y'",
+               errorf(pos, "parameter '%#T' is of incomplete type",
                       orig_type, declaration->symbol);
        }
 }
@@ -3605,7 +3751,7 @@ static declaration_t *parse_parameters(function_type_t *type)
 
        if (token.type == T_IDENTIFIER &&
            !is_typedef_symbol(token.v.symbol)) {
-               token_type_t la1_type = look_ahead(1)->type;
+               token_type_t la1_type = (token_type_t)look_ahead(1)->type;
                if (la1_type == ',' || la1_type == ')') {
                        type->kr_style_parameters = true;
                        declarations = parse_identifier_list();
@@ -3896,8 +4042,10 @@ static construct_type_t *parse_inner_declarator(declaration_t *declaration,
                next_token();
                add_anchor_token(')');
                inner_types = parse_inner_declarator(declaration, may_be_abstract);
-               /* All later declarators only modify the return type, not declaration */
-               declaration = NULL;
+               if (inner_types != NULL) {
+                       /* All later declarators only modify the return type, not declaration */
+                       declaration = NULL;
+               }
                rem_anchor_token(')');
                expect(')');
                break;
@@ -4206,7 +4354,7 @@ static bool is_sym_main(const symbol_t *const sym)
        return strcmp(sym->string, "main") == 0;
 }
 
-static declaration_t *internal_record_declaration(
+static declaration_t *record_declaration(
        declaration_t *const declaration,
        const bool is_definition)
 {
@@ -4314,8 +4462,9 @@ static declaration_t *internal_record_declaration(
                        if (old_storage_class == STORAGE_CLASS_EXTERN &&
                                        new_storage_class == STORAGE_CLASS_EXTERN) {
 warn_redundant_declaration:
-                               if (!is_definition          &&
-                                   warning.redundant_decls &&
+                               if (!is_definition           &&
+                                   warning.redundant_decls  &&
+                                   is_type_valid(prev_type) &&
                                    strcmp(previous_declaration->source_position.input_name, "<builtin>") != 0) {
                                        warningf(&declaration->source_position,
                                                 "redundant declaration for '%Y' (declared %P)",
@@ -4333,14 +4482,16 @@ warn_redundant_declaration:
                                } else {
                                        goto warn_redundant_declaration;
                                }
-                       } else if (old_storage_class == new_storage_class) {
-                               errorf(&declaration->source_position,
-                                      "redeclaration of '%Y' (declared %P)",
-                                      symbol, &previous_declaration->source_position);
-                       } else {
-                               errorf(&declaration->source_position,
-                                      "redeclaration of '%Y' with different linkage (declared %P)",
-                                      symbol, &previous_declaration->source_position);
+                       } else if (is_type_valid(prev_type)) {
+                               if (old_storage_class == new_storage_class) {
+                                       errorf(&declaration->source_position,
+                                              "redeclaration of '%Y' (declared %P)",
+                                              symbol, &previous_declaration->source_position);
+                               } else {
+                                       errorf(&declaration->source_position,
+                                              "redeclaration of '%Y' with different linkage (declared %P)",
+                                              symbol, &previous_declaration->source_position);
+                               }
                        }
                }
 
@@ -4379,16 +4530,6 @@ warn_redundant_declaration:
        return append_declaration(declaration);
 }
 
-static declaration_t *record_declaration(declaration_t *declaration)
-{
-       return internal_record_declaration(declaration, false);
-}
-
-static declaration_t *record_definition(declaration_t *declaration)
-{
-       return internal_record_declaration(declaration, true);
-}
-
 static void parser_error_multiple_definition(declaration_t *declaration,
                const source_position_t *source_position)
 {
@@ -4433,53 +4574,55 @@ static void parse_init_declarator_rest(declaration_t *declaration)
                must_be_constant = true;
        }
 
+       if (is_type_function(type)) {
+               errorf(&declaration->source_position,
+                      "function '%#T' is initialized like a variable",
+                      orig_type, declaration->symbol);
+               orig_type = type_error_type;
+       }
+
        parse_initializer_env_t env;
        env.type             = orig_type;
        env.must_be_constant = must_be_constant;
-       env.declaration      = declaration;
+       env.declaration      = current_init_decl = declaration;
 
        initializer_t *initializer = parse_initializer(&env);
+       current_init_decl = NULL;
 
-       if (env.type != orig_type) {
-               orig_type         = env.type;
-               type              = skip_typeref(orig_type);
-               declaration->type = env.type;
-       }
-
-       if (is_type_function(type)) {
-               errorf(&declaration->source_position,
-                      "initializers not allowed for function types at declator '%Y' (type '%T')",
-                      declaration->symbol, orig_type);
-       } else {
+       if (!is_type_function(type)) {
+               /* Â§ 6.7.5 (22)  array initializers for arrays with unknown size determine
+                * the array type size */
+               declaration->type             = env.type;
                declaration->init.initializer = initializer;
        }
 }
 
 /* parse rest of a declaration without any declarator */
 static void parse_anonymous_declaration_rest(
-               const declaration_specifiers_t *specifiers,
-               parsed_declaration_func finished_declaration)
+               const declaration_specifiers_t *specifiers)
 {
        eat(';');
 
+       if (specifiers->declared_storage_class != STORAGE_CLASS_NONE) {
+               warningf(&specifiers->source_position,
+                       "useless storage class in empty declaration");
+       }
+
+#ifdef RECORD_EMPTY_DECLARARTIONS
        declaration_t *const declaration    = allocate_declaration_zero();
        declaration->type                   = specifiers->type;
        declaration->declared_storage_class = specifiers->declared_storage_class;
        declaration->source_position        = specifiers->source_position;
        declaration->modifiers              = specifiers->modifiers;
+       declaration->storage_class          = STORAGE_CLASS_NONE;
+#endif
 
-       if (declaration->declared_storage_class != STORAGE_CLASS_NONE) {
-               warningf(&declaration->source_position,
-                        "useless storage class in empty declaration");
-       }
-       declaration->storage_class = STORAGE_CLASS_NONE;
-
-       type_t *type = declaration->type;
+       type_t *type = specifiers->type;
        switch (type->kind) {
                case TYPE_COMPOUND_STRUCT:
                case TYPE_COMPOUND_UNION: {
                        if (type->compound.declaration->symbol == NULL) {
-                               warningf(&declaration->source_position,
+                               warningf(&specifiers->source_position,
                                         "unnamed struct/union that defines no instances");
                        }
                        break;
@@ -4489,11 +4632,13 @@ static void parse_anonymous_declaration_rest(
                        break;
 
                default:
-                       warningf(&declaration->source_position, "empty declaration");
+                       warningf(&specifiers->source_position, "empty declaration");
                        break;
        }
 
-       finished_declaration(declaration);
+#ifdef RECORD_EMPTY_DECLARARTIONS
+       append_declaration(declaration);
+#endif
 }
 
 static void parse_declaration_rest(declaration_t *ndeclaration,
@@ -4504,7 +4649,8 @@ static void parse_declaration_rest(declaration_t *ndeclaration,
        add_anchor_token('=');
        add_anchor_token(',');
        while(true) {
-               declaration_t *declaration = finished_declaration(ndeclaration);
+               declaration_t *declaration =
+                       finished_declaration(ndeclaration, token.type == '=');
 
                type_t *orig_type = declaration->type;
                type_t *type      = skip_typeref(orig_type);
@@ -4534,7 +4680,7 @@ end_error:
        rem_anchor_token(',');
 }
 
-static declaration_t *finished_kr_declaration(declaration_t *declaration)
+static declaration_t *finished_kr_declaration(declaration_t *declaration, bool is_definition)
 {
        symbol_t *symbol  = declaration->symbol;
        if (symbol == NULL) {
@@ -4543,7 +4689,7 @@ static declaration_t *finished_kr_declaration(declaration_t *declaration)
        }
        namespace_t namespc = (namespace_t) declaration->namespc;
        if (namespc != NAMESPACE_NORMAL) {
-               return record_declaration(declaration);
+               return record_declaration(declaration, false);
        }
 
        declaration_t *previous_declaration = get_declaration(symbol, namespc);
@@ -4554,6 +4700,10 @@ static declaration_t *finished_kr_declaration(declaration_t *declaration)
                return declaration;
        }
 
+       if (is_definition) {
+               errorf(HERE, "parameter %Y is initialised", declaration->symbol);
+       }
+
        if (previous_declaration->type == NULL) {
                previous_declaration->type          = declaration->type;
                previous_declaration->declared_storage_class = declaration->declared_storage_class;
@@ -4561,7 +4711,7 @@ static declaration_t *finished_kr_declaration(declaration_t *declaration)
                previous_declaration->parent_scope  = scope;
                return previous_declaration;
        } else {
-               return record_declaration(declaration);
+               return record_declaration(declaration, false);
        }
 }
 
@@ -4572,7 +4722,7 @@ static void parse_declaration(parsed_declaration_func finished_declaration)
        parse_declaration_specifiers(&specifiers);
 
        if (token.type == ';') {
-               parse_anonymous_declaration_rest(&specifiers, append_declaration);
+               parse_anonymous_declaration_rest(&specifiers);
        } else {
                declaration_t *declaration = parse_declarator(&specifiers, /*may_be_abstract=*/false);
                parse_declaration_rest(declaration, &specifiers, finished_declaration);
@@ -4707,6 +4857,10 @@ static void check_labels(void)
        for (const goto_statement_t *goto_statement = goto_first;
            goto_statement != NULL;
            goto_statement = goto_statement->next) {
+               /* skip computed gotos */
+               if (goto_statement->expression != NULL)
+                       continue;
+
                declaration_t *label = goto_statement->label;
 
                label->used = true;
@@ -4912,9 +5066,16 @@ found_break_parent:
                }
 
                case STATEMENT_GOTO:
-                       next = stmt->gotos.label->init.statement;
-                       if (next == NULL) /* missing label */
-                               return;
+                       if (stmt->gotos.expression) {
+                               statement_t *parent = stmt->base.parent;
+                               if (parent == NULL) /* top level goto */
+                                       return;
+                               next = parent;
+                       } else {
+                               next = stmt->gotos.label->init.statement;
+                               if (next == NULL) /* missing label */
+                                       return;
+                       }
                        break;
 
                case STATEMENT_LABEL:
@@ -5222,7 +5383,7 @@ static void parse_external_declaration(void)
 
        /* must be a declaration */
        if (token.type == ';') {
-               parse_anonymous_declaration_rest(&specifiers, append_declaration);
+               parse_anonymous_declaration_rest(&specifiers);
                return;
        }
 
@@ -5241,11 +5402,8 @@ static void parse_external_declaration(void)
        switch (token.type) {
                case ',':
                case ';':
-                       parse_declaration_rest(ndeclaration, &specifiers, record_declaration);
-                       return;
-
                case '=':
-                       parse_declaration_rest(ndeclaration, &specifiers, record_definition);
+                       parse_declaration_rest(ndeclaration, &specifiers, record_declaration);
                        return;
        }
 
@@ -5276,6 +5434,14 @@ static void parse_external_declaration(void)
                warningf(HERE, "function '%Y' returns an aggregate",
                         ndeclaration->symbol);
        }
+       if (warning.traditional && !type->function.unspecified_parameters) {
+               warningf(HERE, "traditional C rejects ISO C style function definition of function '%Y'",
+                       ndeclaration->symbol);
+       }
+       if (warning.old_style_definition && type->function.unspecified_parameters) {
+               warningf(HERE, "old-style function definition '%Y'",
+                       ndeclaration->symbol);
+       }
 
        /* Â§ 6.7.5.3 (14) a function definition with () means no
         * parameters (and not unspecified parameters) */
@@ -5292,7 +5458,7 @@ static void parse_external_declaration(void)
                ndeclaration->type = type;
        }
 
-       declaration_t *const declaration = record_definition(ndeclaration);
+       declaration_t *const declaration = record_declaration(ndeclaration, true);
        if (ndeclaration != declaration) {
                declaration->scope = ndeclaration->scope;
        }
@@ -5361,12 +5527,40 @@ static void parse_external_declaration(void)
 }
 
 static type_t *make_bitfield_type(type_t *base_type, expression_t *size,
-                                  source_position_t *source_position)
+                                  source_position_t *source_position,
+                                  const symbol_t *symbol)
 {
        type_t *type = allocate_type_zero(TYPE_BITFIELD, source_position);
 
-       type->bitfield.base_type = base_type;
-       type->bitfield.size      = size;
+       type->bitfield.base_type       = base_type;
+       type->bitfield.size_expression = size;
+
+       il_size_t bit_size;
+       type_t *skipped_type = skip_typeref(base_type);
+       if (!is_type_integer(skipped_type)) {
+               errorf(HERE, "bitfield base type '%T' is not an integer type",
+                       base_type);
+               bit_size = 0;
+       } else {
+               bit_size = skipped_type->base.size * 8;
+       }
+
+       if (is_constant_expression(size)) {
+               long v = fold_constant(size);
+
+               if (v < 0) {
+                       errorf(source_position, "negative width in bit-field '%Y'",
+                               symbol);
+               } else if (v == 0) {
+                       errorf(source_position, "zero width for bit-field '%Y'",
+                               symbol);
+               } else if (bit_size > 0 && (il_size_t)v > bit_size) {
+                       errorf(source_position, "width of '%Y' exceeds its type",
+                               symbol);
+               } else {
+                       type->bitfield.bit_size = v;
+               }
+       }
 
        return type;
 }
@@ -5403,12 +5597,12 @@ static void parse_compound_declarators(declaration_t *struct_declaration,
 {
        declaration_t *last_declaration = struct_declaration->scope.declarations;
        if (last_declaration != NULL) {
-               while(last_declaration->next != NULL) {
+               while (last_declaration->next != NULL) {
                        last_declaration = last_declaration->next;
                }
        }
 
-       while(1) {
+       while (true) {
                declaration_t *declaration;
 
                if (token.type == ':') {
@@ -5418,12 +5612,8 @@ static void parse_compound_declarators(declaration_t *struct_declaration,
                        type_t *base_type = specifiers->type;
                        expression_t *size = parse_constant_expression();
 
-                       if (!is_type_integer(skip_typeref(base_type))) {
-                               errorf(HERE, "bitfield base type '%T' is not an integer type",
-                                      base_type);
-                       }
-
-                       type_t *type = make_bitfield_type(base_type, size, &source_position);
+                       type_t *type = make_bitfield_type(base_type, size,
+                                       &source_position, sym_anonymous);
 
                        declaration                         = allocate_declaration_zero();
                        declaration->namespc                = NAMESPACE_NORMAL;
@@ -5443,12 +5633,8 @@ static void parse_compound_declarators(declaration_t *struct_declaration,
                                next_token();
                                expression_t *size = parse_constant_expression();
 
-                               if (!is_type_integer(type)) {
-                                       errorf(HERE, "bitfield base type '%T' is not an "
-                                              "integer type", orig_type);
-                               }
-
-                               type_t *bitfield_type = make_bitfield_type(orig_type, size, &source_position);
+                               type_t *bitfield_type = make_bitfield_type(orig_type, size,
+                                               &source_position, declaration->symbol);
                                declaration->type = bitfield_type;
                        } else {
                                /* TODO we ignore arrays for now... what is missing is a check
@@ -5458,8 +5644,8 @@ static void parse_compound_declarators(declaration_t *struct_declaration,
                                               "compound member '%Y' has incomplete type '%T'",
                                               declaration->symbol, orig_type);
                                } else if (is_type_function(type)) {
-                                       errorf(HERE, "compound member '%Y' must not have function "
-                                              "type '%T'", declaration->symbol, orig_type);
+                                       errorf(HERE, "compound member '%Y' must not have function type '%T'",
+                                              declaration->symbol, orig_type);
                                }
                        }
                }
@@ -5501,7 +5687,7 @@ static void parse_compound_type_entries(declaration_t *compound_declaration)
        eat('{');
        add_anchor_token('}');
 
-       while(token.type != '}' && token.type != T_EOF) {
+       while (token.type != '}' && token.type != T_EOF) {
                declaration_specifiers_t specifiers;
                memset(&specifiers, 0, sizeof(specifiers));
                parse_declaration_specifiers(&specifiers);
@@ -5713,7 +5899,7 @@ static declaration_t *create_implicit_function(symbol_t *symbol,
 
        bool strict_prototypes_old = warning.strict_prototypes;
        warning.strict_prototypes  = false;
-       record_declaration(declaration);
+       record_declaration(declaration, false);
        warning.strict_prototypes = strict_prototypes_old;
 
        return declaration;
@@ -5847,7 +6033,10 @@ type_t *revert_automatic_type_conversion(const expression_t *expression)
 {
        switch (expression->kind) {
                case EXPR_REFERENCE: return expression->reference.declaration->type;
-               case EXPR_SELECT:    return expression->select.compound_entry->type;
+
+               case EXPR_SELECT:
+                       return get_qualified_type(expression->select.compound_entry->type,
+                                                 expression->base.type->base.qualifiers);
 
                case EXPR_UNARY_DEREFERENCE: {
                        const expression_t *const value = expression->unary.value;
@@ -5896,21 +6085,15 @@ static expression_t *parse_reference(void)
 
        declaration_t *declaration = get_declaration(symbol, NAMESPACE_NORMAL);
 
-       source_position_t source_position = token.source_position;
-       next_token();
-
        if (declaration == NULL) {
-               if (token.type == '(') {
+               if (!strict_mode && look_ahead(1)->type == '(') {
                        /* an implicitly declared function */
-                       if (strict_mode) {
-                               errorf(HERE, "unknown symbol '%Y' found.", symbol);
-                       } else if (warning.implicit_function_declaration) {
+                       if (warning.implicit_function_declaration) {
                                warningf(HERE, "implicit declaration of function '%Y'",
                                        symbol);
                        }
 
-                       declaration = create_implicit_function(symbol,
-                                                              &source_position);
+                       declaration = create_implicit_function(symbol, HERE);
                } else {
                        errorf(HERE, "unknown symbol '%Y' found.", symbol);
                        declaration = create_error_declaration(symbol, STORAGE_CLASS_NONE);
@@ -5936,17 +6119,21 @@ static expression_t *parse_reference(void)
                        "function" : "variable";
 
                if (declaration->deprecated_string != NULL) {
-                       warningf(&source_position,
-                               "%s '%Y' is deprecated (declared %P): \"%s\"", prefix,
-                               declaration->symbol, &declaration->source_position,
+                       warningf(HERE, "%s '%Y' is deprecated (declared %P): \"%s\"",
+                               prefix, declaration->symbol, &declaration->source_position,
                                declaration->deprecated_string);
                } else {
-                       warningf(&source_position,
-                               "%s '%Y' is deprecated (declared %P)", prefix,
+                       warningf(HERE, "%s '%Y' is deprecated (declared %P)", prefix,
                                declaration->symbol, &declaration->source_position);
                }
        }
+       if (warning.init_self && declaration == current_init_decl) {
+               current_init_decl = NULL;
+               warningf(HERE, "variable '%#T' is initialized by itself",
+                       declaration->type, declaration->symbol);
+       }
 
+       next_token();
        return expression;
 }
 
@@ -6493,6 +6680,71 @@ end_error:
        return create_invalid_expression();
 }
 
+/**
+ * Return the declaration for a given label symbol or create a new one.
+ *
+ * @param symbol  the symbol of the label
+ */
+static declaration_t *get_label(symbol_t *symbol)
+{
+       declaration_t *candidate;
+       assert(current_function != NULL);
+
+       candidate = get_declaration(symbol, NAMESPACE_LOCAL_LABEL);
+       /* if we found a local label, we already created the declaration */
+       if (candidate != NULL) {
+               assert(candidate->parent_scope == scope);
+               return candidate;
+       }
+
+       candidate = get_declaration(symbol, NAMESPACE_LABEL);
+       /* if we found a label in the same function, then we already created the
+        * declaration */
+       if (candidate != NULL
+                       && candidate->parent_scope == &current_function->scope) {
+               return candidate;
+       }
+
+       /* otherwise we need to create a new one */
+       declaration_t *const declaration = allocate_declaration_zero();
+       declaration->namespc       = NAMESPACE_LABEL;
+       declaration->symbol        = symbol;
+
+       label_push(declaration);
+
+       return declaration;
+}
+
+/**
+ * Parses a GNU && label address expression.
+ */
+static expression_t *parse_label_address(void)
+{
+       source_position_t source_position = token.source_position;
+       eat(T_ANDAND);
+       if (token.type != T_IDENTIFIER) {
+               parse_error_expected("while parsing label address", T_IDENTIFIER, NULL);
+               goto end_error;
+       }
+       symbol_t *symbol = token.v.symbol;
+       next_token();
+
+       declaration_t *label = get_label(symbol);
+
+       label->used          = true;
+       label->address_taken = true;
+
+       expression_t *expression = allocate_expression_zero(EXPR_LABEL_ADDRESS);
+       expression->base.source_position = source_position;
+
+       /* label address is threaten as a void pointer */
+       expression->base.type                 = type_void_ptr;
+       expression->label_address.declaration = label;
+       return expression;
+end_error:
+       return create_invalid_expression();
+}
+
 /**
  * Parse a microsoft __noop expression.
  */
@@ -6570,6 +6822,10 @@ static expression_t *parse_primary_expression(void)
                case T___builtin_constant_p:     return parse_builtin_constant();
                case T___builtin_prefetch:       return parse_builtin_prefetch();
                case T__assume:                  return parse_assume();
+               case T_ANDAND:
+                       if (c_mode & _GNUC)
+                               return parse_label_address();
+                       break;
 
                case '(':                        return parse_parenthesized_expression();
                case T___noop:                   return parse_noop_expression();
@@ -6633,19 +6889,18 @@ static expression_t *parse_array_expression(unsigned precedence,
                                orig_type_left, orig_type_inside);
                }
                return_type             = type_error_type;
-               array_access->array_ref = create_invalid_expression();
+               array_access->array_ref = left;
+               array_access->index     = inside;
        }
 
+       expression->base.type = automatic_type_conversion(return_type);
+
        rem_anchor_token(']');
-       if (token.type != ']') {
+       if (token.type == ']') {
+               next_token();
+       } else {
                parse_error_expected("Problem while parsing array access", ']', NULL);
-               return expression;
        }
-       next_token();
-
-       return_type           = automatic_type_conversion(return_type);
-       expression->base.type = return_type;
-
        return expression;
 }
 
@@ -6733,56 +6988,67 @@ static expression_t *parse_select_expression(unsigned precedence,
                parse_error_expected("while parsing select", T_IDENTIFIER, NULL);
                return select;
        }
-       symbol_t *symbol      = token.v.symbol;
-       select->select.symbol = symbol;
+       symbol_t *symbol = token.v.symbol;
        next_token();
 
        type_t *const orig_type = compound->base.type;
        type_t *const type      = skip_typeref(orig_type);
 
-       type_t *type_left = type;
-       if (is_pointer) {
-               if (!is_type_pointer(type)) {
-                       if (is_type_valid(type)) {
-                               errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type);
-                       }
-                       return create_invalid_expression();
+       type_t *type_left;
+       bool    saw_error = false;
+       if (is_type_pointer(type)) {
+               if (!is_pointer) {
+                       errorf(HERE,
+                              "request for member '%Y' in something not a struct or union, but '%T'",
+                              symbol, orig_type);
+                       saw_error = true;
                }
-               type_left = type->pointer.points_to;
-       }
-       type_left = skip_typeref(type_left);
-
-       if (type_left->kind != TYPE_COMPOUND_STRUCT &&
-           type_left->kind != TYPE_COMPOUND_UNION) {
-               if (is_type_valid(type_left)) {
-                       errorf(HERE, "request for member '%Y' in something not a struct or "
-                              "union, but '%T'", symbol, type_left);
+               type_left = skip_typeref(type->pointer.points_to);
+       } else {
+               if (is_pointer && is_type_valid(type)) {
+                       errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type);
+                       saw_error = true;
                }
-               return create_invalid_expression();
+               type_left = type;
        }
 
-       declaration_t *const declaration = type_left->compound.declaration;
+       declaration_t *entry;
+       if (type_left->kind == TYPE_COMPOUND_STRUCT ||
+           type_left->kind == TYPE_COMPOUND_UNION) {
+               declaration_t *const declaration = type_left->compound.declaration;
 
-       if (!declaration->init.complete) {
-               errorf(HERE, "request for member '%Y' of incomplete type '%T'",
-                      symbol, type_left);
-               return create_invalid_expression();
-       }
+               if (!declaration->init.complete) {
+                       errorf(HERE, "request for member '%Y' of incomplete type '%T'",
+                              symbol, type_left);
+                       goto create_error_entry;
+               }
 
-       declaration_t *iter = find_compound_entry(declaration, symbol);
-       if (iter == NULL) {
-               errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol);
-               return create_invalid_expression();
+               entry = find_compound_entry(declaration, symbol);
+               if (entry == NULL) {
+                       errorf(HERE, "'%T' has no member named '%Y'", orig_type, symbol);
+                       goto create_error_entry;
+               }
+       } else {
+               if (is_type_valid(type_left) && !saw_error) {
+                       errorf(HERE,
+                              "request for member '%Y' in something not a struct or union, but '%T'",
+                              symbol, type_left);
+               }
+create_error_entry:
+               entry         = allocate_declaration_zero();
+               entry->symbol = symbol;
        }
 
+       select->select.compound_entry = entry;
+
+       type_t *const res_type =
+               get_qualified_type(entry->type, type_left->base.qualifiers);
+
        /* we always do the auto-type conversions; the & and sizeof parser contains
         * code to revert this! */
-       type_t *expression_type = automatic_type_conversion(iter->type);
+       select->base.type = automatic_type_conversion(res_type);
 
-       select->select.compound_entry = iter;
-       select->base.type             = expression_type;
-
-       type_t *skipped = skip_typeref(iter->type);
+       type_t *skipped = skip_typeref(res_type);
        if (skipped->kind == TYPE_BITFIELD) {
                select->base.type = skipped->bitfield.base_type;
        }
@@ -6791,12 +7057,13 @@ static expression_t *parse_select_expression(unsigned precedence,
 }
 
 static void check_call_argument(const function_parameter_t *parameter,
-                                call_argument_t *argument)
+                                call_argument_t *argument, unsigned pos)
 {
        type_t         *expected_type      = parameter->type;
        type_t         *expected_type_skip = skip_typeref(expected_type);
        assign_error_t  error              = ASSIGN_ERROR_INCOMPATIBLE;
        expression_t   *arg_expr           = argument->expression;
+       type_t         *arg_type           = skip_typeref(arg_expr->base.type);
 
        /* handle transparent union gnu extension */
        if (is_type_union(expected_type_skip)
@@ -6829,9 +7096,23 @@ static void check_call_argument(const function_parameter_t *parameter,
        argument->expression = create_implicit_cast(argument->expression,
                                                    expected_type);
 
-       /* TODO report exact scope in error messages (like "in 3rd parameter") */
-       report_assign_error(error, expected_type, arg_expr,     "function call",
-                           &arg_expr->base.source_position);
+       if (error != ASSIGN_SUCCESS) {
+               /* 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);
+       } 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) &&
+                   !types_compatible(expected_type_skip, type_void_ptr) &&
+                   !types_compatible(type_void_ptr,      promoted_type)) {
+                       /* Deliberately show the skipped types in this warning */
+                       warningf(&arg_expr->base.source_position,
+                               "passing call argument %u as '%T' rather than '%T' due to prototype",
+                               pos, expected_type_skip, promoted_type);
+               }
+       }
 }
 
 /**
@@ -6874,7 +7155,7 @@ static expression_t *parse_call_expression(unsigned precedence,
        if (token.type != ')') {
                call_argument_t *last_argument = NULL;
 
-               while(true) {
+               while (true) {
                        call_argument_t *argument = allocate_ast_zero(sizeof(argument[0]));
 
                        argument->expression = parse_assignment_expression();
@@ -6900,9 +7181,9 @@ static expression_t *parse_call_expression(unsigned precedence,
        function_parameter_t *parameter = function_type->parameters;
        call_argument_t      *argument  = call->arguments;
        if (!function_type->unspecified_parameters) {
-               for; parameter != NULL && argument != NULL;
+               for (unsigned pos = 0; parameter != NULL && argument != NULL;
                                parameter = parameter->next, argument = argument->next) {
-                       check_call_argument(parameter, argument);
+                       check_call_argument(parameter, argument, ++pos);
                }
 
                if (parameter != NULL) {
@@ -7043,13 +7324,8 @@ static expression_t *parse_conditional_expression(unsigned precedence,
                                to = type_void;
                        }
 
-                       type_t *const copy = duplicate_type(to);
-                       copy->base.qualifiers = to1->base.qualifiers | to2->base.qualifiers;
-
-                       type_t *const type = typehash_insert(copy);
-                       if (type != copy)
-                               free_type(copy);
-
+                       type_t *const type =
+                               get_qualified_type(to, to1->base.qualifiers | to2->base.qualifiers);
                        result_type = make_pointer_type(type, TYPE_QUALIFIER_NONE);
                } else if (is_type_integer(other_type)) {
                        warningf(&conditional->base.source_position,
@@ -7149,6 +7425,20 @@ static bool check_pointer_arithmetic(const source_position_t *source_position,
        return true;
 }
 
+static bool is_lvalue(const expression_t *expression)
+{
+       switch (expression->kind) {
+       case EXPR_REFERENCE:
+       case EXPR_ARRAY_ACCESS:
+       case EXPR_SELECT:
+       case EXPR_UNARY_DEREFERENCE:
+               return true;
+
+       default:
+               return false;
+       }
+}
+
 static void semantic_incdec(unary_expression_t *expression)
 {
        type_t *const orig_type = expression->value->base.type;
@@ -7164,6 +7454,10 @@ static void semantic_incdec(unary_expression_t *expression)
                       "operation needs an arithmetic or pointer type");
                return;
        }
+       if (!is_lvalue(expression->value)) {
+               /* TODO: improve error message */
+               errorf(&expression->base.source_position, "lvalue required as operand");
+       }
        expression->base.type = orig_type;
 }
 
@@ -7175,7 +7469,7 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression)
                if (is_type_valid(type)) {
                        /* TODO: improve error message */
                        errorf(&expression->base.source_position,
-                              "operation needs an arithmetic type");
+                               "operation needs an arithmetic type");
                }
                return;
        }
@@ -7183,6 +7477,14 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression)
        expression->base.type = orig_type;
 }
 
+static void semantic_unexpr_plus(unary_expression_t *expression)
+{
+       semantic_unexpr_arithmetic(expression);
+       if (warning.traditional)
+               warningf(&expression->base.source_position,
+                       "traditional C rejects the unary plus operator");
+}
+
 static void semantic_not(unary_expression_t *expression)
 {
        type_t *const orig_type = expression->value->base.type;
@@ -7217,7 +7519,7 @@ static void semantic_dereference(unary_expression_t *expression)
        if (!is_type_pointer(type)) {
                if (is_type_valid(type)) {
                        errorf(&expression->base.source_position,
-                              "Unary '*' needs pointer or arrray type, but type '%T' given", orig_type);
+                              "Unary '*' needs pointer or array type, but type '%T' given", orig_type);
                }
                return;
        }
@@ -7227,6 +7529,12 @@ static void semantic_dereference(unary_expression_t *expression)
        expression->base.type = result_type;
 }
 
+/**
+ * Record that an address is taken (expression represents an lvalue).
+ *
+ * @param expression       the expression
+ * @param may_be_register  if true, the expression might be an register
+ */
 static void set_address_taken(expression_t *expression, bool may_be_register)
 {
        if (expression->kind != EXPR_REFERENCE)
@@ -7280,7 +7588,7 @@ static expression_t *parse_##unexpression_type(unsigned precedence)            \
 CREATE_UNARY_EXPRESSION_PARSER('-', EXPR_UNARY_NEGATE,
                                semantic_unexpr_arithmetic)
 CREATE_UNARY_EXPRESSION_PARSER('+', EXPR_UNARY_PLUS,
-                               semantic_unexpr_arithmetic)
+                               semantic_unexpr_plus)
 CREATE_UNARY_EXPRESSION_PARSER('!', EXPR_UNARY_NOT,
                                semantic_not)
 CREATE_UNARY_EXPRESSION_PARSER('*', EXPR_UNARY_DEREFERENCE,
@@ -7323,6 +7631,9 @@ static type_t *semantic_arithmetic(type_t *type_left, type_t *type_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;
@@ -7409,10 +7720,15 @@ static void semantic_binexpr_arithmetic(binary_expression_t *expression)
 
 static void warn_div_by_zero(binary_expression_t const *const expression)
 {
-       if (warning.div_by_zero                       &&
-           is_type_integer(expression->base.type)    &&
-           is_constant_expression(expression->right) &&
-           fold_constant(expression->right) == 0) {
+       if (!warning.div_by_zero ||
+           !is_type_integer(expression->base.type))
+               return;
+
+       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)     &&
+           fold_constant(right) == 0) {
                warningf(&expression->base.source_position, "division by zero");
        }
 }
@@ -7617,20 +7933,6 @@ static bool has_const_fields(const compound_type_t *type)
        return false;
 }
 
-static bool is_lvalue(const expression_t *expression)
-{
-       switch (expression->kind) {
-       case EXPR_REFERENCE:
-       case EXPR_ARRAY_ACCESS:
-       case EXPR_SELECT:
-       case EXPR_UNARY_DEREFERENCE:
-               return true;
-
-       default:
-               return false;
-       }
-}
-
 static bool is_valid_assignment_lhs(expression_t const* const left)
 {
        type_t *const orig_type_left = revert_automatic_type_conversion(left);
@@ -7765,9 +8067,6 @@ static void semantic_binexpr_assign(binary_expression_t *expression)
        expression_t *left           = expression->left;
        type_t       *orig_type_left = left->base.type;
 
-       type_t *type_left = revert_automatic_type_conversion(left);
-       type_left         = skip_typeref(orig_type_left);
-
        if (!is_valid_assignment_lhs(left))
                return;
 
@@ -7802,6 +8101,7 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_WIDE_CHARACTER_CONSTANT:   return false;
                case EXPR_STRING_LITERAL:            return false;
                case EXPR_WIDE_STRING_LITERAL:       return false;
+               case EXPR_LABEL_ADDRESS:             return false;
 
                case EXPR_CALL: {
                        const call_expression_t *const call = &expr->call;
@@ -8354,12 +8654,18 @@ static statement_t *parse_case_statement(void)
        source_position_t *const pos       = &statement->base.source_position;
 
        *pos                             = token.source_position;
-       statement->case_label.expression = parse_expression();
-       if (! is_constant_expression(statement->case_label.expression)) {
-               errorf(pos, "case label does not reduce to an integer constant");
+       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(expression->base.type)) {
+                       errorf(pos, "case label does not reduce to an integer constant");
+               }
                statement->case_label.is_bad = true;
        } else {
-               long const val = fold_constant(statement->case_label.expression);
+               long const val = fold_constant(expression);
                statement->case_label.first_case = val;
                statement->case_label.last_case  = val;
        }
@@ -8367,16 +8673,22 @@ static statement_t *parse_case_statement(void)
        if (c_mode & _GNUC) {
                if (token.type == T_DOTDOTDOT) {
                        next_token();
-                       statement->case_label.end_range = parse_expression();
-                       if (! is_constant_expression(statement->case_label.end_range)) {
-                               errorf(pos, "case range does not reduce to an integer constant");
+                       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(end_range->base.type)) {
+                                       errorf(pos, "case range does not reduce to an integer constant");
+                               }
                                statement->case_label.is_bad = true;
                        } else {
-                               long const val = fold_constant(statement->case_label.end_range);
+                               long const val = fold_constant(end_range);
                                statement->case_label.last_case = val;
 
                                if (val < statement->case_label.first_case) {
-                                       statement->case_label.is_empty = true;
+                                       statement->case_label.is_empty_range = true;
                                        warningf(pos, "empty range specified");
                                }
                        }
@@ -8392,7 +8704,7 @@ static statement_t *parse_case_statement(void)
                        /* Check for duplicate case values */
                        case_label_statement_t *c = &statement->case_label;
                        for (case_label_statement_t *l = current_switch->first_case; l != NULL; l = l->next) {
-                               if (l->is_bad || l->is_empty || l->expression == NULL)
+                               if (l->is_bad || l->is_empty_range || l->expression == NULL)
                                        continue;
 
                                if (c->last_case < l->first_case || c->first_case > l->last_case)
@@ -8474,32 +8786,6 @@ end_error:
        return create_invalid_statement();
 }
 
-/**
- * Return the declaration for a given label symbol or create a new one.
- *
- * @param symbol  the symbol of the label
- */
-static declaration_t *get_label(symbol_t *symbol)
-{
-       declaration_t *candidate = get_declaration(symbol, NAMESPACE_LABEL);
-       assert(current_function != NULL);
-       /* if we found a label in the same function, then we already created the
-        * declaration */
-       if (candidate != NULL
-                       && candidate->parent_scope == &current_function->scope) {
-               return candidate;
-       }
-
-       /* otherwise we need to create a new one */
-       declaration_t *const declaration = allocate_declaration_zero();
-       declaration->namespc       = NAMESPACE_LABEL;
-       declaration->symbol        = symbol;
-
-       label_push(declaration);
-
-       return declaration;
-}
-
 /**
  * Parse a label statement.
  */
@@ -8517,9 +8803,9 @@ static statement_t *parse_label_statement(void)
 
        PUSH_PARENT(statement);
 
-       /* if source position is already set then the label is defined twice,
-        * otherwise it was just mentioned in a goto so far */
-       if (label->source_position.input_name != NULL) {
+       /* if statement is already set then the label is defined twice,
+        * otherwise it was just mentioned in a goto/local label declaration so far */
+       if (label->init.statement != NULL) {
                errorf(HERE, "duplicate label '%Y' (declared %P)",
                       symbol, &label->source_position);
        } else {
@@ -8656,6 +8942,13 @@ static statement_t *parse_switch(void)
        type_t       *      type = skip_typeref(expr->base.type);
        if (is_type_integer(type)) {
                type = promote_integer(type);
+               if (warning.traditional) {
+                       if (get_rank(type) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
+                               warningf(&expr->base.source_position,
+                                       "'%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);
@@ -8830,22 +9123,47 @@ end_error:
  */
 static statement_t *parse_goto(void)
 {
+       source_position_t source_position = token.source_position;
        eat(T_goto);
 
-       if (token.type != T_IDENTIFIER) {
-               parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
-               eat_statement();
-               goto end_error;
-       }
-       symbol_t *symbol = token.v.symbol;
-       next_token();
+       statement_t *statement;
+       if (c_mode & _GNUC && token.type == '*') {
+               next_token();
+               expression_t *expression = parse_expression();
 
-       declaration_t *label = get_label(symbol);
+               /* Argh: although documentation say the expression must be of type void *,
+                * gcc excepts anything that can be casted into void * without error */
+               type_t *type = expression->base.type;
 
-       statement_t *statement          = allocate_statement_zero(STATEMENT_GOTO);
-       statement->base.source_position = token.source_position;
+               if (type != type_error_type) {
+                       if (!is_type_pointer(type) && !is_type_integer(type)) {
+                               errorf(&source_position, "cannot convert to a pointer type");
+                       } else if (type != type_void_ptr) {
+                               warningf(&source_position,
+                                       "type of computed goto expression should be 'void*' not '%T'", type);
+                       }
+                       expression = create_implicit_cast(expression, type_void_ptr);
+               }
 
-       statement->gotos.label = label;
+               statement                       = allocate_statement_zero(STATEMENT_GOTO);
+               statement->base.source_position = source_position;
+               statement->gotos.expression     = expression;
+       } else {
+               if (token.type != T_IDENTIFIER) {
+                       if (c_mode & _GNUC)
+                               parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
+                       else
+                               parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
+                       eat_statement();
+                       goto end_error;
+               }
+               symbol_t *symbol = token.v.symbol;
+               next_token();
+
+               statement                       = allocate_statement_zero(STATEMENT_GOTO);
+               statement->base.source_position = source_position;
+               statement->gotos.label          = get_label(symbol);
+       }
 
        /* remember the goto's in a list for later checking */
        if (goto_last == NULL) {
@@ -8903,7 +9221,7 @@ end_error:
 /**
  * Parse a __leave statement.
  */
-static statement_t *parse_leave(void)
+static statement_t *parse_leave_statement(void)
 {
        if (current_try == NULL) {
                errorf(HERE, "__leave statement not within __try");
@@ -9131,6 +9449,54 @@ static statement_t *parse_empty_statement(void)
        return statement;
 }
 
+static statement_t *parse_local_label_declaration(void) {
+       statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION);
+       statement->base.source_position = token.source_position;
+
+       eat(T___label__);
+
+       declaration_t *begin = NULL, *end = NULL;
+
+       while (true) {
+               if (token.type != T_IDENTIFIER) {
+                       parse_error_expected("while parsing local label declaration",
+                               T_IDENTIFIER, NULL);
+                       goto end_error;
+               }
+               symbol_t      *symbol      = token.v.symbol;
+               declaration_t *declaration = get_declaration(symbol, NAMESPACE_LOCAL_LABEL);
+               if (declaration != NULL) {
+                       errorf(HERE, "multiple definitions of '__label__ %Y' (previous definition at %P)",
+                               symbol, &declaration->source_position);
+               } else {
+                       declaration = allocate_declaration_zero();
+                       declaration->namespc         = NAMESPACE_LOCAL_LABEL;
+                       declaration->source_position = token.source_position;
+                       declaration->symbol          = symbol;
+                       declaration->parent_scope    = scope;
+                       declaration->init.statement  = NULL;
+
+                       if (end != NULL)
+                               end->next = declaration;
+                       end = declaration;
+                       if (begin == NULL)
+                               begin = declaration;
+
+                       local_label_push(declaration);
+               }
+               next_token();
+
+               if (token.type != ',')
+                       break;
+               next_token();
+       }
+       eat(';');
+end_error:
+       statement->declaration.declarations_begin = begin;
+       statement->declaration.declarations_end   = end;
+       return statement;
+}
+
 /**
  * Parse a statement.
  * There's also parse_statement() which additionally checks for
@@ -9150,13 +9516,18 @@ static statement_t *intern_parse_statement(void)
                } else if (is_typedef_symbol(token.v.symbol)) {
                        statement = parse_declaration_statement();
                } else switch (la1_type) {
+                       case '*':
+                               if (get_declaration(token.v.symbol, NAMESPACE_NORMAL) != NULL)
+                                       goto expression_statment;
+                               /* FALLTHROUGH */
+
                        DECLARATION_START
                        case T_IDENTIFIER:
-                       case '*':
                                statement = parse_declaration_statement();
                                break;
 
                        default:
+expression_statment:
                                statement = parse_expression_statement();
                                break;
                }
@@ -9176,9 +9547,13 @@ static statement_t *intern_parse_statement(void)
                statement = parse_declaration_statement();
                break;
 
+       case T___label__:
+               statement = parse_local_label_declaration();
+               break;
+
        case ';':        statement = parse_empty_statement();         break;
        case '{':        statement = parse_compound_statement(false); break;
-       case T___leave:  statement = parse_leave();                   break;
+       case T___leave:  statement = parse_leave_statement();                   break;
        case T___try:    statement = parse_ms_try_statment();         break;
        case T_asm:      statement = parse_asm_statement();           break;
        case T_break:    statement = parse_break();                   break;
@@ -9237,6 +9612,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
        add_anchor_token('}');
 
        int      top        = environment_top();
+       int      top_local  = local_label_top();
        scope_t *last_scope = scope;
        set_scope(&statement->compound.scope);
 
@@ -9299,6 +9675,7 @@ end_error:
        assert(scope == &statement->compound.scope);
        set_scope(last_scope);
        environment_pop_to(top);
+       local_label_pop_to(top_local);
 
        POP_PARENT;
        return statement;
@@ -9425,6 +9802,7 @@ void start_parsing(void)
 {
        environment_stack = NEW_ARR_F(stack_entry_t, 0);
        label_stack       = NEW_ARR_F(stack_entry_t, 0);
+       local_label_stack = NEW_ARR_F(stack_entry_t, 0);
        diagnostic_count  = 0;
        error_count       = 0;
        warning_count     = 0;
@@ -9456,6 +9834,7 @@ translation_unit_t *finish_parsing(void)
 
        DEL_ARR_F(environment_stack);
        DEL_ARR_F(label_stack);
+       DEL_ARR_F(local_label_stack);
 
        translation_unit_t *result = unit;
        unit = NULL;
@@ -9465,7 +9844,7 @@ translation_unit_t *finish_parsing(void)
 void parse(void)
 {
        lookahead_bufpos = 0;
-       for(int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
+       for (int i = 0; i < MAX_LOOKAHEAD + 2; ++i) {
                next_token();
        }
        parse_translation_unit();
@@ -9476,6 +9855,8 @@ void parse(void)
  */
 void init_parser(void)
 {
+       sym_anonymous = symbol_table_insert("<anonymous>");
+
        if (c_mode & _MS) {
                /* add predefined symbols for extended-decl-modifier */
                sym_align      = symbol_table_insert("align");