- implemented -Wunused-label
[cparser] / parser.c
index 051337a..c769d34 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -44,14 +44,16 @@ 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 context_t          *global_context    = NULL;
-static context_t          *context           = NULL;
+static scope_t            *global_scope      = NULL;
+static scope_t            *scope             = NULL;
 static declaration_t      *last_declaration  = NULL;
 static declaration_t      *current_function  = NULL;
 static switch_statement_t *current_switch    = NULL;
 static statement_t        *current_loop      = NULL;
 static goto_statement_t   *goto_first        = NULL;
 static goto_statement_t   *goto_last         = NULL;
+static label_statement_t  *label_first       = NULL;
+static label_statement_t  *label_last        = NULL;
 static struct obstack  temp_obst;
 
 /** The current source position. */
@@ -487,11 +489,11 @@ static void eat_paren(void)
     }                                              \
     next_token();
 
-static void set_context(context_t *new_context)
+static void set_scope(scope_t *new_scope)
 {
-       context = new_context;
+       scope = new_scope;
 
-       last_declaration = new_context->declarations;
+       last_declaration = new_scope->declarations;
        if(last_declaration != NULL) {
                while(last_declaration->next != NULL) {
                        last_declaration = last_declaration->next;
@@ -558,13 +560,13 @@ static void stack_push(stack_entry_t **stack_ptr, declaration_t *declaration)
 static void environment_push(declaration_t *declaration)
 {
        assert(declaration->source_position.input_name != NULL);
-       assert(declaration->parent_context != NULL);
+       assert(declaration->parent_scope != NULL);
        stack_push(&environment_stack, declaration);
 }
 
 static void label_push(declaration_t *declaration)
 {
-       declaration->parent_context = &current_function->context;
+       declaration->parent_scope = &current_function->scope;
        stack_push(&label_stack, declaration);
 }
 
@@ -983,19 +985,16 @@ static initializer_t *initializer_from_expression(type_t *type,
 }
 
 static initializer_t *parse_sub_initializer(type_t *type,
-                                            expression_t *expression,
-                                            type_t *expression_type);
+                                            expression_t *expression);
 
 static initializer_t *parse_sub_initializer_elem(type_t *type)
 {
        if(token.type == '{') {
-               return parse_sub_initializer(type, NULL, NULL);
+               return parse_sub_initializer(type, NULL);
        }
 
-       expression_t *expression      = parse_assignment_expression();
-       type_t       *expression_type = skip_typeref(expression->base.datatype);
-
-       return parse_sub_initializer(type, expression, expression_type);
+       expression_t *expression = parse_assignment_expression();
+       return parse_sub_initializer(type, expression);
 }
 
 static bool had_initializer_brace_warning;
@@ -1019,8 +1018,7 @@ static void skip_designator(void)
 }
 
 static initializer_t *parse_sub_initializer(type_t *type,
-                                            expression_t *expression,
-                                            type_t *expression_type)
+                                            expression_t *expression)
 {
        if(is_type_scalar(type)) {
                /* there might be extra {} hierarchies */
@@ -1030,7 +1028,7 @@ static initializer_t *parse_sub_initializer(type_t *type,
                                warningf(HERE, "braces around scalar initializer");
                                had_initializer_brace_warning = true;
                        }
-                       initializer_t *result = parse_sub_initializer(type, NULL, NULL);
+                       initializer_t *result = parse_sub_initializer(type, NULL);
                        if(token.type == ',') {
                                next_token();
                                /* TODO: warn about excessive elements */
@@ -1076,8 +1074,7 @@ static initializer_t *parse_sub_initializer(type_t *type,
                if(expression == NULL) {
                        sub = parse_sub_initializer_elem(element_type);
                } else {
-                       sub = parse_sub_initializer(element_type, expression,
-                                                   expression_type);
+                       sub = parse_sub_initializer(element_type, expression);
                }
 
                /* didn't match the subtypes -> try the parent type */
@@ -1107,7 +1104,7 @@ static initializer_t *parse_sub_initializer(type_t *type,
                }
        } else {
                assert(is_type_compound(type));
-               context_t *const context = &type->compound.declaration->context;
+               scope_t *const scope = &type->compound.declaration->scope;
 
                if(token.type == '[') {
                        errorf(HERE,
@@ -1116,7 +1113,7 @@ static initializer_t *parse_sub_initializer(type_t *type,
                        skip_designator();
                }
 
-               declaration_t *first = context->declarations;
+               declaration_t *first = scope->declarations;
                if(first == NULL)
                        return NULL;
                type_t *first_type = first->type;
@@ -1127,7 +1124,7 @@ static initializer_t *parse_sub_initializer(type_t *type,
                if(expression == NULL) {
                        sub = parse_sub_initializer_elem(first_type);
                } else {
-                       sub = parse_sub_initializer(first_type, expression,expression_type);
+                       sub = parse_sub_initializer(first_type, expression);
                }
 
                /* didn't match the subtypes -> try our parent type */
@@ -1216,7 +1213,7 @@ static initializer_t *parse_initializer(type_t *const orig_type)
                expect('}');
                return result;
        } else {
-               result = parse_sub_initializer(type, NULL, NULL);
+               result = parse_sub_initializer(type, NULL);
        }
 
        return result;
@@ -1267,7 +1264,7 @@ static declaration_t *parse_compound_type_specifier(bool is_struct)
                        (is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION);
                declaration->source_position = token.source_position;
                declaration->symbol          = symbol;
-               declaration->parent_context  = context;
+               declaration->parent_scope  = scope;
                if (symbol != NULL) {
                        environment_push(declaration);
                }
@@ -1279,19 +1276,19 @@ static declaration_t *parse_compound_type_specifier(bool is_struct)
                        assert(symbol != NULL);
                        errorf(HERE, "multiple definition of '%s %Y'",
                               is_struct ? "struct" : "union", symbol);
-                       declaration->context.declarations = NULL;
+                       declaration->scope.declarations = NULL;
                }
                declaration->init.is_defined = true;
 
-               int         top          = environment_top();
-               context_t  *last_context = context;
-               set_context(&declaration->context);
+               int       top        = environment_top();
+               scope_t  *last_scope = scope;
+               set_scope(&declaration->scope);
 
                parse_compound_type_entries();
                parse_attributes();
 
-               assert(context == &declaration->context);
-               set_context(last_context);
+               assert(scope == &declaration->scope);
+               set_scope(last_scope);
                environment_pop_to(top);
        }
 
@@ -1365,7 +1362,7 @@ static type_t *parse_enum_specifier(void)
                declaration->namespc         = NAMESPACE_ENUM;
                declaration->source_position = token.source_position;
                declaration->symbol          = symbol;
-               declaration->parent_context  = context;
+               declaration->parent_scope  = scope;
        }
 
        type_t *const type      = allocate_type_zero(TYPE_ENUM);
@@ -2025,7 +2022,7 @@ static construct_type_t *parse_function_declarator(declaration_t *declaration)
 
        declaration_t *parameters = parse_parameters(&type->function);
        if(declaration != NULL) {
-               declaration->context.declarations = parameters;
+               declaration->scope.declarations = parameters;
        }
 
        construct_function_type_t *construct_function_type =
@@ -2248,12 +2245,67 @@ static declaration_t *append_declaration(declaration_t* const declaration)
        if (last_declaration != NULL) {
                last_declaration->next = declaration;
        } else {
-               context->declarations = declaration;
+               scope->declarations = declaration;
        }
        last_declaration = declaration;
        return declaration;
 }
 
+/**
+ * Check if the declaration of main is suspicious.  main should be a
+ * function with external linkage, returning int, taking either zero
+ * arguments, two, or three arguments of appropriate types, ie.
+ *
+ * int main([ int argc, char **argv [, char **env ] ]).
+ *
+ * @param decl    the declaration to check
+ * @param type    the function type of the declaration
+ */
+static void check_type_of_main(const declaration_t *const decl, const function_type_t *const func_type)
+{
+       if (decl->storage_class == STORAGE_CLASS_STATIC) {
+               warningf(decl->source_position, "'main' is normally a non-static function");
+       }
+       if (skip_typeref(func_type->return_type) != type_int) {
+               warningf(decl->source_position, "return type of 'main' should be 'int', but is '%T'", func_type->return_type);
+       }
+       const function_parameter_t *parm = func_type->parameters;
+       if (parm != NULL) {
+               type_t *const first_type = parm->type;
+               if (!types_compatible(skip_typeref(first_type), type_int)) {
+                       warningf(decl->source_position, "first argument of 'main' should be 'int', but is '%T'", first_type);
+               }
+               parm = parm->next;
+               if (parm != NULL) {
+                       type_t *const second_type = parm->type;
+                       if (!types_compatible(skip_typeref(second_type), type_char_ptr_ptr)) {
+                               warningf(decl->source_position, "second argument of 'main' should be 'char**', but is '%T'", second_type);
+                       }
+                       parm = parm->next;
+                       if (parm != NULL) {
+                               type_t *const third_type = parm->type;
+                               if (!types_compatible(skip_typeref(third_type), type_char_ptr_ptr)) {
+                                       warningf(decl->source_position, "third argument of 'main' should be 'char**', but is '%T'", third_type);
+                               }
+                               parm = parm->next;
+                               if (parm != NULL) {
+                                       warningf(decl->source_position, "'main' takes only zero, two or three arguments");
+                               }
+                       }
+               } else {
+                       warningf(decl->source_position, "'main' takes only zero, two or three arguments");
+               }
+       }
+}
+
+/**
+ * Check if a symbol is the equal to "main".
+ */
+static bool is_sym_main(const symbol_t *const sym)
+{
+       return strcmp(sym->string, "main") == 0;
+}
+
 static declaration_t *internal_record_declaration(
        declaration_t *const declaration,
        const bool is_function_definition)
@@ -2261,19 +2313,24 @@ static declaration_t *internal_record_declaration(
        const symbol_t *const symbol  = declaration->symbol;
        const namespace_t     namespc = (namespace_t)declaration->namespc;
 
-       const type_t *const type = skip_typeref(declaration->type);
+       type_t       *const orig_type = declaration->type;
+       const type_t *const type      = skip_typeref(orig_type);
        if (is_type_function(type) &&
                        type->function.unspecified_parameters &&
                        warning.strict_prototypes) {
                warningf(declaration->source_position,
                         "function declaration '%#T' is not a prototype",
-                        type, declaration->symbol);
+                        orig_type, declaration->symbol);
+       }
+
+       if (is_function_definition && warning.main && is_sym_main(symbol)) {
+               check_type_of_main(declaration, &type->function);
        }
 
        declaration_t *const previous_declaration = get_declaration(symbol, namespc);
        assert(declaration != previous_declaration);
        if (previous_declaration != NULL) {
-               if (previous_declaration->parent_context == context) {
+               if (previous_declaration->parent_scope == scope) {
                        /* can happen for K&R style declarations */
                        if(previous_declaration->type == NULL) {
                                previous_declaration->type = declaration->type;
@@ -2283,7 +2340,7 @@ static declaration_t *internal_record_declaration(
                        if (!types_compatible(type, prev_type)) {
                                errorf(declaration->source_position,
                                        "declaration '%#T' is incompatible with previous declaration '%#T'",
-                                       type, symbol, previous_declaration->type, symbol);
+                                       orig_type, symbol, previous_declaration->type, symbol);
                                errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
                        } else {
                                unsigned old_storage_class = previous_declaration->storage_class;
@@ -2297,7 +2354,13 @@ static declaration_t *internal_record_declaration(
                                                        old_storage_class = STORAGE_CLASS_EXTERN;
 
                                                case STORAGE_CLASS_EXTERN:
-                                                       if (new_storage_class == STORAGE_CLASS_NONE && !is_function_definition) {
+                                                       if (is_function_definition) {
+                                                               if (warning.missing_prototypes &&
+                                                                   prev_type->function.unspecified_parameters &&
+                                                                   !is_sym_main(symbol)) {
+                                                                       warningf(declaration->source_position, "no previous prototype for '%#T'", orig_type, symbol);
+                                                               }
+                                                       } else if (new_storage_class == STORAGE_CLASS_NONE) {
                                                                new_storage_class = STORAGE_CLASS_EXTERN;
                                                        }
                                                        break;
@@ -2308,7 +2371,7 @@ static declaration_t *internal_record_declaration(
 
                                if (old_storage_class == STORAGE_CLASS_EXTERN &&
                                                new_storage_class == STORAGE_CLASS_EXTERN) {
-       warn_redundant_declaration:
+warn_redundant_declaration:
                                        if (warning.redundant_decls) {
                                                warningf(declaration->source_position, "redundant declaration for '%Y'", symbol);
                                                warningf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
@@ -2337,17 +2400,28 @@ static declaration_t *internal_record_declaration(
                        }
                        return previous_declaration;
                }
-       } else if (is_function_definition &&
-                       declaration->storage_class != STORAGE_CLASS_STATIC &&
-                       warning.missing_declarations) {
-               warningf(declaration->source_position, "no previous declaration for '%#T'", type, symbol);
+       } else if (is_function_definition) {
+               if (declaration->storage_class != STORAGE_CLASS_STATIC) {
+                       if (warning.missing_prototypes && !is_sym_main(symbol)) {
+                               warningf(declaration->source_position, "no previous prototype for '%#T'", orig_type, symbol);
+                       } else if (warning.missing_declarations && !is_sym_main(symbol)) {
+                               warningf(declaration->source_position, "no previous declaration for '%#T'", orig_type, symbol);
+                       }
+               }
+       } else if (warning.missing_declarations &&
+           scope == global_scope &&
+           !is_type_function(type) && (
+             declaration->storage_class == STORAGE_CLASS_NONE ||
+             declaration->storage_class == STORAGE_CLASS_THREAD
+           )) {
+               warningf(declaration->source_position, "no previous declaration for '%#T'", orig_type, symbol);
        }
 
-       assert(declaration->parent_context == NULL);
+       assert(declaration->parent_scope == NULL);
        assert(declaration->symbol != NULL);
-       assert(context != NULL);
+       assert(scope != NULL);
 
-       declaration->parent_context = context;
+       declaration->parent_scope = scope;
 
        environment_push(declaration);
        return append_declaration(declaration);
@@ -2528,7 +2602,7 @@ static declaration_t *finished_kr_declaration(declaration_t *declaration)
 
        declaration_t *previous_declaration = get_declaration(symbol, namespc);
        if(previous_declaration == NULL ||
-                       previous_declaration->parent_context != context) {
+                       previous_declaration->parent_scope != scope) {
                errorf(HERE, "expected declaration of a function parameter, found '%Y'",
                       symbol);
                return declaration;
@@ -2537,7 +2611,7 @@ static declaration_t *finished_kr_declaration(declaration_t *declaration)
        if(previous_declaration->type == NULL) {
                previous_declaration->type           = declaration->type;
                previous_declaration->storage_class  = declaration->storage_class;
-               previous_declaration->parent_context = context;
+               previous_declaration->parent_scope = scope;
                return previous_declaration;
        } else {
                return record_declaration(declaration);
@@ -2568,14 +2642,14 @@ static void parse_kr_declaration_list(declaration_t *declaration)
                return;
 
        /* push function parameters */
-       int         top          = environment_top();
-       context_t  *last_context = context;
-       set_context(&declaration->context);
+       int       top        = environment_top();
+       scope_t  *last_scope = scope;
+       set_scope(&declaration->scope);
 
-       declaration_t *parameter = declaration->context.declarations;
+       declaration_t *parameter = declaration->scope.declarations;
        for( ; parameter != NULL; parameter = parameter->next) {
-               assert(parameter->parent_context == NULL);
-               parameter->parent_context = context;
+               assert(parameter->parent_scope == NULL);
+               parameter->parent_scope = scope;
                environment_push(parameter);
        }
 
@@ -2585,8 +2659,8 @@ static void parse_kr_declaration_list(declaration_t *declaration)
        }
 
        /* pop function parameters */
-       assert(context == &declaration->context);
-       set_context(last_context);
+       assert(scope == &declaration->scope);
+       set_scope(last_scope);
        environment_pop_to(top);
 
        /* update function type */
@@ -2596,7 +2670,7 @@ static void parse_kr_declaration_list(declaration_t *declaration)
        function_parameter_t *parameters     = NULL;
        function_parameter_t *last_parameter = NULL;
 
-       declaration_t *parameter_declaration = declaration->context.declarations;
+       declaration_t *parameter_declaration = declaration->scope.declarations;
        for( ; parameter_declaration != NULL;
                        parameter_declaration = parameter_declaration->next) {
                type_t *parameter_type = parameter_declaration->type;
@@ -2641,27 +2715,49 @@ static void parse_kr_declaration_list(declaration_t *declaration)
 
 /**
  * Check if all labels are defined in the current function.
+ * Check if all labels are used in the current function.
  */
-static void check_for_missing_labels(void)
+static void check_labels(void)
 {
        bool first_err = true;
        for (const goto_statement_t *goto_statement = goto_first;
-            goto_statement != NULL;
-            goto_statement = goto_statement->next) {
-                const declaration_t *label = goto_statement->label;
-
-                if (label->source_position.input_name == NULL) {
-                        if (first_err) {
-                                first_err = false;
-                                diagnosticf("%s: In function '%Y':\n",
-                                        current_function->source_position.input_name,
-                                        current_function->symbol);
-                        }
-                        errorf(goto_statement->statement.source_position,
-                                "label '%Y' used but not defined", label->symbol);
+           goto_statement != NULL;
+           goto_statement = goto_statement->next) {
+               declaration_t *label = goto_statement->label;
+
+               label->used = true;
+               if (label->source_position.input_name == NULL) {
+                       if (first_err) {
+                               first_err = false;
+                               diagnosticf("%s: In function '%Y':\n",
+                                       current_function->source_position.input_name,
+                                       current_function->symbol);
+                       }
+                       errorf(goto_statement->statement.source_position,
+                               "label '%Y' used but not defined", label->symbol);
                 }
        }
        goto_first = goto_last = NULL;
+
+       if (warning.unused_label) {
+               for (const label_statement_t *label_statement = label_first;
+                        label_statement != NULL;
+                        label_statement = label_statement->next) {
+                       const declaration_t *label = label_statement->label;
+
+                       if (! label->used) {
+                               if (first_err) {
+                                       first_err = false;
+                                       diagnosticf("%s: In function '%Y':\n",
+                                               current_function->source_position.input_name,
+                                               current_function->symbol);
+                               }
+                               warningf(label_statement->statement.source_position,
+                                       "label '%Y' defined but not used", label->symbol);
+                       }
+               }
+       }
+       label_first = label_last = NULL;
 }
 
 static void parse_external_declaration(void)
@@ -2724,23 +2820,23 @@ static void parse_external_declaration(void)
 
        declaration_t *const declaration = record_function_definition(ndeclaration);
        if(ndeclaration != declaration) {
-               declaration->context = ndeclaration->context;
+               declaration->scope = ndeclaration->scope;
        }
        type = skip_typeref(declaration->type);
 
-       /* push function parameters and switch context */
-       int         top          = environment_top();
-       context_t  *last_context = context;
-       set_context(&declaration->context);
+       /* push function parameters and switch scope */
+       int       top        = environment_top();
+       scope_t  *last_scope = scope;
+       set_scope(&declaration->scope);
 
-       declaration_t *parameter = declaration->context.declarations;
+       declaration_t *parameter = declaration->scope.declarations;
        for( ; parameter != NULL; parameter = parameter->next) {
-               if(parameter->parent_context == &ndeclaration->context) {
-                       parameter->parent_context = context;
+               if(parameter->parent_scope == &ndeclaration->scope) {
+                       parameter->parent_scope = scope;
                }
-               assert(parameter->parent_context == NULL
-                               || parameter->parent_context == context);
-               parameter->parent_context = context;
+               assert(parameter->parent_scope == NULL
+                               || parameter->parent_scope == scope);
+               parameter->parent_scope = scope;
                environment_push(parameter);
        }
 
@@ -2755,7 +2851,7 @@ static void parse_external_declaration(void)
                current_function                    = declaration;
 
                declaration->init.statement = parse_compound_statement();
-               check_for_missing_labels();
+               check_labels();
 
                assert(current_function == declaration);
                current_function = old_current_function;
@@ -2763,8 +2859,8 @@ static void parse_external_declaration(void)
        }
 
 end_of_parse_external_declaration:
-       assert(context == &declaration->context);
-       set_context(last_context);
+       assert(scope == &declaration->scope);
+       set_scope(last_scope);
        environment_pop_to(top);
 }
 
@@ -2961,18 +3057,18 @@ static declaration_t *create_implicit_function(symbol_t *symbol,
        declaration->type            = type;
        declaration->symbol          = symbol;
        declaration->source_position = source_position;
-       declaration->parent_context  = global_context;
+       declaration->parent_scope  = global_scope;
 
-       context_t *old_context = context;
-       set_context(global_context);
+       scope_t *old_scope = scope;
+       set_scope(global_scope);
 
        environment_push(declaration);
-       /* prepend the declaration to the global declarations list */
-       declaration->next     = context->declarations;
-       context->declarations = declaration;
+       /* prepends the declaration to the global declarations list */
+       declaration->next   = scope->declarations;
+       scope->declarations = declaration;
 
-       assert(context == global_context);
-       set_context(old_context);
+       assert(scope == global_scope);
+       set_scope(old_scope);
 
        return declaration;
 }
@@ -3317,7 +3413,7 @@ static expression_t *parse_va_start(void)
        expression_t *const expr = parse_assignment_expression();
        if (expr->kind == EXPR_REFERENCE) {
                declaration_t *const decl = expr->reference.declaration;
-               if (decl->parent_context == &current_function->context &&
+               if (decl->parent_scope == &current_function->scope &&
                    decl->next == NULL) {
                        expression->va_starte.parameter = decl;
                        expect(')');
@@ -3694,7 +3790,7 @@ static expression_t *parse_select_expression(unsigned precedence,
                return create_invalid_expression();
        }
 
-       declaration_t *iter = declaration->context.declarations;
+       declaration_t *iter = declaration->scope.declarations;
        for( ; iter != NULL; iter = iter->next) {
                if(iter->symbol == symbol) {
                        break;
@@ -3785,7 +3881,7 @@ static expression_t *parse_call_expression(unsigned precedence,
                for( ; parameter != NULL && argument != NULL;
                                parameter = parameter->next, argument = argument->next) {
                        type_t *expected_type = parameter->type;
-                       /* TODO report context in error messages */
+                       /* TODO report scope in error messages */
                        expression_t *const arg_expr = argument->expression;
                        type_t       *const res_type = semantic_assign(expected_type, arg_expr, "function call");
                        if (res_type == NULL) {
@@ -3943,6 +4039,7 @@ static void semantic_incdec(unary_expression_t *expression)
 {
        type_t *const orig_type = expression->value->base.datatype;
        type_t *const type      = skip_typeref(orig_type);
+       /* TODO !is_type_real && !is_type_pointer */
        if(!is_type_arithmetic(type) && type->kind != TYPE_POINTER) {
                if (is_type_valid(type)) {
                        /* TODO: improve error message */
@@ -4239,6 +4336,11 @@ static void semantic_sub(binary_expression_t *expression)
        }
 }
 
+/**
+ * Check the semantics of comparison expressions.
+ *
+ * @param expression   The expression to check.
+ */
 static void semantic_comparison(binary_expression_t *expression)
 {
        expression_t *left            = expression->left;
@@ -4255,6 +4357,13 @@ static void semantic_comparison(binary_expression_t *expression)
                expression->left  = create_implicit_cast(left, arithmetic_type);
                expression->right = create_implicit_cast(right, arithmetic_type);
                expression->expression.datatype = arithmetic_type;
+               if (warning.float_equal &&
+                   (expression->expression.kind == EXPR_BINARY_EQUAL ||
+                    expression->expression.kind == EXPR_BINARY_NOTEQUAL) &&
+                   is_type_floating(arithmetic_type)) {
+                       warningf(expression->expression.source_position,
+                                "comparing floating point with == or != is unsafe");
+               }
        } else if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
                /* TODO check compatibility */
        } else if (is_type_pointer(type_left)) {
@@ -4263,7 +4372,8 @@ static void semantic_comparison(binary_expression_t *expression)
                expression->left = create_implicit_cast(left, type_right);
        } else if (is_type_valid(type_left) && is_type_valid(type_right)) {
                type_error_incompatible("invalid operands in comparison",
-                                       token.source_position, type_left, type_right);
+                                       expression->expression.source_position,
+                                       type_left, type_right);
        }
        expression->expression.datatype = type_int;
 }
@@ -4347,8 +4457,8 @@ static void semantic_logical_op(binary_expression_t *expression)
  */
 static bool has_const_fields(const compound_type_t *type)
 {
-       const context_t     *context = &type->declaration->context;
-       const declaration_t *declaration = context->declarations;
+       const scope_t       *scope       = &type->declaration->scope;
+       const declaration_t *declaration = scope->declarations;
 
        for (; declaration != NULL; declaration = declaration->next) {
                if (declaration->namespc != NAMESPACE_NORMAL)
@@ -4408,8 +4518,115 @@ static void semantic_binexpr_assign(binary_expression_t *expression)
        expression->expression.datatype = orig_type_left;
 }
 
+static bool expression_has_effect(const expression_t *const expr)
+{
+       switch (expr->kind) {
+               case EXPR_UNKNOWN:                   break;
+               case EXPR_INVALID:                   break;
+               case EXPR_REFERENCE:                 return false;
+               case EXPR_CONST:                     return false;
+               case EXPR_STRING_LITERAL:            return false;
+               case EXPR_WIDE_STRING_LITERAL:       return false;
+               case EXPR_CALL: {
+                       const call_expression_t *const call = &expr->call;
+                       if (call->function->kind != EXPR_BUILTIN_SYMBOL)
+                               return true;
+
+                       switch (call->function->builtin_symbol.symbol->ID) {
+                               case T___builtin_va_end: return true;
+                               default:                 return false;
+                       }
+               }
+               case EXPR_CONDITIONAL: {
+                       const conditional_expression_t *const cond = &expr->conditional;
+                       return
+                               expression_has_effect(cond->true_expression) &&
+                               expression_has_effect(cond->false_expression);
+               }
+               case EXPR_SELECT:                    return false;
+               case EXPR_ARRAY_ACCESS:              return false;
+               case EXPR_SIZEOF:                    return false;
+               case EXPR_CLASSIFY_TYPE:             return false;
+               case EXPR_ALIGNOF:                   return false;
+
+               case EXPR_FUNCTION:                  return false;
+               case EXPR_PRETTY_FUNCTION:           return false;
+               case EXPR_BUILTIN_SYMBOL:            break; /* handled in EXPR_CALL */
+               case EXPR_BUILTIN_CONSTANT_P:        return false;
+               case EXPR_BUILTIN_PREFETCH:          return true;
+               case EXPR_OFFSETOF:                  return false;
+               case EXPR_VA_START:                  return true;
+               case EXPR_VA_ARG:                    return true;
+               case EXPR_STATEMENT:                 return true; // TODO
+
+               case EXPR_UNARY_NEGATE:              return false;
+               case EXPR_UNARY_PLUS:                return false;
+               case EXPR_UNARY_BITWISE_NEGATE:      return false;
+               case EXPR_UNARY_NOT:                 return false;
+               case EXPR_UNARY_DEREFERENCE:         return false;
+               case EXPR_UNARY_TAKE_ADDRESS:        return false;
+               case EXPR_UNARY_POSTFIX_INCREMENT:   return true;
+               case EXPR_UNARY_POSTFIX_DECREMENT:   return true;
+               case EXPR_UNARY_PREFIX_INCREMENT:    return true;
+               case EXPR_UNARY_PREFIX_DECREMENT:    return true;
+               case EXPR_UNARY_CAST:
+                       return is_type_atomic(expr->base.datatype, ATOMIC_TYPE_VOID);
+               case EXPR_UNARY_CAST_IMPLICIT:       return true;
+               case EXPR_UNARY_ASSUME:              return true;
+               case EXPR_UNARY_BITFIELD_EXTRACT:    return false;
+
+               case EXPR_BINARY_ADD:                return false;
+               case EXPR_BINARY_SUB:                return false;
+               case EXPR_BINARY_MUL:                return false;
+               case EXPR_BINARY_DIV:                return false;
+               case EXPR_BINARY_MOD:                return false;
+               case EXPR_BINARY_EQUAL:              return false;
+               case EXPR_BINARY_NOTEQUAL:           return false;
+               case EXPR_BINARY_LESS:               return false;
+               case EXPR_BINARY_LESSEQUAL:          return false;
+               case EXPR_BINARY_GREATER:            return false;
+               case EXPR_BINARY_GREATEREQUAL:       return false;
+               case EXPR_BINARY_BITWISE_AND:        return false;
+               case EXPR_BINARY_BITWISE_OR:         return false;
+               case EXPR_BINARY_BITWISE_XOR:        return false;
+               case EXPR_BINARY_SHIFTLEFT:          return false;
+               case EXPR_BINARY_SHIFTRIGHT:         return false;
+               case EXPR_BINARY_ASSIGN:             return true;
+               case EXPR_BINARY_MUL_ASSIGN:         return true;
+               case EXPR_BINARY_DIV_ASSIGN:         return true;
+               case EXPR_BINARY_MOD_ASSIGN:         return true;
+               case EXPR_BINARY_ADD_ASSIGN:         return true;
+               case EXPR_BINARY_SUB_ASSIGN:         return true;
+               case EXPR_BINARY_SHIFTLEFT_ASSIGN:   return true;
+               case EXPR_BINARY_SHIFTRIGHT_ASSIGN:  return true;
+               case EXPR_BINARY_BITWISE_AND_ASSIGN: return true;
+               case EXPR_BINARY_BITWISE_XOR_ASSIGN: return true;
+               case EXPR_BINARY_BITWISE_OR_ASSIGN:  return true;
+               case EXPR_BINARY_LOGICAL_AND:
+               case EXPR_BINARY_LOGICAL_OR:
+               case EXPR_BINARY_COMMA:
+                       return expression_has_effect(expr->binary.right);
+
+               case EXPR_BINARY_BUILTIN_EXPECT:     return true;
+               case EXPR_BINARY_ISGREATER:          return false;
+               case EXPR_BINARY_ISGREATEREQUAL:     return false;
+               case EXPR_BINARY_ISLESS:             return false;
+               case EXPR_BINARY_ISLESSEQUAL:        return false;
+               case EXPR_BINARY_ISLESSGREATER:      return false;
+               case EXPR_BINARY_ISUNORDERED:        return false;
+       }
+
+       panic("unexpected statement");
+}
+
 static void semantic_comma(binary_expression_t *expression)
 {
+       if (warning.unused_value) {
+               const expression_t *const left = expression->left;
+               if (!expression_has_effect(left)) {
+                       warningf(left->base.source_position, "left-hand operand of comma expression has no effect");
+               }
+       }
        expression->expression.datatype = expression->right->base.datatype;
 }
 
@@ -4854,7 +5071,7 @@ static declaration_t *get_label(symbol_t *symbol)
        /* if we found a label in the same function, then we already created the
         * declaration */
        if(candidate != NULL
-                       && candidate->parent_context == &current_function->context) {
+                       && candidate->parent_scope == &current_function->scope) {
                return candidate;
        }
 
@@ -4902,7 +5119,21 @@ static statement_t *parse_label_statement(void)
                errorf(HERE, "label at end of compound statement");
                return (statement_t*) label_statement;
        } else {
-               label_statement->label_statement = parse_statement();
+               if (token.type == ';') {
+                       /* eat an empty statement here, to avoid the warning about an empty
+                        * after a label.  label:; is commonly used to have a label before
+                        * a }. */
+                       next_token();
+               } else {
+                       label_statement->label_statement = parse_statement();
+               }
+       }
+
+       /* remember the labels's in a list for later checking */
+       if (label_last == NULL) {
+               label_first = label_last = label_statement;
+       } else {
+               label_last->next = label_statement;
        }
 
        return (statement_t*) label_statement;
@@ -4960,6 +5191,10 @@ static statement_t *parse_switch(void)
        statement->body = parse_statement();
        current_switch  = rem;
 
+       if (warning.switch_default && find_default_label(statement) == NULL) {
+               warningf(statement->statement.source_position, "switch has no default case");
+       }
+
        return (statement_t*) statement;
 }
 
@@ -5026,9 +5261,9 @@ static statement_t *parse_for(void)
 
        expect('(');
 
-       int         top          = environment_top();
-       context_t  *last_context = context;
-       set_context(&statement->context);
+       int      top        = environment_top();
+       scope_t *last_scope = scope;
+       set_scope(&statement->scope);
 
        if(token.type != ';') {
                if(is_declaration_specifier(&token, false)) {
@@ -5051,8 +5286,8 @@ static statement_t *parse_for(void)
        expect(')');
        statement->body = parse_loop_body((statement_t*)statement);
 
-       assert(context == &statement->context);
-       set_context(last_context);
+       assert(scope == &statement->scope);
+       set_scope(last_scope);
        environment_pop_to(top);
 
        return (statement_t*) statement;
@@ -5241,7 +5476,7 @@ static statement_t *parse_declaration_statement(void)
        parse_declaration(record_declaration);
 
        if(before == NULL) {
-               statement->declaration.declarations_begin = context->declarations;
+               statement->declaration.declarations_begin = scope->declarations;
        } else {
                statement->declaration.declarations_begin = before->next;
        }
@@ -5258,7 +5493,12 @@ static statement_t *parse_expression_statement(void)
        statement_t *statement = allocate_statement_zero(STATEMENT_EXPRESSION);
 
        statement->base.source_position  = token.source_position;
-       statement->expression.expression = parse_expression();
+       expression_t *const expr         = parse_expression();
+       statement->expression.expression = expr;
+
+       if (warning.unused_value  && !expression_has_effect(expr)) {
+               warningf(expr->base.source_position, "statement has no effect");
+       }
 
        expect(';');
 
@@ -5327,6 +5567,9 @@ static statement_t *parse_statement(void)
                break;
 
        case ';':
+               if (warning.empty_statement) {
+                       warningf(HERE, "statement is empty");
+               }
                next_token();
                statement = NULL;
                break;
@@ -5381,9 +5624,9 @@ static statement_t *parse_compound_statement(void)
 
        eat('{');
 
-       int        top          = environment_top();
-       context_t *last_context = context;
-       set_context(&compound_statement->context);
+       int      top        = environment_top();
+       scope_t *last_scope = scope;
+       set_scope(&compound_statement->scope);
 
        statement_t *last_statement = NULL;
 
@@ -5410,8 +5653,8 @@ static statement_t *parse_compound_statement(void)
                errorf(compound_statement->statement.source_position, "end of file while looking for closing '}'");
        }
 
-       assert(context == &compound_statement->context);
-       set_context(last_context);
+       assert(scope == &compound_statement->scope);
+       set_scope(last_scope);
        environment_pop_to(top);
 
        return (statement_t*) compound_statement;
@@ -5444,11 +5687,11 @@ static translation_unit_t *parse_translation_unit(void)
 {
        translation_unit_t *unit = allocate_ast_zero(sizeof(unit[0]));
 
-       assert(global_context == NULL);
-       global_context = &unit->context;
+       assert(global_scope == NULL);
+       global_scope = &unit->scope;
 
-       assert(context == NULL);
-       set_context(&unit->context);
+       assert(scope == NULL);
+       set_scope(&unit->scope);
 
        initialize_builtin_types();
 
@@ -5462,12 +5705,12 @@ static translation_unit_t *parse_translation_unit(void)
                }
        }
 
-       assert(context == &unit->context);
-       context          = NULL;
+       assert(scope == &unit->scope);
+       scope          = NULL;
        last_declaration = NULL;
 
-       assert(global_context == &unit->context);
-       global_context = NULL;
+       assert(global_scope == &unit->scope);
+       global_scope = NULL;
 
        return unit;
 }