add option -l and -L, reorganize option handler
[cparser] / parser.c
index a42e169..5ae71c7 100644 (file)
--- a/parser.c
+++ b/parser.c
 #include "type_hash.h"
 #include "ast_t.h"
 #include "lang_features.h"
+#include "warning.h"
 #include "adt/bitfiddle.h"
 #include "adt/error.h"
 #include "adt/array.h"
 
 //#define PRINT_TOKENS
-//#define ABORT_ON_ERROR
 #define MAX_LOOKAHEAD 2
 
 typedef struct {
@@ -639,15 +639,13 @@ static int get_rank(const type_t *type)
                return ATOMIC_TYPE_INT;
 
        assert(type->kind == TYPE_ATOMIC);
-       const atomic_type_t *atomic_type = &type->atomic;
-       atomic_type_kind_t   atype       = atomic_type->akind;
-       return atype;
+       return type->atomic.akind;
 }
 
 static type_t *promote_integer(type_t *type)
 {
        if(type->kind == TYPE_BITFIELD)
-               return promote_integer(type->bitfield.base);
+               type = type->bitfield.base;
 
        if(get_rank(type) < ATOMIC_TYPE_INT)
                type = type_int;
@@ -704,77 +702,12 @@ static bool is_null_pointer_constant(const expression_t *expression)
 static expression_t *create_implicit_cast(expression_t *expression,
                                           type_t *dest_type)
 {
-       type_t *source_type = expression->base.datatype;
+       type_t *const source_type = expression->base.datatype;
 
-       if(source_type == NULL)
+       if (source_type == dest_type)
                return expression;
 
-       source_type = skip_typeref(source_type);
-       dest_type   = skip_typeref(dest_type);
-
-       if(source_type == dest_type)
-               return expression;
-
-       switch (dest_type->kind) {
-               case TYPE_ENUM:
-                       /* TODO warning for implicitly converting to enum */
-               case TYPE_BITFIELD:
-               case TYPE_ATOMIC:
-                       if (source_type->kind != TYPE_ATOMIC &&
-                                       source_type->kind != TYPE_ENUM &&
-                                       source_type->kind != TYPE_BITFIELD) {
-                               panic("casting of non-atomic types not implemented yet");
-                       }
-
-                       if(is_type_floating(dest_type) && !is_type_scalar(source_type)) {
-                               type_error_incompatible("can't cast types",
-                                               expression->base.source_position, source_type,
-                                               dest_type);
-                               return expression;
-                       }
-
-                       return create_cast_expression(expression, dest_type);
-
-               case TYPE_POINTER:
-                       switch (source_type->kind) {
-                               case TYPE_ATOMIC:
-                                       if (is_null_pointer_constant(expression)) {
-                                               return create_cast_expression(expression, dest_type);
-                                       }
-                                       break;
-
-                               case TYPE_POINTER:
-                                       if (pointers_compatible(source_type, dest_type)) {
-                                               return create_cast_expression(expression, dest_type);
-                                       }
-                                       break;
-
-                               case TYPE_ARRAY: {
-                                       array_type_t   *array_type   = &source_type->array;
-                                       pointer_type_t *pointer_type = &dest_type->pointer;
-                                       if (types_compatible(array_type->element_type,
-                                                                                pointer_type->points_to)) {
-                                               return create_cast_expression(expression, dest_type);
-                                       }
-                                       break;
-                               }
-
-                               default:
-                                       panic("casting of non-atomic types not implemented yet");
-                       }
-
-                       type_error_incompatible("can't implicitly cast types",
-                                       expression->base.source_position, source_type, dest_type);
-                       return expression;
-
-               case TYPE_COMPOUND_STRUCT:
-               case TYPE_COMPOUND_UNION:
-               case TYPE_ERROR:
-                       return expression;
-
-               default:
-                       panic("casting of non-atomic types not implemented yet");
-       }
+       return create_cast_expression(expression, dest_type);
 }
 
 /** Implements the rules from § 6.5.16.1 */
@@ -783,12 +716,8 @@ static type_t *semantic_assign(type_t *orig_type_left,
                             const char *context)
 {
        type_t *const orig_type_right = right->base.datatype;
-
-       if (!is_type_valid(orig_type_right))
-               return orig_type_right;
-
-       type_t *const type_left  = skip_typeref(orig_type_left);
-       type_t *const type_right = skip_typeref(orig_type_right);
+       type_t *const type_left       = skip_typeref(orig_type_left);
+       type_t *const type_right      = skip_typeref(orig_type_right);
 
        if ((is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) ||
            (is_type_pointer(type_left) && is_null_pointer_constant(right)) ||
@@ -798,13 +727,8 @@ static type_t *semantic_assign(type_t *orig_type_left,
        }
 
        if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
-               pointer_type_t *pointer_type_left  = &type_left->pointer;
-               pointer_type_t *pointer_type_right = &type_right->pointer;
-               type_t         *points_to_left     = pointer_type_left->points_to;
-               type_t         *points_to_right    = pointer_type_right->points_to;
-
-               points_to_left  = skip_typeref(points_to_left);
-               points_to_right = skip_typeref(points_to_right);
+               type_t *points_to_left  = skip_typeref(type_left->pointer.points_to);
+               type_t *points_to_right = skip_typeref(type_right->pointer.points_to);
 
                /* the left type has all qualifiers from the right type */
                unsigned missing_qualifiers
@@ -834,6 +758,12 @@ static type_t *semantic_assign(type_t *orig_type_left,
                }
        }
 
+       if (!is_type_valid(type_left))
+               return type_left;
+
+       if (!is_type_valid(type_right))
+               return orig_type_right;
+
        return NULL;
 }
 
@@ -1053,19 +983,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;
@@ -1089,8 +1016,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 */
@@ -1100,7 +1026,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 */
@@ -1132,10 +1058,6 @@ static initializer_t *parse_sub_initializer(type_t *type,
        initializer_t  *result = NULL;
        initializer_t **elems;
        if(is_type_array(type)) {
-               array_type_t *array_type   = &type->array;
-               type_t       *element_type = array_type->element_type;
-               element_type               = skip_typeref(element_type);
-
                if(token.type == '.') {
                        errorf(HERE,
                               "compound designator in initializer for array type '%T'",
@@ -1143,13 +1065,14 @@ static initializer_t *parse_sub_initializer(type_t *type,
                        skip_designator();
                }
 
+               type_t *const element_type = skip_typeref(type->array.element_type);
+
                initializer_t *sub;
                had_initializer_brace_warning = false;
                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 */
@@ -1179,8 +1102,7 @@ static initializer_t *parse_sub_initializer(type_t *type,
                }
        } else {
                assert(is_type_compound(type));
-               compound_type_t *compound_type = &type->compound;
-               context_t       *context       = &compound_type->declaration->context;
+               context_t *const context = &type->compound.declaration->context;
 
                if(token.type == '[') {
                        errorf(HERE,
@@ -1200,7 +1122,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 */
@@ -1267,10 +1189,6 @@ static initializer_t *parse_initializer(type_t *const orig_type)
 
        if(token.type != '{') {
                expression_t  *expression  = parse_assignment_expression();
-               if (expression->base.datatype == NULL) {
-                       /* something bad happens, don't produce further errors */
-                       return NULL;
-               }
                initializer_t *initializer = initializer_from_expression(type, expression);
                if(initializer == NULL) {
                        errorf(HERE,
@@ -1293,7 +1211,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;
@@ -1823,7 +1741,9 @@ finish_specifiers:
                        /* invalid specifier combination, give an error message */
                        if(type_specifiers == 0) {
                                if (! strict_mode) {
-                                       warningf(HERE, "no type specifiers in declaration, using int");
+                                       if (warning.implicit_int) {
+                                               warningf(HERE, "no type specifiers in declaration, using 'int'");
+                                       }
                                        atomic_type = ATOMIC_TYPE_INT;
                                        break;
                                } else {
@@ -1912,16 +1832,13 @@ static void semantic_parameter(declaration_t *declaration)
                errorf(HERE, "parameter may only have none or register storage class");
        }
 
-       type_t *orig_type = declaration->type;
-       if(orig_type == NULL)
-               return;
-       type_t *type = skip_typeref(orig_type);
+       type_t *const orig_type = declaration->type;
+       type_t *      type      = skip_typeref(orig_type);
 
        /* Array as last part of a parameter type is just syntactic sugar.  Turn it
         * into a pointer. § 6.7.5.3 (7) */
        if (is_type_array(type)) {
-               const array_type_t *arr_type     = &type->array;
-               type_t             *element_type = arr_type->element_type;
+               type_t *const element_type = type->array.element_type;
 
                type = make_pointer_type(element_type, type->base.qualifiers);
 
@@ -2231,7 +2148,16 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
 
                        function_type->function.return_type = type;
 
-                       type = function_type;
+                       type_t *skipped_return_type = skip_typeref(type);
+                       if (is_type_function(skipped_return_type)) {
+                               errorf(HERE, "function returning function is not allowed");
+                               type = type_error_type;
+                       } else if (is_type_array(skipped_return_type)) {
+                               errorf(HERE, "function returning array is not allowed");
+                               type = type_error_type;
+                       } else {
+                               type = function_type;
+                       }
                        break;
                }
 
@@ -2255,7 +2181,13 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                        array_type->array.is_variable  = parsed_array->is_variable;
                        array_type->array.size         = parsed_array->size;
 
-                       type = array_type;
+                       type_t *skipped_type = skip_typeref(type);
+                       if (is_type_atomic(skipped_type, ATOMIC_TYPE_VOID)) {
+                               errorf(HERE, "array of void is not allowed");
+                               type = type_error_type;
+                       } else {
+                               type = array_type;
+                       }
                        break;
                }
                }
@@ -2317,6 +2249,11 @@ static declaration_t *append_declaration(declaration_t* const declaration)
        return declaration;
 }
 
+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)
@@ -2325,7 +2262,9 @@ static declaration_t *internal_record_declaration(
        const namespace_t     namespc = (namespace_t)declaration->namespc;
 
        const type_t *const type = skip_typeref(declaration->type);
-       if (is_type_function(type) && type->function.unspecified_parameters) {
+       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);
@@ -2333,68 +2272,84 @@ static declaration_t *internal_record_declaration(
 
        declaration_t *const previous_declaration = get_declaration(symbol, namespc);
        assert(declaration != previous_declaration);
-       if (previous_declaration != NULL
-                       && previous_declaration->parent_context == context) {
-               /* can happen for K&R style declarations */
-               if(previous_declaration->type == NULL) {
-                       previous_declaration->type = declaration->type;
-               }
-
-               const type_t *const prev_type = skip_typeref(previous_declaration->type);
-               if (!types_compatible(type, prev_type)) {
-                       errorf(declaration->source_position,
-                               "declaration '%#T' is incompatible with previous declaration '%#T'",
-                               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;
-                       unsigned new_storage_class = declaration->storage_class;
-
-                       /* pretend no storage class means extern for function declarations
-                        * (except if the previous declaration is neither none nor extern) */
-                       if (is_type_function(type)) {
-                               switch (old_storage_class) {
-                                       case STORAGE_CLASS_NONE:
-                                               old_storage_class = STORAGE_CLASS_EXTERN;
-
-                                       case STORAGE_CLASS_EXTERN:
-                                               if (new_storage_class == STORAGE_CLASS_NONE && !is_function_definition) {
-                                                       new_storage_class = STORAGE_CLASS_EXTERN;
-                                               }
-                                               break;
+       if (previous_declaration != NULL) {
+               if (previous_declaration->parent_context == context) {
+                       /* can happen for K&R style declarations */
+                       if(previous_declaration->type == NULL) {
+                               previous_declaration->type = declaration->type;
+                       }
 
-                                       default: break;
+                       const type_t *const prev_type = skip_typeref(previous_declaration->type);
+                       if (!types_compatible(type, prev_type)) {
+                               errorf(declaration->source_position,
+                                       "declaration '%#T' is incompatible with previous declaration '%#T'",
+                                       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;
+                               unsigned new_storage_class = declaration->storage_class;
+
+                               /* pretend no storage class means extern for function declarations
+                                * (except if the previous declaration is neither none nor extern) */
+                               if (is_type_function(type)) {
+                                       switch (old_storage_class) {
+                                               case STORAGE_CLASS_NONE:
+                                                       old_storage_class = STORAGE_CLASS_EXTERN;
+
+                                               case STORAGE_CLASS_EXTERN:
+                                                       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'", type, symbol);
+                                                               }
+                                                       } else if (new_storage_class == STORAGE_CLASS_NONE) {
+                                                               new_storage_class = STORAGE_CLASS_EXTERN;
+                                                       }
+                                                       break;
+
+                                               default: break;
+                                       }
                                }
-                       }
 
-                       if (old_storage_class == STORAGE_CLASS_EXTERN &&
-                           new_storage_class == STORAGE_CLASS_EXTERN) {
+                               if (old_storage_class == STORAGE_CLASS_EXTERN &&
+                                               new_storage_class == STORAGE_CLASS_EXTERN) {
 warn_redundant_declaration:
-                                       warningf(declaration->source_position, "redundant declaration for '%Y'", symbol);
-                                       warningf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
-                       } else if (current_function == NULL) {
-                               if (old_storage_class != STORAGE_CLASS_STATIC &&
-                                   new_storage_class == STORAGE_CLASS_STATIC) {
-                                       errorf(declaration->source_position, "static declaration of '%Y' follows non-static declaration", symbol);
-                                       errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
-                               } else {
-                                       if (old_storage_class != STORAGE_CLASS_EXTERN && !is_function_definition) {
-                                               goto 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);
                                        }
-                                       if (new_storage_class == STORAGE_CLASS_NONE) {
-                                               previous_declaration->storage_class = STORAGE_CLASS_NONE;
+                               } else if (current_function == NULL) {
+                                       if (old_storage_class != STORAGE_CLASS_STATIC &&
+                                                       new_storage_class == STORAGE_CLASS_STATIC) {
+                                               errorf(declaration->source_position, "static declaration of '%Y' follows non-static declaration", symbol);
+                                               errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
+                                       } else {
+                                               if (old_storage_class != STORAGE_CLASS_EXTERN && !is_function_definition) {
+                                                       goto warn_redundant_declaration;
+                                               }
+                                               if (new_storage_class == STORAGE_CLASS_NONE) {
+                                                       previous_declaration->storage_class = STORAGE_CLASS_NONE;
+                                               }
                                        }
-                               }
-                       } else {
-                               if (old_storage_class == new_storage_class) {
-                                       errorf(declaration->source_position, "redeclaration of '%Y'", symbol);
                                } else {
-                                       errorf(declaration->source_position, "redeclaration of '%Y' with different linkage", symbol);
+                                       if (old_storage_class == new_storage_class) {
+                                               errorf(declaration->source_position, "redeclaration of '%Y'", symbol);
+                                       } else {
+                                               errorf(declaration->source_position, "redeclaration of '%Y' with different linkage", symbol);
+                                       }
+                                       errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
                                }
-                               errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
                        }
+                       return previous_declaration;
+               }
+       } else if (is_function_definition &&
+                       declaration->storage_class != STORAGE_CLASS_STATIC) {
+               if (warning.missing_prototypes && !is_sym_main(symbol)) {
+                       warningf(declaration->source_position, "no previous prototype for '%#T'", type, symbol);
+               } else if (warning.missing_declarations && !is_sym_main(symbol)) {
+                       warningf(declaration->source_position, "no previous declaration for '%#T'", type, symbol);
                }
-               return previous_declaration;
        }
 
        assert(declaration->parent_context == NULL);
@@ -2407,57 +2362,12 @@ warn_redundant_declaration:
        return append_declaration(declaration);
 }
 
-/**
- * Check if a given type is a vilid array type.
- */
-static bool is_valid_array_type(const type_t *type) {
-       if (type->kind == TYPE_ARRAY) {
-               const array_type_t *array = &type->array;
-               const type_t       *etype = skip_typeref(array->element_type);
-
-               if (! is_valid_array_type(etype))
-                       return false;
-
-               if (etype->kind == TYPE_ATOMIC) {
-                       const atomic_type_t *atype = &etype->atomic;
-
-                       if (atype->akind == ATOMIC_TYPE_VOID) {
-                               return false;
-                       }
-               }
-       }
-       return true;
-}
-
 static declaration_t *record_declaration(declaration_t *declaration)
 {
-       declaration = internal_record_declaration(declaration, false);
-       const type_t *type = skip_typeref(declaration->type);
-
-       /* check the type here for several not allowed combinations */
-       if (type->kind == TYPE_FUNCTION) {
-               const function_type_t* function_type = &type->function;
-               const type_t*          ret_type      = skip_typeref(function_type->return_type);
-
-               if (ret_type->kind == TYPE_FUNCTION) {
-                       errorf(declaration->source_position, "'%Y' declared as function returning a function",
-                               declaration->symbol);
-                       declaration->type = type_error_type;
-               } else if (ret_type->kind == TYPE_ARRAY) {
-                       errorf(declaration->source_position, "'%Y' declared as function returning an array",
-                               declaration->symbol);
-                       declaration->type = type_error_type;
-               }
-       }
-       if (! is_valid_array_type(type)) {
-               errorf(declaration->source_position, "declaration of '%Y' as array of voids",
-                               declaration->symbol);
-               declaration->type = type_error_type;
-       }
-       return declaration;
+       return internal_record_declaration(declaration, false);
 }
 
-static declaration_t *record_function_definition(declaration_t *const declaration)
+static declaration_t *record_function_definition(declaration_t *declaration)
 {
        return internal_record_declaration(declaration, true);
 }
@@ -2515,20 +2425,17 @@ static void parse_init_declarator_rest(declaration_t *declaration)
 
                        switch (initializer->kind) {
                                case INITIALIZER_LIST: {
-                                       initializer_list_t *const list = &initializer->list;
-                                       cnst->conste.v.int_value = list->len;
+                                       cnst->conste.v.int_value = initializer->list.len;
                                        break;
                                }
 
                                case INITIALIZER_STRING: {
-                                       initializer_string_t *const string = &initializer->string;
-                                       cnst->conste.v.int_value = string->string.size;
+                                       cnst->conste.v.int_value = initializer->string.string.size;
                                        break;
                                }
 
                                case INITIALIZER_WIDE_STRING: {
-                                       initializer_wide_string_t *const string = &initializer->wide_string;
-                                       cnst->conste.v.int_value = string->string.size;
+                                       cnst->conste.v.int_value = initializer->wide_string.string.size;
                                        break;
                                }
 
@@ -2569,8 +2476,7 @@ static void parse_anonymous_declaration_rest(
        switch (type->kind) {
                case TYPE_COMPOUND_STRUCT:
                case TYPE_COMPOUND_UNION: {
-                       const compound_type_t *compound_type = &type->compound;
-                       if (compound_type->declaration->symbol == NULL) {
+                       if (type->compound.declaration->symbol == NULL) {
                                warningf(declaration->source_position, "unnamed struct/union that defines no instances");
                        }
                        break;
@@ -2597,8 +2503,9 @@ static void parse_declaration_rest(declaration_t *ndeclaration,
                type_t *orig_type = declaration->type;
                type_t *type      = skip_typeref(orig_type);
 
-               if(is_type_valid(type) &&
-                  type->kind != TYPE_FUNCTION && declaration->is_inline) {
+               if (type->kind != TYPE_FUNCTION &&
+                   declaration->is_inline &&
+                   is_type_valid(type)) {
                        warningf(declaration->source_position,
                                 "variable '%Y' declared 'inline'\n", declaration->symbol);
                }
@@ -2707,8 +2614,10 @@ static void parse_kr_declaration_list(declaration_t *declaration)
                                errorf(HERE, "no type specified for function parameter '%Y'",
                                       parameter_declaration->symbol);
                        } else {
-                               warningf(HERE, "no type specified for function parameter '%Y', using int",
-                                        parameter_declaration->symbol);
+                               if (warning.implicit_int) {
+                                       warningf(HERE, "no type specified for function parameter '%Y', using 'int'",
+                                               parameter_declaration->symbol);
+                               }
                                parameter_type              = type_int;
                                parameter_declaration->type = parameter_type;
                        }
@@ -2797,16 +2706,14 @@ static void parse_external_declaration(void)
        }
 
        type_t *type = ndeclaration->type;
-       if(type == NULL) {
-               eat_block();
-               return;
-       }
 
        /* note that we don't skip typerefs: the standard doesn't allow them here
         * (so we can't use is_type_function here) */
        if(type->kind != TYPE_FUNCTION) {
-               errorf(HERE, "declarator '%#T' has a body but is not a function type",
-                      type, ndeclaration->symbol);
+               if (is_type_valid(type)) {
+                       errorf(HERE, "declarator '%#T' has a body but is not a function type",
+                              type, ndeclaration->symbol);
+               }
                eat_block();
                return;
        }
@@ -3135,9 +3042,6 @@ static type_t *get_builtin_symbol_type(symbol_t *symbol)
  */
 static type_t *automatic_type_conversion(type_t *orig_type)
 {
-       if(orig_type == NULL)
-               return NULL;
-
        type_t *type = skip_typeref(orig_type);
        if(is_type_array(type)) {
                array_type_t *array_type   = &type->array;
@@ -3160,42 +3064,30 @@ static type_t *automatic_type_conversion(type_t *orig_type)
  */
 type_t *revert_automatic_type_conversion(const expression_t *expression)
 {
-       if(expression->base.datatype == NULL)
-               return NULL;
+       switch (expression->kind) {
+               case EXPR_REFERENCE: return expression->reference.declaration->type;
+               case EXPR_SELECT:    return expression->select.compound_entry->type;
 
-       switch(expression->kind) {
-       case EXPR_REFERENCE: {
-               const reference_expression_t *ref = &expression->reference;
-               return ref->declaration->type;
-       }
-       case EXPR_SELECT: {
-               const select_expression_t *select = &expression->select;
-               return select->compound_entry->type;
-       }
-       case EXPR_UNARY_DEREFERENCE: {
-               expression_t   *value        = expression->unary.value;
-               type_t         *type         = skip_typeref(value->base.datatype);
-               pointer_type_t *pointer_type = &type->pointer;
+               case EXPR_UNARY_DEREFERENCE: {
+                       const expression_t *const value = expression->unary.value;
+                       type_t             *const type  = skip_typeref(value->base.datatype);
+                       assert(is_type_pointer(type));
+                       return type->pointer.points_to;
+               }
 
-               return pointer_type->points_to;
-       }
-       case EXPR_BUILTIN_SYMBOL: {
-               const builtin_symbol_expression_t *builtin
-                       = &expression->builtin_symbol;
-               return get_builtin_symbol_type(builtin->symbol);
-       }
-       case EXPR_ARRAY_ACCESS: {
-               const array_access_expression_t *array_access
-                       = &expression->array_access;
-               const expression_t *array_ref = array_access->array_ref;
-               type_t *type_left  = skip_typeref(array_ref->base.datatype);
-               assert(is_type_pointer(type_left));
-               pointer_type_t *pointer_type = &type_left->pointer;
-               return pointer_type->points_to;
-       }
+               case EXPR_BUILTIN_SYMBOL:
+                       return get_builtin_symbol_type(expression->builtin_symbol.symbol);
 
-       default:
-               break;
+               case EXPR_ARRAY_ACCESS: {
+                       const expression_t *const array_ref = expression->array_access.array_ref;
+                       type_t             *const type_left = skip_typeref(array_ref->base.datatype);
+                       if (!is_type_valid(type_left))
+                               return type_left;
+                       assert(is_type_pointer(type_left));
+                       return type_left->pointer.points_to;
+               }
+
+               default: break;
        }
 
        return expression->base.datatype;
@@ -3216,8 +3108,10 @@ static expression_t *parse_reference(void)
        if(declaration == NULL) {
                if (! strict_mode && token.type == '(') {
                        /* an implicitly defined function */
-                       warningf(HERE, "implicit declaration of function '%Y'",
-                                ref->symbol);
+                       if (warning.implicit_function_declaration) {
+                               warningf(HERE, "implicit declaration of function '%Y'",
+                                       ref->symbol);
+                       }
 
                        declaration = create_implicit_function(ref->symbol,
                                                               source_position);
@@ -3269,31 +3163,24 @@ static expression_t *parse_statement_expression(void)
 {
        expression_t *expression = allocate_expression_zero(EXPR_STATEMENT);
 
-       statement_t *statement          = parse_compound_statement();
-       expression->statement.statement = statement;
-       if(statement == NULL) {
-               expect(')');
-               return NULL;
-       }
-
-       assert(statement->kind == STATEMENT_COMPOUND);
-       compound_statement_t *compound_statement = &statement->compound;
+       statement_t *statement           = parse_compound_statement();
+       expression->statement.statement  = statement;
+       expression->base.source_position = statement->base.source_position;
 
-       /* find last statement and use it's type */
-       const statement_t *last_statement = NULL;
-       const statement_t *iter           = compound_statement->statements;
-       for( ; iter != NULL; iter = iter->base.next) {
-               last_statement = iter;
-       }
+       /* find last statement and use its type */
+       type_t *type = type_void;
+       const statement_t *stmt = statement->compound.statements;
+       if (stmt != NULL) {
+               while (stmt->base.next != NULL)
+                       stmt = stmt->base.next;
 
-       if(last_statement->kind == STATEMENT_EXPRESSION) {
-               const expression_statement_t *expression_statement
-                       = &last_statement->expression;
-               expression->base.datatype
-                       = expression_statement->expression->base.datatype;
+               if (stmt->kind == STATEMENT_EXPRESSION) {
+                       type = stmt->expression.expression->base.datatype;
+               }
        } else {
-               expression->base.datatype = type_void;
+               warningf(expression->base.source_position, "empty statement expression ({})");
        }
+       expression->base.datatype = type;
 
        expect(')');
 
@@ -3553,16 +3440,16 @@ static expression_t *parse_compare_builtin(void)
        expression->binary.right = parse_assignment_expression();
        expect(')');
 
-       type_t *orig_type_left  = expression->binary.left->base.datatype;
-       type_t *orig_type_right = expression->binary.right->base.datatype;
-       if(orig_type_left == NULL || orig_type_right == NULL)
-               return expression;
+       type_t *const orig_type_left  = expression->binary.left->base.datatype;
+       type_t *const orig_type_right = expression->binary.right->base.datatype;
 
-       type_t *type_left  = skip_typeref(orig_type_left);
-       type_t *type_right = skip_typeref(orig_type_right);
+       type_t *const type_left  = skip_typeref(orig_type_left);
+       type_t *const type_right = skip_typeref(orig_type_right);
        if(!is_type_floating(type_left) && !is_type_floating(type_right)) {
-               type_error_incompatible("invalid operands in comparison",
-                                       token.source_position, type_left, type_right);
+               if (is_type_valid(type_left) && is_type_valid(type_right)) {
+                       type_error_incompatible("invalid operands in comparison",
+                               token.source_position, orig_type_left, orig_type_right);
+               }
        } else {
                semantic_comparison(&expression->binary);
        }
@@ -3676,14 +3563,13 @@ static expression_t *parse_primary_expression(void)
  * Check if the expression has the character type and issue a warning then.
  */
 static void check_for_char_index_type(const expression_t *expression) {
-       type_t *type      = expression->base.datatype;
-       type_t *base_type = skip_typeref(type);
+       type_t       *const type      = expression->base.datatype;
+       const type_t *const base_type = skip_typeref(type);
 
-       if (base_type->base.kind == TYPE_ATOMIC) {
-               switch (base_type->atomic.akind == ATOMIC_TYPE_CHAR) {
-                       warningf(expression->base.source_position,
-                               "array subscript has type '%T'", type);
-               }
+       if (is_type_atomic(base_type, ATOMIC_TYPE_CHAR) &&
+                       warning.char_subscripts) {
+               warningf(expression->base.source_position,
+                       "array subscript has type '%T'", type);
        }
 }
 
@@ -3701,33 +3587,32 @@ static expression_t *parse_array_expression(unsigned precedence,
 
        array_access->expression.kind = EXPR_ARRAY_ACCESS;
 
-       type_t *type_left   = left->base.datatype;
-       type_t *type_inside = inside->base.datatype;
-       type_t *return_type = NULL;
-
-       if(type_left != NULL && type_inside != NULL) {
-               type_left   = skip_typeref(type_left);
-               type_inside = skip_typeref(type_inside);
-
-               if(is_type_pointer(type_left)) {
-                       pointer_type_t *pointer = &type_left->pointer;
-                       return_type             = pointer->points_to;
-                       array_access->array_ref = left;
-                       array_access->index     = inside;
-                       check_for_char_index_type(inside);
-               } else if(is_type_pointer(type_inside)) {
-                       pointer_type_t *pointer = &type_inside->pointer;
-                       return_type             = pointer->points_to;
-                       array_access->array_ref = inside;
-                       array_access->index     = left;
-                       array_access->flipped   = true;
-                       check_for_char_index_type(left);
-               } else {
-                       errorf(HERE, "array access on object with non-pointer types '%T', '%T'", type_left, type_inside);
-               }
-       } else {
+       type_t *const orig_type_left   = left->base.datatype;
+       type_t *const orig_type_inside = inside->base.datatype;
+
+       type_t *const type_left   = skip_typeref(orig_type_left);
+       type_t *const type_inside = skip_typeref(orig_type_inside);
+
+       type_t *return_type;
+       if (is_type_pointer(type_left)) {
+               return_type             = type_left->pointer.points_to;
                array_access->array_ref = left;
                array_access->index     = inside;
+               check_for_char_index_type(inside);
+       } else if (is_type_pointer(type_inside)) {
+               return_type             = type_inside->pointer.points_to;
+               array_access->array_ref = inside;
+               array_access->index     = left;
+               array_access->flipped   = true;
+               check_for_char_index_type(left);
+       } else {
+               if (is_type_valid(type_left) && is_type_valid(type_inside)) {
+                       errorf(HERE,
+                               "array access on object with non-pointer types '%T', '%T'",
+                               orig_type_left, orig_type_inside);
+               }
+               return_type             = type_error_type;
+               array_access->array_ref = create_invalid_expression();
        }
 
        if(token.type != ']') {
@@ -3786,32 +3671,31 @@ static expression_t *parse_select_expression(unsigned precedence,
        select->select.symbol = symbol;
        next_token();
 
-       type_t *orig_type = compound->base.datatype;
-       if(orig_type == NULL)
-               return create_invalid_expression();
-
-       type_t *type = skip_typeref(orig_type);
+       type_t *const orig_type = compound->base.datatype;
+       type_t *const type      = skip_typeref(orig_type);
 
        type_t *type_left = type;
        if(is_pointer) {
-               if(type->kind != TYPE_POINTER) {
-                       errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type);
+               if (!is_type_pointer(type)) {
+                       if (is_type_valid(type)) {
+                               errorf(HERE, "left hand side of '->' is not a pointer, but '%T'", orig_type);
+                       }
                        return create_invalid_expression();
                }
-               pointer_type_t *pointer_type = &type->pointer;
-               type_left                    = pointer_type->points_to;
+               type_left = type->pointer.points_to;
        }
        type_left = skip_typeref(type_left);
 
-       if(type_left->kind != TYPE_COMPOUND_STRUCT
-                       && type_left->kind != TYPE_COMPOUND_UNION) {
-               errorf(HERE, "request for member '%Y' in something not a struct or "
-                      "union, but '%T'", symbol, type_left);
+       if (type_left->kind != TYPE_COMPOUND_STRUCT &&
+           type_left->kind != TYPE_COMPOUND_UNION) {
+               if (is_type_valid(type_left)) {
+                       errorf(HERE, "request for member '%Y' in something not a struct or "
+                              "union, but '%T'", symbol, type_left);
+               }
                return create_invalid_expression();
        }
 
-       compound_type_t *compound_type = &type_left->compound;
-       declaration_t   *declaration   = compound_type->declaration;
+       declaration_t *const declaration = type_left->compound.declaration;
 
        if(!declaration->init.is_defined) {
                errorf(HERE, "request for member '%Y' of incomplete type '%T'",
@@ -3863,27 +3747,21 @@ static expression_t *parse_call_expression(unsigned precedence,
        call_expression_t *call = &result->call;
        call->function          = expression;
 
-       function_type_t *function_type = NULL;
-       type_t          *orig_type     = expression->base.datatype;
-       if(is_type_valid(orig_type)) {
-               type_t *type  = skip_typeref(orig_type);
-
-               if(is_type_pointer(type)) {
-                       pointer_type_t *pointer_type = &type->pointer;
+       type_t *const orig_type = expression->base.datatype;
+       type_t *const type      = skip_typeref(orig_type);
 
-                       type = skip_typeref(pointer_type->points_to);
+       function_type_t *function_type = NULL;
+       if (is_type_pointer(type)) {
+               type_t *const to_type = skip_typeref(type->pointer.points_to);
 
-                       if (is_type_function(type)) {
-                               function_type             = &type->function;
-                               call->expression.datatype = function_type->return_type;
-                       }
+               if (is_type_function(to_type)) {
+                       function_type             = &to_type->function;
+                       call->expression.datatype = function_type->return_type;
                }
-               if(function_type == NULL) {
-                       errorf(HERE, "called object '%E' (type '%T') is not a pointer to a function", expression, orig_type);
+       }
 
-                       function_type             = NULL;
-                       call->expression.datatype = NULL;
-               }
+       if (function_type == NULL && is_type_valid(type)) {
+               errorf(HERE, "called object '%E' (type '%T') is not a pointer to a function", expression, orig_type);
        }
 
        /* parse arguments */
@@ -3917,8 +3795,16 @@ static expression_t *parse_call_expression(unsigned precedence,
                                parameter = parameter->next, argument = argument->next) {
                        type_t *expected_type = parameter->type;
                        /* TODO report context in error messages */
-                       argument->expression = create_implicit_cast(argument->expression,
-                                                                   expected_type);
+                       expression_t *const arg_expr = argument->expression;
+                       type_t       *const res_type = semantic_assign(expected_type, arg_expr, "function call");
+                       if (res_type == NULL) {
+                               /* TODO improve error message */
+                               errorf(arg_expr->base.source_position,
+                                       "Cannot call function with argument '%E' of type '%T' where type '%T' is expected",
+                                       arg_expr, arg_expr->base.datatype, expected_type);
+                       } else {
+                               argument->expression = create_implicit_cast(argument->expression, expected_type);
+                       }
                }
                /* too few parameters */
                if(parameter != NULL) {
@@ -3933,9 +3819,6 @@ static expression_t *parse_call_expression(unsigned precedence,
                                for( ; argument != NULL; argument = argument->next) {
                                        type_t *type = argument->expression->base.datatype;
 
-                                       if(type == NULL)
-                                               continue;
-
                                        type = skip_typeref(type);
                                        if(is_type_integer(type)) {
                                                type = promote_integer(type);
@@ -3961,15 +3844,10 @@ static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right);
 
 static bool same_compound_type(const type_t *type1, const type_t *type2)
 {
-       if(!is_type_compound(type1))
-               return false;
-       if(type1->kind != type2->kind)
-               return false;
-
-       const compound_type_t *compound1 = &type1->compound;
-       const compound_type_t *compound2 = &type2->compound;
-
-       return compound1->declaration == compound2->declaration;
+       return
+               is_type_compound(type1) &&
+               type1->kind == type2->kind &&
+               type1->compound.declaration == type2->compound.declaration;
 }
 
 /**
@@ -3988,13 +3866,11 @@ static expression_t *parse_conditional_expression(unsigned precedence,
        conditional->condition = expression;
 
        /* 6.5.15.2 */
-       type_t *condition_type_orig = expression->base.datatype;
-       if(is_type_valid(condition_type_orig)) {
-               type_t *condition_type = skip_typeref(condition_type_orig);
-               if(condition_type->kind != TYPE_ERROR && !is_type_scalar(condition_type)) {
-                       type_error("expected a scalar type in conditional condition",
-                                  expression->base.source_position, condition_type_orig);
-               }
+       type_t *const condition_type_orig = expression->base.datatype;
+       type_t *const condition_type      = skip_typeref(condition_type_orig);
+       if (!is_type_scalar(condition_type) && is_type_valid(condition_type)) {
+               type_error("expected a scalar type in conditional condition",
+                          expression->base.source_position, condition_type_orig);
        }
 
        expression_t *true_expression = parse_expression();
@@ -4004,16 +3880,13 @@ static expression_t *parse_conditional_expression(unsigned precedence,
        conditional->true_expression  = true_expression;
        conditional->false_expression = false_expression;
 
-       type_t *orig_true_type  = true_expression->base.datatype;
-       type_t *orig_false_type = false_expression->base.datatype;
-       if(!is_type_valid(orig_true_type) || !is_type_valid(orig_false_type))
-               return result;
-
-       type_t *true_type  = skip_typeref(orig_true_type);
-       type_t *false_type = skip_typeref(orig_false_type);
+       type_t *const orig_true_type  = true_expression->base.datatype;
+       type_t *const orig_false_type = false_expression->base.datatype;
+       type_t *const true_type       = skip_typeref(orig_true_type);
+       type_t *const false_type      = skip_typeref(orig_false_type);
 
        /* 6.5.15.3 */
-       type_t *result_type = NULL;
+       type_t *result_type;
        if (is_type_arithmetic(true_type) && is_type_arithmetic(false_type)) {
                result_type = semantic_arithmetic(true_type, false_type);
 
@@ -4023,9 +3896,10 @@ static expression_t *parse_conditional_expression(unsigned precedence,
                conditional->true_expression     = true_expression;
                conditional->false_expression    = false_expression;
                conditional->expression.datatype = result_type;
-       } else if (same_compound_type(true_type, false_type)
-                       || (is_type_atomic(true_type, ATOMIC_TYPE_VOID) &&
-                               is_type_atomic(false_type, ATOMIC_TYPE_VOID))) {
+       } else if (same_compound_type(true_type, false_type) || (
+           is_type_atomic(true_type, ATOMIC_TYPE_VOID) &&
+           is_type_atomic(false_type, ATOMIC_TYPE_VOID)
+               )) {
                /* just take 1 of the 2 types */
                result_type = true_type;
        } else if (is_type_pointer(true_type) && is_type_pointer(false_type)
@@ -4034,9 +3908,12 @@ static expression_t *parse_conditional_expression(unsigned precedence,
                result_type = true_type;
        } else {
                /* TODO */
-               type_error_incompatible("while parsing conditional",
-                                       expression->base.source_position, true_type,
-                                       false_type);
+               if (is_type_valid(true_type) && is_type_valid(false_type)) {
+                       type_error_incompatible("while parsing conditional",
+                                               expression->base.source_position, true_type,
+                                               false_type);
+               }
+               result_type = type_error_type;
        }
 
        conditional->expression.datatype = result_type;
@@ -4073,14 +3950,14 @@ static expression_t *parse_builtin_classify_type(const unsigned precedence)
 
 static void semantic_incdec(unary_expression_t *expression)
 {
-       type_t *orig_type = expression->value->base.datatype;
-       if(!is_type_valid(orig_type))
-               return;
-
-       type_t *type = skip_typeref(orig_type);
+       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) {
-               /* TODO: improve error message */
-               errorf(HERE, "operation needs an arithmetic or pointer type");
+               if (is_type_valid(type)) {
+                       /* TODO: improve error message */
+                       errorf(HERE, "operation needs an arithmetic or pointer type");
+               }
                return;
        }
 
@@ -4089,14 +3966,13 @@ static void semantic_incdec(unary_expression_t *expression)
 
 static void semantic_unexpr_arithmetic(unary_expression_t *expression)
 {
-       type_t *orig_type = expression->value->base.datatype;
-       if(!is_type_valid(orig_type))
-               return;
-
-       type_t *type = skip_typeref(orig_type);
+       type_t *const orig_type = expression->value->base.datatype;
+       type_t *const type      = skip_typeref(orig_type);
        if(!is_type_arithmetic(type)) {
-               /* TODO: improve error message */
-               errorf(HERE, "operation needs an arithmetic type");
+               if (is_type_valid(type)) {
+                       /* TODO: improve error message */
+                       errorf(HERE, "operation needs an arithmetic type");
+               }
                return;
        }
 
@@ -4105,13 +3981,12 @@ static void semantic_unexpr_arithmetic(unary_expression_t *expression)
 
 static void semantic_unexpr_scalar(unary_expression_t *expression)
 {
-       type_t *orig_type = expression->value->base.datatype;
-       if(!is_type_valid(orig_type))
-               return;
-
-       type_t *type = skip_typeref(orig_type);
+       type_t *const orig_type = expression->value->base.datatype;
+       type_t *const type      = skip_typeref(orig_type);
        if (!is_type_scalar(type)) {
-               errorf(HERE, "operand of ! must be of scalar type");
+               if (is_type_valid(type)) {
+                       errorf(HERE, "operand of ! must be of scalar type");
+               }
                return;
        }
 
@@ -4120,13 +3995,12 @@ static void semantic_unexpr_scalar(unary_expression_t *expression)
 
 static void semantic_unexpr_integer(unary_expression_t *expression)
 {
-       type_t *orig_type = expression->value->base.datatype;
-       if(!is_type_valid(orig_type))
-               return;
-
-       type_t *type = skip_typeref(orig_type);
+       type_t *const orig_type = expression->value->base.datatype;
+       type_t *const type      = skip_typeref(orig_type);
        if (!is_type_integer(type)) {
-               errorf(HERE, "operand of ~ must be of integer type");
+               if (is_type_valid(type)) {
+                       errorf(HERE, "operand of ~ must be of integer type");
+               }
                return;
        }
 
@@ -4135,19 +4009,16 @@ static void semantic_unexpr_integer(unary_expression_t *expression)
 
 static void semantic_dereference(unary_expression_t *expression)
 {
-       type_t *orig_type = expression->value->base.datatype;
-       if(!is_type_valid(orig_type))
-               return;
-
-       type_t *type = skip_typeref(orig_type);
+       type_t *const orig_type = expression->value->base.datatype;
+       type_t *const type      = skip_typeref(orig_type);
        if(!is_type_pointer(type)) {
-               errorf(HERE, "Unary '*' needs pointer or arrray type, but type '%T' given", orig_type);
+               if (is_type_valid(type)) {
+                       errorf(HERE, "Unary '*' needs pointer or arrray type, but type '%T' given", orig_type);
+               }
                return;
        }
 
-       pointer_type_t *pointer_type = &type->pointer;
-       type_t         *result_type  = pointer_type->points_to;
-
+       type_t *result_type = type->pointer.points_to;
        result_type = automatic_type_conversion(result_type);
        expression->expression.datatype = result_type;
 }
@@ -4165,8 +4036,7 @@ static void semantic_take_addr(unary_expression_t *expression)
                return;
 
        if(value->kind == EXPR_REFERENCE) {
-               reference_expression_t *reference   = (reference_expression_t*) value;
-               declaration_t          *declaration = reference->declaration;
+               declaration_t *const declaration = value->reference.declaration;
                if(declaration != NULL) {
                        if (declaration->storage_class == STORAGE_CLASS_REGISTER) {
                                errorf(expression->expression.source_position,
@@ -4279,20 +4149,18 @@ static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right)
  */
 static void semantic_binexpr_arithmetic(binary_expression_t *expression)
 {
-       expression_t *left       = expression->left;
-       expression_t *right      = expression->right;
-       type_t       *orig_type_left  = left->base.datatype;
-       type_t       *orig_type_right = right->base.datatype;
-
-       if(orig_type_left == NULL || orig_type_right == NULL)
-               return;
-
-       type_t *type_left  = skip_typeref(orig_type_left);
-       type_t *type_right = skip_typeref(orig_type_right);
+       expression_t *const left            = expression->left;
+       expression_t *const right           = expression->right;
+       type_t       *const orig_type_left  = left->base.datatype;
+       type_t       *const orig_type_right = right->base.datatype;
+       type_t       *const type_left       = skip_typeref(orig_type_left);
+       type_t       *const type_right      = skip_typeref(orig_type_right);
 
        if(!is_type_arithmetic(type_left) || !is_type_arithmetic(type_right)) {
                /* TODO: improve error message */
-               errorf(HERE, "operation needs arithmetic types");
+               if (is_type_valid(type_left) && is_type_valid(type_right)) {
+                       errorf(HERE, "operation needs arithmetic types");
+               }
                return;
        }
 
@@ -4304,20 +4172,18 @@ static void semantic_binexpr_arithmetic(binary_expression_t *expression)
 
 static void semantic_shift_op(binary_expression_t *expression)
 {
-       expression_t *left       = expression->left;
-       expression_t *right      = expression->right;
-       type_t       *orig_type_left  = left->base.datatype;
-       type_t       *orig_type_right = right->base.datatype;
-
-       if(orig_type_left == NULL || orig_type_right == NULL)
-               return;
-
-       type_t *type_left  = skip_typeref(orig_type_left);
-       type_t *type_right = skip_typeref(orig_type_right);
+       expression_t *const left            = expression->left;
+       expression_t *const right           = expression->right;
+       type_t       *const orig_type_left  = left->base.datatype;
+       type_t       *const orig_type_right = right->base.datatype;
+       type_t       *      type_left       = skip_typeref(orig_type_left);
+       type_t       *      type_right      = skip_typeref(orig_type_right);
 
        if(!is_type_integer(type_left) || !is_type_integer(type_right)) {
                /* TODO: improve error message */
-               errorf(HERE, "operation needs integer types");
+               if (is_type_valid(type_left) && is_type_valid(type_right)) {
+                       errorf(HERE, "operation needs integer types");
+               }
                return;
        }
 
@@ -4331,16 +4197,12 @@ static void semantic_shift_op(binary_expression_t *expression)
 
 static void semantic_add(binary_expression_t *expression)
 {
-       expression_t *left            = expression->left;
-       expression_t *right           = expression->right;
-       type_t       *orig_type_left  = left->base.datatype;
-       type_t       *orig_type_right = right->base.datatype;
-
-       if(orig_type_left == NULL || orig_type_right == NULL)
-               return;
-
-       type_t *type_left  = skip_typeref(orig_type_left);
-       type_t *type_right = skip_typeref(orig_type_right);
+       expression_t *const left            = expression->left;
+       expression_t *const right           = expression->right;
+       type_t       *const orig_type_left  = left->base.datatype;
+       type_t       *const orig_type_right = right->base.datatype;
+       type_t       *const type_left       = skip_typeref(orig_type_left);
+       type_t       *const type_right      = skip_typeref(orig_type_right);
 
        /* § 5.6.5 */
        if(is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
@@ -4353,23 +4215,19 @@ static void semantic_add(binary_expression_t *expression)
                expression->expression.datatype = type_left;
        } else if(is_type_pointer(type_right) && is_type_integer(type_left)) {
                expression->expression.datatype = type_right;
-       } else {
+       } else if (is_type_valid(type_left) && is_type_valid(type_right)) {
                errorf(HERE, "invalid operands to binary + ('%T', '%T')", orig_type_left, orig_type_right);
        }
 }
 
 static void semantic_sub(binary_expression_t *expression)
 {
-       expression_t *left            = expression->left;
-       expression_t *right           = expression->right;
-       type_t       *orig_type_left  = left->base.datatype;
-       type_t       *orig_type_right = right->base.datatype;
-
-       if(orig_type_left == NULL || orig_type_right == NULL)
-               return;
-
-       type_t       *type_left       = skip_typeref(orig_type_left);
-       type_t       *type_right      = skip_typeref(orig_type_right);
+       expression_t *const left            = expression->left;
+       expression_t *const right           = expression->right;
+       type_t       *const orig_type_left  = left->base.datatype;
+       type_t       *const orig_type_right = right->base.datatype;
+       type_t       *const type_left       = skip_typeref(orig_type_left);
+       type_t       *const type_right      = skip_typeref(orig_type_right);
 
        /* § 5.6.5 */
        if(is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
@@ -4382,12 +4240,12 @@ static void semantic_sub(binary_expression_t *expression)
                expression->expression.datatype = type_left;
        } else if(is_type_pointer(type_left) && is_type_pointer(type_right)) {
                if(!pointers_compatible(type_left, type_right)) {
-                       errorf(HERE, "pointers to incompatible objects to binary - ('%T', '%T')", orig_type_left, orig_type_right);
+                       errorf(HERE, "pointers to incompatible objects to binary '-' ('%T', '%T')", orig_type_left, orig_type_right);
                } else {
                        expression->expression.datatype = type_ptrdiff_t;
                }
-       } else {
-               errorf(HERE, "invalid operands to binary - ('%T', '%T')", orig_type_left, orig_type_right);
+       } else if (is_type_valid(type_left) && is_type_valid(type_right)) {
+               errorf(HERE, "invalid operands to binary '-' ('%T', '%T')", orig_type_left, orig_type_right);
        }
 }
 
@@ -4398,9 +4256,6 @@ static void semantic_comparison(binary_expression_t *expression)
        type_t       *orig_type_left  = left->base.datatype;
        type_t       *orig_type_right = right->base.datatype;
 
-       if(orig_type_left == NULL || orig_type_right == NULL)
-               return;
-
        type_t *type_left  = skip_typeref(orig_type_left);
        type_t *type_right = skip_typeref(orig_type_right);
 
@@ -4416,7 +4271,7 @@ static void semantic_comparison(binary_expression_t *expression)
                expression->right = create_implicit_cast(right, type_left);
        } else if (is_type_pointer(type_right)) {
                expression->left = create_implicit_cast(left, type_right);
-       } else {
+       } 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);
        }
@@ -4430,15 +4285,14 @@ static void semantic_arithmetic_assign(binary_expression_t *expression)
        type_t       *orig_type_left  = left->base.datatype;
        type_t       *orig_type_right = right->base.datatype;
 
-       if(orig_type_left == NULL || orig_type_right == NULL)
-               return;
-
        type_t *type_left  = skip_typeref(orig_type_left);
        type_t *type_right = skip_typeref(orig_type_right);
 
        if(!is_type_arithmetic(type_left) || !is_type_arithmetic(type_right)) {
                /* TODO: improve error message */
-               errorf(HERE, "operation needs arithmetic types");
+               if (is_type_valid(type_left) && is_type_valid(type_right)) {
+                       errorf(HERE, "operation needs arithmetic types");
+               }
                return;
        }
 
@@ -4453,16 +4307,12 @@ static void semantic_arithmetic_assign(binary_expression_t *expression)
 
 static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression)
 {
-       expression_t *left            = expression->left;
-       expression_t *right           = expression->right;
-       type_t       *orig_type_left  = left->base.datatype;
-       type_t       *orig_type_right = right->base.datatype;
-
-       if(orig_type_left == NULL || orig_type_right == NULL)
-               return;
-
-       type_t *type_left  = skip_typeref(orig_type_left);
-       type_t *type_right = skip_typeref(orig_type_right);
+       expression_t *const left            = expression->left;
+       expression_t *const right           = expression->right;
+       type_t       *const orig_type_left  = left->base.datatype;
+       type_t       *const orig_type_right = right->base.datatype;
+       type_t       *const type_left       = skip_typeref(orig_type_left);
+       type_t       *const type_right      = skip_typeref(orig_type_right);
 
        if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
                /* combined instructions are tricky. We can't create an implicit cast on
@@ -4474,9 +4324,8 @@ static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression)
                expression->expression.datatype = type_left;
        } else if (is_type_pointer(type_left) && is_type_integer(type_right)) {
                expression->expression.datatype = type_left;
-       } else {
+       } else if (is_type_valid(type_left) && is_type_valid(type_right)) {
                errorf(HERE, "incompatible types '%T' and '%T' in assignment", orig_type_left, orig_type_right);
-               return;
        }
 }
 
@@ -4485,20 +4334,18 @@ static void semantic_arithmetic_addsubb_assign(binary_expression_t *expression)
  */
 static void semantic_logical_op(binary_expression_t *expression)
 {
-       expression_t *left            = expression->left;
-       expression_t *right           = expression->right;
-       type_t       *orig_type_left  = left->base.datatype;
-       type_t       *orig_type_right = right->base.datatype;
-
-       if(orig_type_left == NULL || orig_type_right == NULL)
-               return;
-
-       type_t *type_left  = skip_typeref(orig_type_left);
-       type_t *type_right = skip_typeref(orig_type_right);
+       expression_t *const left            = expression->left;
+       expression_t *const right           = expression->right;
+       type_t       *const orig_type_left  = left->base.datatype;
+       type_t       *const orig_type_right = right->base.datatype;
+       type_t       *const type_left       = skip_typeref(orig_type_left);
+       type_t       *const type_right      = skip_typeref(orig_type_right);
 
        if (!is_type_scalar(type_left) || !is_type_scalar(type_right)) {
                /* TODO: improve error message */
-               errorf(HERE, "operation needs scalar types");
+               if (is_type_valid(type_left) && is_type_valid(type_right)) {
+                       errorf(HERE, "operation needs scalar types");
+               }
                return;
        }
 
@@ -4533,9 +4380,6 @@ static void semantic_binexpr_assign(binary_expression_t *expression)
        expression_t *left           = expression->left;
        type_t       *orig_type_left = left->base.datatype;
 
-       if(orig_type_left == NULL)
-               return;
-
        type_t *type_left = revert_automatic_type_conversion(left);
        type_left         = skip_typeref(orig_type_left);
 
@@ -4574,8 +4418,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;
 }
 
@@ -5111,7 +5062,13 @@ static statement_t *parse_switch(void)
 
        expect('(');
        expression_t *const expr = parse_expression();
-       type_t       *const type = promote_integer(skip_typeref(expr->base.datatype));
+       type_t       *      type = skip_typeref(expr->base.datatype);
+       if (is_type_integer(type)) {
+               type = promote_integer(type);
+       } else if (is_type_valid(type)) {
+               errorf(expr->base.source_position, "switch quantity is not an integer, but '%T'", type);
+               type = type_error_type;
+       }
        statement->expression = create_implicit_cast(expr, type);
        expect(')');
 
@@ -5120,6 +5077,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;
 }
 
@@ -5340,22 +5301,15 @@ static statement_t *parse_return(void)
        statement->statement.kind            = STATEMENT_RETURN;
        statement->statement.source_position = token.source_position;
 
-       assert(is_type_function(current_function->type));
-       function_type_t *function_type = &current_function->type->function;
-       type_t          *return_type   = function_type->return_type;
-
        expression_t *return_value = NULL;
        if(token.type != ';') {
                return_value = parse_expression();
        }
        expect(';');
 
-       if(return_type == NULL)
-               return (statement_t*) statement;
-       if(return_value != NULL && return_value->base.datatype == NULL)
-               return (statement_t*) statement;
-
-       return_type = skip_typeref(return_type);
+       const type_t *const func_type = current_function->type;
+       assert(is_type_function(func_type));
+       type_t *const return_type = skip_typeref(func_type->function.return_type);
 
        if(return_value != NULL) {
                type_t *return_value_type = skip_typeref(return_value->base.datatype);
@@ -5366,20 +5320,14 @@ static statement_t *parse_return(void)
                                "'return' with a value, in function returning void");
                        return_value = NULL;
                } else {
-                       if(is_type_valid(return_type)) {
-                               if (return_value->base.datatype == NULL)
-                                       return (statement_t*)statement;
-
-                               type_t *const res_type = semantic_assign(return_type,
-                                       return_value, "'return'");
-                               if (res_type == NULL) {
-                                       errorf(statement->statement.source_position,
-                                               "cannot assign to '%T' from '%T'",
-                                               "cannot return something of type '%T' in function returning '%T'",
-                                               return_value->base.datatype, return_type);
-                               } else {
-                                       return_value = create_implicit_cast(return_value, res_type);
-                               }
+                       type_t *const res_type = semantic_assign(return_type,
+                               return_value, "'return'");
+                       if (res_type == NULL) {
+                               errorf(statement->statement.source_position,
+                                       "cannot return something of type '%T' in function returning '%T'",
+                                       return_value->base.datatype, return_type);
+                       } else {
+                               return_value = create_implicit_cast(return_value, res_type);
                        }
                }
                /* check for returning address of a local var */
@@ -5431,7 +5379,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(';');
 
@@ -5500,6 +5453,9 @@ static statement_t *parse_statement(void)
                break;
 
        case ';':
+               if (warning.empty_statement) {
+                       warningf(HERE, "statement is empty");
+               }
                next_token();
                statement = NULL;
                break;
@@ -5547,7 +5503,7 @@ static statement_t *parse_statement(void)
  */
 static statement_t *parse_compound_statement(void)
 {
-       compound_statement_t *compound_statement
+       compound_statement_t *const compound_statement
                = allocate_ast_zero(sizeof(compound_statement[0]));
        compound_statement->statement.kind            = STATEMENT_COMPOUND;
        compound_statement->statement.source_position = token.source_position;