Remove stale (since r21011) comment.
[cparser] / parser.c
index 83f51e0..fa85c3c 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -114,9 +114,12 @@ 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;
+/** The global file scope. */
+static scope_t            *file_scope        = NULL;
+/** The current scope. */
 static scope_t            *scope             = NULL;
 static declaration_t      *last_declaration  = NULL;
+/** Point to the current function declaration if inside a function. */
 static declaration_t      *current_function  = NULL;
 static declaration_t      *current_init_decl = NULL;
 static switch_statement_t *current_switch    = NULL;
@@ -138,7 +141,7 @@ static struct obstack      temp_obst;
 
 #define PUSH_PARENT(stmt)                          \
        statement_t *const prev_parent = current_parent; \
-       current_parent = (stmt);
+       ((void)(current_parent = (stmt)))
 #define POP_PARENT ((void)(current_parent = prev_parent))
 
 static source_position_t null_position = { NULL, 0 };
@@ -353,8 +356,9 @@ static statement_t *allocate_statement_zero(statement_kind_t kind)
        size_t       size = get_statement_struct_size(kind);
        statement_t *res  = allocate_ast_zero(size);
 
-       res->base.kind   = kind;
-       res->base.parent = current_parent;
+       res->base.kind            = kind;
+       res->base.parent          = current_parent;
+       res->base.source_position = token.source_position;
        return res;
 }
 
@@ -387,9 +391,7 @@ static expression_t *create_invalid_expression(void)
  */
 static statement_t *create_invalid_statement(void)
 {
-       statement_t *statement          = allocate_statement_zero(STATEMENT_INVALID);
-       statement->base.source_position = token.source_position;
-       return statement;
+       return allocate_statement_zero(STATEMENT_INVALID);
 }
 
 /**
@@ -397,9 +399,7 @@ static statement_t *create_invalid_statement(void)
  */
 static statement_t *create_empty_statement(void)
 {
-       statement_t *statement          = allocate_statement_zero(STATEMENT_EMPTY);
-       statement->base.source_position = token.source_position;
-       return statement;
+       return allocate_statement_zero(STATEMENT_EMPTY);
 }
 
 /**
@@ -637,13 +637,9 @@ check_stop:
  */
 static void eat_until_anchor(void)
 {
-       if (token.type == T_EOF)
-               return;
        while (token_anchor_set[token.type] == 0) {
                if (token.type == '(' || token.type == '{' || token.type == '[')
                        eat_until_matching_token(token.type);
-               if (token.type == T_EOF)
-                       break;
                next_token();
        }
 }
@@ -713,16 +709,25 @@ static void type_error_incompatible(const char *msg,
                next_token();                                     \
        } while (0)
 
-static void set_scope(scope_t *new_scope)
+static void scope_push(scope_t *new_scope)
 {
        if (scope != NULL) {
                scope->last_declaration = last_declaration;
+               new_scope->depth        = scope->depth + 1;
        }
-       scope = new_scope;
+       new_scope->parent = scope;
+       scope             = new_scope;
 
        last_declaration = new_scope->last_declaration;
 }
 
+static void scope_pop(void)
+{
+       scope->last_declaration = last_declaration;
+       scope = scope->parent;
+       last_declaration = scope->last_declaration;
+}
+
 /**
  * Search a symbol in a given namespace and returns its declaration or
  * NULL if this symbol was not found.
@@ -749,28 +754,20 @@ static void stack_push(stack_entry_t **stack_ptr, declaration_t *declaration)
        namespace_t  namespc = (namespace_t) declaration->namespc;
 
        /* replace/add declaration into declaration list of the symbol */
-       declaration_t *iter = symbol->declaration;
-       if (iter == NULL) {
-               symbol->declaration = declaration;
-       } else {
-               declaration_t *iter_last = NULL;
-               for( ; iter != NULL; iter_last = iter, iter = iter->symbol_next) {
-                       /* replace an entry? */
-                       if (iter->namespc == namespc) {
-                               if (iter_last == NULL) {
-                                       symbol->declaration = declaration;
-                               } else {
-                                       iter_last->symbol_next = declaration;
-                               }
-                               declaration->symbol_next = iter->symbol_next;
-                               break;
-                       }
-               }
-               if (iter == NULL) {
-                       assert(iter_last->symbol_next == NULL);
-                       iter_last->symbol_next = declaration;
+       declaration_t **anchor;
+       declaration_t  *iter;
+       for (anchor = &symbol->declaration;; anchor = &iter->symbol_next) {
+               iter = *anchor;
+               if (iter == NULL)
+                       break;
+
+               /* replace an entry? */
+               if (iter->namespc == namespc) {
+                       declaration->symbol_next = iter->symbol_next;
+                       break;
                }
        }
+       *anchor = declaration;
 
        /* remember old declaration */
        stack_entry_t entry;
@@ -835,29 +832,23 @@ static void stack_pop_to(stack_entry_t **stack_ptr, size_t new_top)
                namespace_t    namespc         = (namespace_t)entry->namespc;
 
                /* replace/remove declaration */
-               declaration_t *declaration = symbol->declaration;
-               assert(declaration != NULL);
-               if (declaration->namespc == namespc) {
-                       if (old_declaration == NULL) {
-                               symbol->declaration = declaration->symbol_next;
-                       } else {
-                               symbol->declaration = old_declaration;
-                       }
-               } else {
-                       declaration_t *iter_last = declaration;
-                       declaration_t *iter      = declaration->symbol_next;
-                       for( ; iter != NULL; iter_last = iter, iter = iter->symbol_next) {
-                               /* replace an entry? */
-                               if (iter->namespc == namespc) {
-                                       assert(iter_last != NULL);
-                                       iter_last->symbol_next = old_declaration;
-                                       if (old_declaration != NULL) {
-                                               old_declaration->symbol_next = iter->symbol_next;
-                                       }
-                                       break;
-                               }
-                       }
+               declaration_t **anchor;
+               declaration_t  *iter;
+               for (anchor = &symbol->declaration;; anchor = &iter->symbol_next) {
+                       iter = *anchor;
                        assert(iter != NULL);
+                       /* replace an entry? */
+                       if (iter->namespc == namespc)
+                               break;
+               }
+
+               /* Not all declarations adhere scopes (e.g. jump labels), so this
+                * correction is necessary */
+               if (old_declaration != NULL) {
+                       old_declaration->symbol_next = iter->symbol_next;
+                       *anchor = old_declaration;
+               } else {
+                       *anchor = iter->symbol_next;
                }
        }
 
@@ -1671,7 +1662,6 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes)
                                }
 
                                switch(kind) {
-                               case GNU_AK_CONST:
                                case GNU_AK_VOLATILE:
                                case GNU_AK_NAKED:
                                case GNU_AK_MALLOC:
@@ -1711,6 +1701,7 @@ static decl_modifiers_t parse_gnu_attribute(gnu_attribute_t **attributes)
                                case GNU_AK_UNUSED:            modifiers |= DM_UNUSED;            goto no_arg;
                                case GNU_AK_USED:              modifiers |= DM_USED;              goto no_arg;
                                case GNU_AK_PURE:              modifiers |= DM_PURE;              goto no_arg;
+                               case GNU_AK_CONST:             modifiers |= DM_CONST;             goto no_arg;
                                case GNU_AK_ALWAYS_INLINE:     modifiers |= DM_FORCEINLINE;       goto no_arg;
                                case GNU_AK_DLLIMPORT:         modifiers |= DM_DLLIMPORT;         goto no_arg;
                                case GNU_AK_DLLEXPORT:         modifiers |= DM_DLLEXPORT;         goto no_arg;
@@ -2000,6 +1991,11 @@ static initializer_t *initializer_from_expression(type_t *orig_type,
                            &expression->base.source_position);
 
        initializer_t *const result = allocate_initializer_zero(INITIALIZER_VALUE);
+#if 0
+       if (type->kind == TYPE_BITFIELD) {
+               type = type->bitfield.base_type;
+       }
+#endif
        result->value.value = create_implicit_cast(expression, type);
 
        return result;
@@ -2220,34 +2216,37 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                                               "'.%Y' designator used for non-compound type '%T'",
                                               symbol, orig_type);
                                }
-                               goto failed;
-                       }
 
-                       declaration_t *declaration = type->compound.declaration;
-                       declaration_t *iter        = declaration->scope.declarations;
-                       for( ; iter != NULL; iter = iter->next) {
-                               if (iter->symbol == symbol) {
-                                       break;
+                               top->type             = type_error_type;
+                               top->v.compound_entry = NULL;
+                               orig_type             = type_error_type;
+                       } else {
+                               declaration_t *declaration = type->compound.declaration;
+                               declaration_t *iter        = declaration->scope.declarations;
+                               for( ; iter != NULL; iter = iter->next) {
+                                       if (iter->symbol == symbol) {
+                                               break;
+                                       }
                                }
-                       }
-                       if (iter == NULL) {
-                               errorf(&designator->source_position,
-                                      "'%T' has no member named '%Y'", orig_type, symbol);
-                               goto failed;
-                       }
-                       if (used_in_offsetof) {
-                               type_t *real_type = skip_typeref(iter->type);
-                               if (real_type->kind == TYPE_BITFIELD) {
+                               if (iter == NULL) {
                                        errorf(&designator->source_position,
-                                              "offsetof designator '%Y' may not specify bitfield",
-                                              symbol);
+                                              "'%T' has no member named '%Y'", orig_type, symbol);
                                        goto failed;
                                }
-                       }
+                               if (used_in_offsetof) {
+                                       type_t *real_type = skip_typeref(iter->type);
+                                       if (real_type->kind == TYPE_BITFIELD) {
+                                               errorf(&designator->source_position,
+                                                      "offsetof designator '%Y' may not specify bitfield",
+                                                      symbol);
+                                               goto failed;
+                                       }
+                               }
 
-                       top->type             = orig_type;
-                       top->v.compound_entry = iter;
-                       orig_type             = iter->type;
+                               top->type             = orig_type;
+                               top->v.compound_entry = iter;
+                               orig_type             = iter->type;
+                       }
                } else {
                        expression_t *array_index = designator->array_index;
                        assert(designator->array_index != NULL);
@@ -2260,24 +2259,18 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                                }
                                goto failed;
                        }
-                       if (!is_type_valid(array_index->base.type)) {
-                               goto failed;
-                       }
 
                        long index = fold_constant(array_index);
                        if (!used_in_offsetof) {
                                if (index < 0) {
                                        errorf(&designator->source_position,
                                               "array index [%E] must be positive", array_index);
-                                       goto failed;
-                               }
-                               if (type->array.size_constant == true) {
+                               } else if (type->array.size_constant) {
                                        long array_size = type->array.size;
                                        if (index >= array_size) {
                                                errorf(&designator->source_position,
                                                       "designator [%E] (%d) exceeds array size %d",
                                                       array_index, index, array_size);
-                                               goto failed;
                                        }
                                }
                        }
@@ -2315,7 +2308,7 @@ static void advance_current_object(type_path_t *path, size_t top_path_level)
                        path->top_type = entry->type;
                        return;
                }
-       } else {
+       } else if (is_type_array(type)) {
                assert(is_type_array(type));
 
                top->v.index++;
@@ -2323,6 +2316,9 @@ static void advance_current_object(type_path_t *path, size_t top_path_level)
                if (!type->array.size_constant || top->v.index < type->array.size) {
                        return;
                }
+       } else {
+               assert(!is_type_valid(type));
+               return;
        }
 
        /* we're past the last member of the current sub-aggregate, try if we
@@ -2394,13 +2390,6 @@ static initializer_t *parse_sub_initializer(type_path_t *path,
                /* We are initializing an empty compound. */
        } else {
                type = skip_typeref(orig_type);
-
-               /* we can't do usefull stuff if we didn't even parse the type. Skip the
-                * initializers in this case. */
-               if (!is_type_valid(type)) {
-                       skip_initializers();
-                       return create_empty_initializer();
-               }
        }
 
        initializer_t **initializers = NEW_ARR_F(initializer_t*, 0);
@@ -2477,8 +2466,9 @@ finish_designator:
 
                        if (type == NULL) {
                                /* we are already outside, ... */
-                               if (is_type_compound(outer_type) &&
-                                   !outer_type->compound.declaration->init.complete) {
+                               type_t *const outer_type_skip = skip_typeref(outer_type);
+                               if (is_type_compound(outer_type_skip) &&
+                                   !outer_type_skip->compound.declaration->init.complete) {
                                        goto error_parse_next;
                                }
                                goto error_excess;
@@ -3122,7 +3112,7 @@ static declaration_t *create_error_declaration(symbol_t *symbol, storage_class_t
        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_NONE || scope == file_scope ?
                        storage_class : STORAGE_CLASS_AUTO;
        decl->symbol                 = symbol;
        decl->implicit               = true;
@@ -3374,8 +3364,8 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                        type->compound.declaration = parse_compound_type_specifier(false);
                        if (type->compound.declaration->modifiers & DM_TRANSPARENT_UNION)
                                modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
-                       break;
                        finish_union_type(&type->compound);
+                       break;
                }
                case T_enum:
                        type = parse_enum_specifier();
@@ -3674,7 +3664,13 @@ static type_qualifiers_t parse_type_qualifiers(void)
        }
 }
 
-static declaration_t *parse_identifier_list(void)
+/**
+ * Parses an K&R identifier list and return a list of declarations.
+ *
+ * @param last  points to the last declaration in the list
+ * @return the list of declarations
+ */
+static declaration_t *parse_identifier_list(declaration_t **last)
 {
        declaration_t *declarations     = NULL;
        declaration_t *last_declaration = NULL;
@@ -3698,6 +3694,7 @@ static declaration_t *parse_identifier_list(void)
                next_token();
        } while (token.type == T_IDENTIFIER);
 
+       *last = last_declaration;
        return declarations;
 }
 
@@ -3750,7 +3747,13 @@ static declaration_t *parse_parameter(void)
        return declaration;
 }
 
-static declaration_t *parse_parameters(function_type_t *type)
+/**
+ * Parses a function type parameter list and return a list of declarations.
+ *
+ * @param last  point to the last element of the list
+ * @return the parameter list
+ */
+static declaration_t *parse_parameters(function_type_t *type, declaration_t **last)
 {
        declaration_t *declarations = NULL;
 
@@ -3763,7 +3766,7 @@ static declaration_t *parse_parameters(function_type_t *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();
+                       declarations = parse_identifier_list(last);
                        goto parameters_finished;
                }
        }
@@ -3829,10 +3832,12 @@ parameters_finished:
        expect(')');
 
        restore_anchor_state(',', saved_comma_state);
+       *last = last_declaration;
        return declarations;
 
 end_error:
        restore_anchor_state(',', saved_comma_state);
+       *last = NULL;
        return NULL;
 }
 
@@ -3968,9 +3973,12 @@ static construct_type_t *parse_function_declarator(declaration_t *declaration)
                type = allocate_type_zero(TYPE_FUNCTION, HERE);
        }
 
-       declaration_t *parameters = parse_parameters(&type->function);
+       declaration_t *last;
+       declaration_t *parameters = parse_parameters(&type->function, &last);
        if (declaration != NULL) {
-               declaration->scope.declarations = parameters;
+               declaration->scope.declarations     = parameters;
+               declaration->scope.last_declaration = last;
+               declaration->scope.is_parameter     = true;
        }
 
        construct_function_type_t *construct_function_type =
@@ -4251,8 +4259,8 @@ static declaration_t *parse_declarator(
        declaration->is_inline              = specifiers->is_inline;
 
        declaration->storage_class          = specifiers->declared_storage_class;
-       if (declaration->storage_class == STORAGE_CLASS_NONE
-                       && scope != global_scope) {
+       if (declaration->storage_class == STORAGE_CLASS_NONE &&
+           scope != file_scope) {
                declaration->storage_class = STORAGE_CLASS_AUTO;
        }
 
@@ -4388,14 +4396,23 @@ static declaration_t *record_declaration(
 
        if (warning.nested_externs                             &&
            declaration->storage_class == STORAGE_CLASS_EXTERN &&
-           scope                      != global_scope) {
+           scope                      != file_scope) {
                warningf(&declaration->source_position,
                         "nested extern declaration of '%#T'", declaration->type, symbol);
        }
 
        assert(declaration != previous_declaration);
-       if (previous_declaration != NULL
-                       && previous_declaration->parent_scope == scope) {
+       if (previous_declaration != NULL &&
+           previous_declaration->parent_scope->is_parameter &&
+           scope->depth == previous_declaration->parent_scope->depth + 1) {
+               errorf(&declaration->source_position,
+                       "declaration '%#T' redeclares the parameter '%#T' (declared %P)",
+                       orig_type, symbol, previous_declaration->type, symbol,
+                       &previous_declaration->source_position);
+               goto finish;
+       }
+       if (previous_declaration != NULL &&
+           previous_declaration->parent_scope == scope) {
                /* can happen for K&R style declarations */
                if (previous_declaration->type == NULL) {
                        previous_declaration->type = declaration->type;
@@ -4519,7 +4536,7 @@ warn_redundant_declaration:
                }
        } else {
                if (warning.missing_declarations &&
-                   scope == global_scope && (
+                   scope == file_scope && (
                      declaration->storage_class == STORAGE_CLASS_NONE ||
                      declaration->storage_class == STORAGE_CLASS_THREAD
                    )) {
@@ -4527,7 +4544,7 @@ warn_redundant_declaration:
                                 "no previous declaration for '%#T'", orig_type, symbol);
                }
        }
-
+finish:
        assert(declaration->parent_scope == NULL);
        assert(scope != NULL);
 
@@ -4575,9 +4592,9 @@ static void parse_init_declarator_rest(declaration_t *declaration)
        }
 
        bool must_be_constant = false;
-       if (declaration->storage_class == STORAGE_CLASS_STATIC
-                       || declaration->storage_class == STORAGE_CLASS_THREAD_STATIC
-                       || declaration->parent_scope == global_scope) {
+       if (declaration->storage_class == STORAGE_CLASS_STATIC        ||
+           declaration->storage_class == STORAGE_CLASS_THREAD_STATIC ||
+           declaration->parent_scope  == file_scope) {
                must_be_constant = true;
        }
 
@@ -4760,10 +4777,11 @@ static void parse_kr_declaration_list(declaration_t *declaration)
        if (!type->function.kr_style_parameters)
                return;
 
+       add_anchor_token('{');
+
        /* push function parameters */
-       int       top        = environment_top();
-       scope_t  *last_scope = scope;
-       set_scope(&declaration->scope);
+       size_t const top = environment_top();
+       scope_push(&declaration->scope);
 
        declaration_t *parameter = declaration->scope.declarations;
        for ( ; parameter != NULL; parameter = parameter->next) {
@@ -4779,7 +4797,7 @@ static void parse_kr_declaration_list(declaration_t *declaration)
 
        /* pop function parameters */
        assert(scope == &declaration->scope);
-       set_scope(last_scope);
+       scope_pop();
        environment_pop_to(top);
 
        /* update function type */
@@ -4838,6 +4856,8 @@ static void parse_kr_declaration_list(declaration_t *declaration)
        }
 
        declaration->type = type;
+
+       rem_anchor_token('{');
 }
 
 static bool first_err = true;
@@ -5475,9 +5495,8 @@ static void parse_external_declaration(void)
        type = skip_typeref(declaration->type);
 
        /* push function parameters and switch scope */
-       int       top        = environment_top();
-       scope_t  *last_scope = scope;
-       set_scope(&declaration->scope);
+       size_t const top = environment_top();
+       scope_push(&declaration->scope);
 
        declaration_t *parameter = declaration->scope.declarations;
        for( ; parameter != NULL; parameter = parameter->next) {
@@ -5532,7 +5551,7 @@ static void parse_external_declaration(void)
        }
 
        assert(scope == &declaration->scope);
-       set_scope(last_scope);
+       scope_pop();
        environment_pop_to(top);
 }
 
@@ -5697,7 +5716,11 @@ static void parse_compound_type_entries(declaration_t *compound_declaration)
        eat('{');
        add_anchor_token('}');
 
-       while (token.type != '}' && token.type != T_EOF) {
+       while (token.type != '}') {
+               if (token.type == T_EOF) {
+                       errorf(HERE, "EOF while parsing struct");
+                       break;
+               }
                declaration_specifiers_t specifiers;
                memset(&specifiers, 0, sizeof(specifiers));
                parse_declaration_specifiers(&specifiers);
@@ -5705,10 +5728,6 @@ static void parse_compound_type_entries(declaration_t *compound_declaration)
                parse_compound_declarators(compound_declaration, &specifiers);
        }
        rem_anchor_token('}');
-
-       if (token.type == T_EOF) {
-               errorf(HERE, "EOF while parsing struct");
-       }
        next_token();
 }
 
@@ -5995,11 +6014,17 @@ static type_t *get_builtin_symbol_type(symbol_t *symbol)
                return make_function_1_type(type_void_ptr, type_size_t);
        case T___builtin_huge_val:
                return make_function_0_type(type_double);
+       case T___builtin_inf:
+               return make_function_0_type(type_double);
+       case T___builtin_inff:
+               return make_function_0_type(type_float);
+       case T___builtin_infl:
+               return make_function_0_type(type_long_double);
        case T___builtin_nan:
                return make_function_1_type(type_double, type_char_ptr);
        case T___builtin_nanf:
                return make_function_1_type(type_float, type_char_ptr);
-       case T___builtin_nand:
+       case T___builtin_nanl:
                return make_function_1_type(type_long_double, type_char_ptr);
        case T___builtin_va_end:
                return make_function_1_type(type_void, type_valist);
@@ -6108,11 +6133,11 @@ static expression_t *parse_reference(void)
                }
        }
 
-       type_t *type = declaration->type;
+       type_t *orig_type = declaration->type;
 
        /* we always do the auto-type conversions; the & and sizeof parser contains
         * code to revert this! */
-       type = automatic_type_conversion(type);
+       type_t *type = automatic_type_conversion(orig_type);
 
        ref->declaration = declaration;
        ref->base.type   = type;
@@ -6120,6 +6145,15 @@ static expression_t *parse_reference(void)
        /* this declaration is used */
        declaration->used = true;
 
+       if (declaration->parent_scope != file_scope                          &&
+           declaration->parent_scope->depth < current_function->scope.depth &&
+           is_type_valid(orig_type) && !is_type_function(orig_type)) {
+               /* access of a variable from an outer function */
+               declaration->address_taken     = true;
+               ref->is_outer_ref              = true;
+               current_function->need_closure = true;
+       }
+
        /* check for deprecated functions */
        if (warning.deprecated_declarations &&
            declaration->modifiers & DM_DEPRECATED) {
@@ -6611,7 +6645,6 @@ static expression_t *parse_compare_builtin(void)
                break;
        default:
                internal_errorf(HERE, "invalid compare builtin found");
-               break;
        }
        expression->base.source_position = *HERE;
        next_token();
@@ -6701,7 +6734,10 @@ static declaration_t *get_label(symbol_t *symbol)
        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);
+               if (candidate->parent_scope != scope) {
+                       assert(candidate->parent_scope->depth < scope->depth);
+                       current_function->goto_to_outer = true;
+               }
                return candidate;
        }
 
@@ -6816,9 +6852,12 @@ static expression_t *parse_primary_expression(void)
                case T___builtin_va_arg:         return parse_va_arg();
                case T___builtin_expect:
                case T___builtin_alloca:
+               case T___builtin_inf:
+               case T___builtin_inff:
+               case T___builtin_infl:
                case T___builtin_nan:
-               case T___builtin_nand:
                case T___builtin_nanf:
+               case T___builtin_nanl:
                case T___builtin_huge_val:
                case T___builtin_va_end:         return parse_builtin_symbol();
                case T___builtin_isgreater:
@@ -7342,13 +7381,13 @@ static expression_t *parse_conditional_expression(unsigned precedence,
                                        "pointer/integer type mismatch in conditional expression ('%T' and '%T')", true_type, false_type);
                        result_type = pointer_type;
                } else {
-                       type_error_incompatible("while parsing conditional",
-                                       &expression->base.source_position, true_type, false_type);
+                       if (is_type_valid(other_type)) {
+                               type_error_incompatible("while parsing conditional",
+                                               &expression->base.source_position, true_type, false_type);
+                       }
                        result_type = type_error_type;
                }
        } else {
-               /* TODO: one pointer to void*, other some pointer */
-
                if (is_type_valid(true_type) && is_type_valid(false_type)) {
                        type_error_incompatible("while parsing conditional",
                                                &conditional->base.source_position, true_type,
@@ -7446,7 +7485,10 @@ static bool is_lvalue(const expression_t *expression)
                return true;
 
        default:
-               return false;
+               /* Claim it is an lvalue, if the type is invalid.  There was a parse
+                * error before, which maybe prevented properly recognizing it as
+                * lvalue. */
+               return !is_type_valid(skip_typeref(expression->base.type));
        }
 }
 
@@ -7496,6 +7538,46 @@ static void semantic_unexpr_plus(unary_expression_t *expression)
                        "traditional C rejects the unary plus operator");
 }
 
+static expression_t const *get_reference_address(expression_t const *expr)
+{
+       bool regular_take_address = true;
+       for (;;) {
+               if (expr->kind == EXPR_UNARY_TAKE_ADDRESS) {
+                       expr = expr->unary.value;
+               } else {
+                       regular_take_address = false;
+               }
+
+               if (expr->kind != EXPR_UNARY_DEREFERENCE)
+                       break;
+
+               expr = expr->unary.value;
+       }
+
+       if (expr->kind != EXPR_REFERENCE)
+               return NULL;
+
+       if (!regular_take_address &&
+           !is_type_function(skip_typeref(expr->reference.declaration->type))) {
+               return NULL;
+       }
+
+       return expr;
+}
+
+static void warn_function_address_as_bool(expression_t const* expr)
+{
+       if (!warning.address)
+               return;
+
+       expr = get_reference_address(expr);
+       if (expr != NULL) {
+               warningf(&expr->base.source_position,
+                       "the address of '%Y' will always evaluate as 'true'",
+                       expr->reference.declaration->symbol);
+       }
+}
+
 static void semantic_not(unary_expression_t *expression)
 {
        type_t *const orig_type = expression->value->base.type;
@@ -7505,6 +7587,8 @@ static void semantic_not(unary_expression_t *expression)
                       "operand of ! must be of scalar type");
        }
 
+       warn_function_address_as_bool(expression->value);
+
        expression->base.type = type_int;
 }
 
@@ -7574,7 +7658,7 @@ static void semantic_take_addr(unary_expression_t *expression)
        value->base.type    = revert_automatic_type_conversion(value);
 
        type_t *orig_type = value->base.type;
-       if (!is_type_valid(orig_type))
+       if (!is_type_valid(skip_typeref(orig_type)))
                return;
 
        set_address_taken(value, false);
@@ -7852,6 +7936,22 @@ static void semantic_sub(binary_expression_t *expression)
        }
 }
 
+static void warn_string_literal_address(expression_t const* expr)
+{
+       while (expr->kind == EXPR_UNARY_TAKE_ADDRESS) {
+               expr = expr->unary.value;
+               if (expr->kind != EXPR_UNARY_DEREFERENCE)
+                       return;
+               expr = expr->unary.value;
+       }
+
+       if (expr->kind == EXPR_STRING_LITERAL ||
+           expr->kind == EXPR_WIDE_STRING_LITERAL) {
+               warningf(&expr->base.source_position,
+                       "comparison with string literal results in unspecified behaviour");
+       }
+}
+
 /**
  * Check the semantics of comparison expressions.
  *
@@ -7859,13 +7959,32 @@ static void semantic_sub(binary_expression_t *expression)
  */
 static void semantic_comparison(binary_expression_t *expression)
 {
-       expression_t *left            = expression->left;
-       expression_t *right           = expression->right;
-       type_t       *orig_type_left  = left->base.type;
-       type_t       *orig_type_right = right->base.type;
+       expression_t *left  = expression->left;
+       expression_t *right = expression->right;
 
-       type_t *type_left  = skip_typeref(orig_type_left);
-       type_t *type_right = skip_typeref(orig_type_right);
+       if (warning.address) {
+               warn_string_literal_address(left);
+               warn_string_literal_address(right);
+
+               expression_t const* const func_left = get_reference_address(left);
+               if (func_left != NULL && is_null_pointer_constant(right)) {
+                       warningf(&expression->base.source_position,
+                               "the address of '%Y' will never be NULL",
+                               func_left->reference.declaration->symbol);
+               }
+
+               expression_t const* const func_right = get_reference_address(right);
+               if (func_right != NULL && is_null_pointer_constant(right)) {
+                       warningf(&expression->base.source_position,
+                               "the address of '%Y' will never be NULL",
+                               func_right->reference.declaration->symbol);
+               }
+       }
+
+       type_t *orig_type_left  = left->base.type;
+       type_t *orig_type_right = right->base.type;
+       type_t *type_left       = skip_typeref(orig_type_left);
+       type_t *type_right      = skip_typeref(orig_type_right);
 
        /* TODO non-arithmetic types */
        if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
@@ -8058,6 +8177,9 @@ static void semantic_logical_op(binary_expression_t *expression)
        type_t       *const type_left       = skip_typeref(orig_type_left);
        type_t       *const type_right      = skip_typeref(orig_type_right);
 
+       warn_function_address_as_bool(left);
+       warn_function_address_as_bool(right);
+
        if (!is_type_scalar(type_left) || !is_type_scalar(type_right)) {
                /* TODO: improve error message */
                if (is_type_valid(type_left) && is_type_valid(type_right)) {
@@ -8598,13 +8720,11 @@ static asm_clobber_t *parse_asm_clobbers(void)
  */
 static statement_t *parse_asm_statement(void)
 {
-       eat(T_asm);
-
-       statement_t *statement          = allocate_statement_zero(STATEMENT_ASM);
-       statement->base.source_position = token.source_position;
-
+       statement_t     *statement     = allocate_statement_zero(STATEMENT_ASM);
        asm_statement_t *asm_statement = &statement->asms;
 
+       eat(T_asm);
+
        if (token.type == T_volatile) {
                next_token();
                asm_statement->is_volatile = true;
@@ -8659,19 +8779,18 @@ end_error:
  */
 static statement_t *parse_case_statement(void)
 {
-       eat(T_case);
-
        statement_t       *const statement = allocate_statement_zero(STATEMENT_CASE_LABEL);
        source_position_t *const pos       = &statement->base.source_position;
 
-       *pos                             = token.source_position;
+       eat(T_case);
+
        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)) {
+               if (is_type_valid(skip_typeref(expression->base.type))) {
                        errorf(pos, "case label does not reduce to an integer constant");
                }
                statement->case_label.is_bad = true;
@@ -8690,7 +8809,7 @@ static statement_t *parse_case_statement(void)
                                /* 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)) {
+                               if (is_type_valid(skip_typeref(end_range->base.type))) {
                                        errorf(pos, "case range does not reduce to an integer constant");
                                }
                                statement->case_label.is_bad = true;
@@ -8755,10 +8874,9 @@ end_error:
  */
 static statement_t *parse_default_statement(void)
 {
-       eat(T_default);
-
        statement_t *statement = allocate_statement_zero(STATEMENT_CASE_LABEL);
-       statement->base.source_position = token.source_position;
+
+       eat(T_default);
 
        PUSH_PARENT(statement);
 
@@ -8803,14 +8921,13 @@ end_error:
 static statement_t *parse_label_statement(void)
 {
        assert(token.type == T_IDENTIFIER);
-       symbol_t *symbol = token.v.symbol;
-       next_token();
-
-       declaration_t *label = get_label(symbol);
+       symbol_t      *symbol = token.v.symbol;
+       declaration_t *label  = get_label(symbol);
 
        statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL);
-       statement->base.source_position = token.source_position;
-       statement->label.label          = label;
+       statement->label.label       = label;
+
+       next_token();
 
        PUSH_PARENT(statement);
 
@@ -8866,19 +8983,23 @@ static statement_t *parse_label_statement(void)
  */
 static statement_t *parse_if(void)
 {
-       eat(T_if);
+       statement_t *statement = allocate_statement_zero(STATEMENT_IF);
 
-       statement_t *statement          = allocate_statement_zero(STATEMENT_IF);
-       statement->base.source_position = token.source_position;
+       eat(T_if);
 
        PUSH_PARENT(statement);
 
+       add_anchor_token('{');
+
        expect('(');
        add_anchor_token(')');
        statement->ifs.condition = parse_expression();
        rem_anchor_token(')');
        expect(')');
 
+end_error:
+       rem_anchor_token('{');
+
        add_anchor_token(T_else);
        statement->ifs.true_statement = parse_statement();
        rem_anchor_token(T_else);
@@ -8890,9 +9011,6 @@ static statement_t *parse_if(void)
 
        POP_PARENT;
        return statement;
-end_error:
-       POP_PARENT;
-       return create_invalid_statement();
 }
 
 /**
@@ -8940,10 +9058,9 @@ static void check_enum_cases(const switch_statement_t *statement) {
  */
 static statement_t *parse_switch(void)
 {
-       eat(T_switch);
+       statement_t *statement = allocate_statement_zero(STATEMENT_SWITCH);
 
-       statement_t *statement          = allocate_statement_zero(STATEMENT_SWITCH);
-       statement->base.source_position = token.source_position;
+       eat(T_switch);
 
        PUSH_PARENT(statement);
 
@@ -9004,10 +9121,9 @@ static statement_t *parse_loop_body(statement_t *const loop)
  */
 static statement_t *parse_while(void)
 {
-       eat(T_while);
+       statement_t *statement = allocate_statement_zero(STATEMENT_WHILE);
 
-       statement_t *statement          = allocate_statement_zero(STATEMENT_WHILE);
-       statement->base.source_position = token.source_position;
+       eat(T_while);
 
        PUSH_PARENT(statement);
 
@@ -9031,12 +9147,11 @@ end_error:
  */
 static statement_t *parse_do(void)
 {
-       eat(T_do);
-
        statement_t *statement = allocate_statement_zero(STATEMENT_DO_WHILE);
-       statement->base.source_position = token.source_position;
 
-       PUSH_PARENT(statement)
+       eat(T_do);
+
+       PUSH_PARENT(statement);
 
        add_anchor_token(T_while);
        statement->do_while.body = parse_loop_body(statement);
@@ -9062,16 +9177,14 @@ end_error:
  */
 static statement_t *parse_for(void)
 {
-       eat(T_for);
+       statement_t *statement = allocate_statement_zero(STATEMENT_FOR);
 
-       statement_t *statement          = allocate_statement_zero(STATEMENT_FOR);
-       statement->base.source_position = token.source_position;
+       eat(T_for);
 
        PUSH_PARENT(statement);
 
-       int      top        = environment_top();
-       scope_t *last_scope = scope;
-       set_scope(&statement->fors.scope);
+       size_t const top = environment_top();
+       scope_push(&statement->fors.scope);
 
        expect('(');
        add_anchor_token(')');
@@ -9113,7 +9226,7 @@ static statement_t *parse_for(void)
        statement->fors.body = parse_loop_body(statement);
 
        assert(scope == &statement->fors.scope);
-       set_scope(last_scope);
+       scope_pop();
        environment_pop_to(top);
 
        POP_PARENT;
@@ -9123,7 +9236,7 @@ end_error:
        POP_PARENT;
        rem_anchor_token(')');
        assert(scope == &statement->fors.scope);
-       set_scope(last_scope);
+       scope_pop();
        environment_pop_to(top);
 
        return create_invalid_statement();
@@ -9134,10 +9247,9 @@ end_error:
  */
 static statement_t *parse_goto(void)
 {
-       source_position_t source_position = token.source_position;
+       statement_t *statement = allocate_statement_zero(STATEMENT_GOTO);
        eat(T_goto);
 
-       statement_t *statement;
        if (GNU_MODE && token.type == '*') {
                next_token();
                expression_t *expression = parse_expression();
@@ -9148,17 +9260,16 @@ static statement_t *parse_goto(void)
 
                if (type != type_error_type) {
                        if (!is_type_pointer(type) && !is_type_integer(type)) {
-                               errorf(&source_position, "cannot convert to a pointer type");
+                               errorf(&expression->base.source_position,
+                                       "cannot convert to a pointer type");
                        } else if (type != type_void_ptr) {
-                               warningf(&source_position,
+                               warningf(&expression->base.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;
+               statement->gotos.expression = expression;
        } else {
                if (token.type != T_IDENTIFIER) {
                        if (GNU_MODE)
@@ -9171,9 +9282,11 @@ static statement_t *parse_goto(void)
                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);
+               statement->gotos.label = get_label(symbol);
+
+               if (statement->gotos.label->parent_scope->depth < current_function->scope.depth) {
+                       statement->gotos.outer_fkt_jmp = true;
+               }
        }
 
        /* remember the goto's in a list for later checking */
@@ -9201,7 +9314,6 @@ static statement_t *parse_continue(void)
        }
 
        statement_t *statement = allocate_statement_zero(STATEMENT_CONTINUE);
-       statement->base.source_position = token.source_position;
 
        eat(T_continue);
        expect(';');
@@ -9220,7 +9332,6 @@ static statement_t *parse_break(void)
        }
 
        statement_t *statement = allocate_statement_zero(STATEMENT_BREAK);
-       statement->base.source_position = token.source_position;
 
        eat(T_break);
        expect(';');
@@ -9239,7 +9350,6 @@ static statement_t *parse_leave_statement(void)
        }
 
        statement_t *statement = allocate_statement_zero(STATEMENT_LEAVE);
-       statement->base.source_position = token.source_position;
 
        eat(T___leave);
        expect(';');
@@ -9312,11 +9422,10 @@ declaration_t *expr_is_variable(const expression_t *expression)
  */
 static statement_t *parse_return(void)
 {
-       statement_t *statement          = allocate_statement_zero(STATEMENT_RETURN);
-       statement->base.source_position = token.source_position;
-
        eat(T_return);
 
+       statement_t *statement = allocate_statement_zero(STATEMENT_RETURN);
+
        expression_t *return_value = NULL;
        if (token.type != ';') {
                return_value = parse_expression();
@@ -9370,8 +9479,6 @@ static statement_t *parse_declaration_statement(void)
 {
        statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION);
 
-       statement->base.source_position = token.source_position;
-
        declaration_t *before = last_declaration;
        if (GNU_MODE)
                parse_external_declaration();
@@ -9395,7 +9502,6 @@ static statement_t *parse_expression_statement(void)
 {
        statement_t *statement = allocate_statement_zero(STATEMENT_EXPRESSION);
 
-       statement->base.source_position  = token.source_position;
        expression_t *const expr         = parse_expression();
        statement->expression.expression = expr;
 
@@ -9412,7 +9518,6 @@ end_error:
 static statement_t *parse_ms_try_statment(void)
 {
        statement_t *statement = allocate_statement_zero(STATEMENT_MS_TRY);
-       statement->base.source_position  = token.source_position;
        eat(T___try);
 
        PUSH_PARENT(statement);
@@ -9465,7 +9570,6 @@ static statement_t *parse_empty_statement(void)
 
 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__);
 
@@ -9616,9 +9720,12 @@ expression_statment:
        case T___builtin_islessequal:
        case T___builtin_islessgreater:
        case T___builtin_isunordered:
+       case T___builtin_inf:
+       case T___builtin_inff:
+       case T___builtin_infl:
        case T___builtin_nan:
-       case T___builtin_nand:
        case T___builtin_nanf:
+       case T___builtin_nanl:
        case T___builtin_offsetof:
        case T___builtin_prefetch:
        case T___builtin_va_arg:
@@ -9672,21 +9779,24 @@ static statement_t *parse_statement(void)
 static statement_t *parse_compound_statement(bool inside_expression_statement)
 {
        statement_t *statement = allocate_statement_zero(STATEMENT_COMPOUND);
-       statement->base.source_position = token.source_position;
 
        PUSH_PARENT(statement);
 
        eat('{');
        add_anchor_token('}');
 
-       int      top        = environment_top();
-       int      top_local  = local_label_top();
-       scope_t *last_scope = scope;
-       set_scope(&statement->compound.scope);
+       size_t const top       = environment_top();
+       size_t const top_local = local_label_top();
+       scope_push(&statement->compound.scope);
 
        statement_t **anchor            = &statement->compound.statements;
        bool          only_decls_so_far = true;
-       while (token.type != '}' && token.type != T_EOF) {
+       while (token.type != '}') {
+               if (token.type == T_EOF) {
+                       errorf(&statement->base.source_position,
+                              "EOF while parsing compound statement");
+                       break;
+               }
                statement_t *sub_statement = intern_parse_statement();
                if (is_invalid_statement(sub_statement)) {
                        /* an error occurred. if we are at an anchor, return */
@@ -9711,13 +9821,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
 
                anchor = &sub_statement->base.next;
        }
-
-       if (token.type == '}') {
-               next_token();
-       } else {
-               errorf(&statement->base.source_position,
-                      "end of file while looking for closing '}'");
-       }
+       next_token();
 
        /* look over all statements again to produce no effect warnings */
        if (warning.unused_value) {
@@ -9741,7 +9845,7 @@ static statement_t *parse_compound_statement(bool inside_expression_statement)
 end_error:
        rem_anchor_token('}');
        assert(scope == &statement->compound.scope);
-       set_scope(last_scope);
+       scope_pop();
        environment_pop_to(top);
        local_label_pop_to(top_local);
 
@@ -9784,7 +9888,7 @@ static void check_unused_globals(void)
        if (!warning.unused_function && !warning.unused_variable)
                return;
 
-       for (const declaration_t *decl = global_scope->declarations; decl != NULL; decl = decl->next) {
+       for (const declaration_t *decl = file_scope->declarations; decl != NULL; decl = decl->next) {
                if (decl->used                  ||
                    decl->modifiers & DM_UNUSED ||
                    decl->modifiers & DM_USED   ||
@@ -9812,14 +9916,14 @@ static void check_unused_globals(void)
 
 static void parse_global_asm(void)
 {
+       statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
+
        eat(T_asm);
        expect('(');
 
-       statement_t *statement          = allocate_statement_zero(STATEMENT_ASM);
-       statement->base.source_position = token.source_position;
-       statement->asms.asm_text        = parse_string_literals();
-       statement->base.next            = unit->global_asm;
-       unit->global_asm                = statement;
+       statement->asms.asm_text = parse_string_literals();
+       statement->base.next     = unit->global_asm;
+       unit->global_asm         = statement;
 
        expect(')');
        expect(';');
@@ -9832,11 +9936,17 @@ end_error:;
  */
 static void parse_translation_unit(void)
 {
+       add_anchor_token(T_EOF);
+
+#ifndef NDEBUG
+       unsigned char token_anchor_copy[T_LAST_TOKEN];
+       memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy));
+#endif
        for (;;) {
 #ifndef NDEBUG
                bool anchor_leak = false;
                for (int i = 0; i != T_LAST_TOKEN; ++i) {
-                       unsigned char count = token_anchor_set[i];
+                       unsigned char count = token_anchor_set[i] - token_anchor_copy[i];
                        if (count != 0) {
                                errorf(HERE, "Leaked anchor token %k %d times", i, count);
                                anchor_leak = true;
@@ -9863,13 +9973,16 @@ static void parse_translation_unit(void)
                                break;
 
                        case T_EOF:
+                               rem_anchor_token(T_EOF);
                                return;
 
                        case ';':
-                               /* TODO error in strict mode */
-                               warningf(HERE, "stray ';' outside of function");
-                               next_token();
-                               break;
+                               if (!strict_mode) {
+                                       warningf(HERE, "stray ';' outside of function");
+                                       next_token();
+                                       break;
+                               }
+                               /* FALLTHROUGH */
 
                        default:
                                errorf(HERE, "stray %K outside of function", &token);
@@ -9901,24 +10014,25 @@ void start_parsing(void)
        assert(unit == NULL);
        unit = allocate_ast_zero(sizeof(unit[0]));
 
-       assert(global_scope == NULL);
-       global_scope = &unit->scope;
+       assert(file_scope == NULL);
+       file_scope = &unit->scope;
 
        assert(scope == NULL);
-       set_scope(&unit->scope);
+       scope_push(&unit->scope);
 
        initialize_builtin_types();
 }
 
 translation_unit_t *finish_parsing(void)
 {
+       /* do NOT use scope_pop() here, this will crash, will it by hand */
        assert(scope == &unit->scope);
-       scope          = NULL;
+       scope            = NULL;
        last_declaration = NULL;
 
-       assert(global_scope == &unit->scope);
+       assert(file_scope == &unit->scope);
        check_unused_globals();
-       global_scope = NULL;
+       file_scope = NULL;
 
        DEL_ARR_F(environment_stack);
        DEL_ARR_F(label_stack);