Slightly simplify stack_pop_to().
[cparser] / parser.c
index fd17b0a..b800fb8 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;
+/** The global file scope. */
 static scope_t            *global_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;
@@ -713,16 +716,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 +761,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,30 +839,20 @@ 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;
                }
+
+               /* Because of scopes and appending other namespaces to the end of
+                * the list, this must hold. */
+               assert((old_declaration != NULL ? old_declaration->symbol_next : NULL) == iter->symbol_next);
+               *anchor = old_declaration;
        }
 
        ARR_SHRINKLEN(*stack_ptr, (int) new_top);
@@ -3674,7 +3668,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 +3698,7 @@ static declaration_t *parse_identifier_list(void)
                next_token();
        } while (token.type == T_IDENTIFIER);
 
+       *last = last_declaration;
        return declarations;
 }
 
@@ -3750,7 +3751,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 +3770,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 +3836,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 +3977,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 =
@@ -4394,8 +4406,17 @@ static declaration_t *record_declaration(
        }
 
        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;
@@ -4527,7 +4548,7 @@ warn_redundant_declaration:
                                 "no previous declaration for '%#T'", orig_type, symbol);
                }
        }
-
+finish:
        assert(declaration->parent_scope == NULL);
        assert(scope != NULL);
 
@@ -4760,10 +4781,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 +4801,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 +4860,8 @@ static void parse_kr_declaration_list(declaration_t *declaration)
        }
 
        declaration->type = type;
+
+       rem_anchor_token('{');
 }
 
 static bool first_err = true;
@@ -5398,13 +5422,15 @@ static void parse_external_declaration(void)
        add_anchor_token(',');
        add_anchor_token('=');
        add_anchor_token(';');
+       add_anchor_token('{');
 
        /* declarator is common to both function-definitions and declarations */
        declaration_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false);
 
-       rem_anchor_token(',');
-       rem_anchor_token('=');
+       rem_anchor_token('{');
        rem_anchor_token(';');
+       rem_anchor_token('=');
+       rem_anchor_token(',');
 
        /* must be a declaration */
        switch (token.type) {
@@ -5473,9 +5499,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) {
@@ -5530,7 +5555,7 @@ static void parse_external_declaration(void)
        }
 
        assert(scope == &declaration->scope);
-       set_scope(last_scope);
+       scope_pop();
        environment_pop_to(top);
 }
 
@@ -6106,11 +6131,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;
@@ -6118,6 +6143,15 @@ static expression_t *parse_reference(void)
        /* this declaration is used */
        declaration->used = true;
 
+       if (declaration->parent_scope != global_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) {
@@ -6699,7 +6733,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;
        }
 
@@ -7494,6 +7531,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;
@@ -7503,6 +7580,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;
 }
 
@@ -7850,6 +7929,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.
  *
@@ -7857,13 +7952,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)) {
@@ -8056,6 +8170,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)) {
@@ -9067,9 +9184,8 @@ static statement_t *parse_for(void)
 
        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(')');
@@ -9111,7 +9227,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;
@@ -9121,7 +9237,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();
@@ -9172,6 +9288,10 @@ static statement_t *parse_goto(void)
                statement                       = allocate_statement_zero(STATEMENT_GOTO);
                statement->base.source_position = source_position;
                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 */
@@ -9555,7 +9675,7 @@ expression_statment:
                bool old_gcc_extension = in_gcc_extension;
                in_gcc_extension       = true;
                statement = parse_statement();
-               in_gcc_extension = false;
+               in_gcc_extension = old_gcc_extension;
                break;
 
        DECLARATION_START
@@ -9677,10 +9797,9 @@ static statement_t *parse_compound_statement(bool inside_expression_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;
@@ -9739,7 +9858,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);
 
@@ -9903,15 +10022,16 @@ void start_parsing(void)
        global_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);