Print \n after $invalid statement$.
[cparser] / parser.c
index ffc742f..1ccaffa 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -110,6 +110,7 @@ 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;
@@ -133,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;
@@ -315,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];
@@ -479,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.
  */
@@ -764,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);
@@ -772,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
  */
@@ -782,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
  */
@@ -832,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
@@ -848,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;
@@ -986,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;
 
@@ -2104,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;
 
@@ -2119,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));
        }
 }
 
@@ -3076,6 +3121,102 @@ static declaration_t *create_error_declaration(symbol_t *symbol, storage_class_t
        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;
@@ -3215,6 +3356,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: {
@@ -3223,6 +3365,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();
@@ -3897,8 +4040,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;
@@ -4315,8 +4460,9 @@ static declaration_t *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)",
@@ -4334,14 +4480,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);
+                               }
                        }
                }
 
@@ -4703,6 +4851,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;
@@ -4908,9 +5060,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:
@@ -5362,12 +5521,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;
 }
@@ -5404,12 +5591,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 == ':') {
@@ -5419,12 +5606,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;
@@ -5444,12 +5627,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
@@ -5502,7 +5681,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);
@@ -5900,21 +6079,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);
@@ -5940,23 +6113,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(&source_position,
-                       "variable '%#T' is initialized by itself",
+               warningf(HERE, "variable '%#T' is initialized by itself",
                        declaration->type, declaration->symbol);
        }
 
+       next_token();
        return expression;
 }
 
@@ -6503,6 +6674,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.
  */
@@ -6580,6 +6816,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();
@@ -6643,19 +6883,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;
 }
 
@@ -6775,7 +7014,7 @@ static expression_t *parse_select_expression(unsigned precedence,
                if (!declaration->init.complete) {
                        errorf(HERE, "request for member '%Y' of incomplete type '%T'",
                               symbol, type_left);
-                       return create_invalid_expression();
+                       goto create_error_entry;
                }
 
                entry = find_compound_entry(declaration, symbol);
@@ -6857,26 +7096,15 @@ static void check_call_argument(const function_parameter_t *parameter,
                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) {
-               if (
-                   /* passing as integer instead of float or complex */
-                   (is_type_integer(expected_type) &&
-                    (is_type_float(arg_type) || is_type_complex(arg_type))) ||
-                   /* passing as complex instead of integer or float */
-                   (is_type_complex(expected_type) &&
-                    (is_type_integer(arg_type) || is_type_float(arg_type))) ||
-                   /* passing as float instead of integer or complex */
-                   (is_type_float(expected_type) &&
-                    (is_type_integer(arg_type) || is_type_complex(arg_type))) ||
-                   /* passing as float instead of double */
-                   (is_type_float(expected_type) && expected_type != type_double &&
-                    is_type_float(arg_type))) {
+       } 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, arg_type);
-               }
-               if (is_type_integer(expected_type) && is_type_integer(arg_type)) {
-                       /* TODO check for size HERE */
+                               pos, expected_type_skip, promoted_type);
                }
        }
 }
@@ -7285,7 +7513,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;
        }
@@ -7397,6 +7625,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;
@@ -7483,10 +7714,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");
        }
 }
@@ -7859,6 +8095,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;
@@ -8411,12 +8648,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;
        }
@@ -8424,16 +8667,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");
                                }
                        }
@@ -8449,7 +8698,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)
@@ -8531,32 +8780,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.
  */
@@ -8574,9 +8797,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 {
@@ -8894,22 +9117,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                       = 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->gotos.label = label;
+               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) {
@@ -8967,7 +9215,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");
@@ -9195,6 +9443,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
@@ -9214,13 +9510,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;
                }
@@ -9240,9 +9541,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;
@@ -9301,6 +9606,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);
 
@@ -9363,6 +9669,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;
@@ -9489,6 +9796,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;
@@ -9520,6 +9828,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;
@@ -9529,7 +9838,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();
@@ -9540,6 +9849,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");