build unknown if return value is missing
[cparser] / parser.c
index fa8ad94..d35396f 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -42,7 +42,7 @@ static type_t         *type_uint        = NULL;
 static type_t         *type_long_double = NULL;
 static type_t         *type_double      = NULL;
 static type_t         *type_float       = NULL;
-static type_t         *type_const_char  = NULL;
+static type_t         *type_char        = NULL;
 static type_t         *type_string      = NULL;
 static type_t         *type_void        = NULL;
 static type_t         *type_void_ptr    = NULL;
@@ -120,6 +120,26 @@ static inline void *allocate_type_zero(size_t size)
        return res;
 }
 
+static inline size_t get_initializer_size(initializer_type_t type)
+{
+       static const size_t size[] = {
+               [INITIALIZER_VALUE]  = sizeof(initializer_value_t),
+               [INITIALIZER_STRING] = sizeof(initializer_string_t),
+               [INITIALIZER_LIST]   = sizeof(initializer_list_t)
+       };
+       assert(type < INITIALIZER_COUNT);
+       assert(size[type] != 0);
+       return size[type];
+}
+
+static inline initializer_t *allocate_initializer(initializer_type_t type)
+{
+       initializer_t *result = allocate_ast_zero(get_initializer_size(type));
+       result->type          = type;
+
+       return result;
+}
+
 static inline void free_type(void *type)
 {
        obstack_free(type_obst, type);
@@ -654,75 +674,59 @@ static expression_t *create_implicit_cast(expression_t *expression,
        if(source_type == dest_type)
                return expression;
 
-       if(dest_type->type == TYPE_ATOMIC) {
-               if(source_type->type != TYPE_ATOMIC)
-                       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->source_position,
-                                               source_type, dest_type);
-                       return expression;
-               }
-
-               return create_cast_expression(expression, dest_type);
-       }
-       if(dest_type->type == TYPE_POINTER) {
-               pointer_type_t *pointer_type
-                       = (pointer_type_t*) dest_type;
-               switch (source_type->type) {
-                       case TYPE_ATOMIC:
-                               if (is_null_expression(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;
+       switch (dest_type->type) {
+               case TYPE_ENUM:
+                       /* TODO warning for implicitly converting to enum */
+               case TYPE_ATOMIC:
+                       if (source_type->type != TYPE_ATOMIC &&
+                                       source_type->type != TYPE_ENUM) {
+                               panic("casting of non-atomic types not implemented yet");
+                       }
 
-                       case TYPE_ARRAY: {
-                               array_type_t *const array_type = (array_type_t*) source_type;
-                               if (types_compatible(array_type->element_type,
-                                                                                                                pointer_type->points_to)) {
-                                       return create_cast_expression(expression, dest_type);
-                               }
-                               break;
+                       if(is_type_floating(dest_type) && !is_type_scalar(source_type)) {
+                               type_error_incompatible("can't cast types",
+                                               expression->source_position, source_type, dest_type);
+                               return expression;
                        }
 
-                       default:
-                               panic("casting of non-atomic types not implemented yet");
-               }
+                       return create_cast_expression(expression, dest_type);
 
-               type_error_incompatible("can't implicitly cast types",
-                                       expression->source_position,
-                                       source_type, dest_type);
-               return expression;
-       }
+               case TYPE_POINTER:
+                       switch (source_type->type) {
+                               case TYPE_ATOMIC:
+                                       if (is_null_expression(expression)) {
+                                               return create_cast_expression(expression, dest_type);
+                                       }
+                                       break;
 
-       panic("casting of non-atomic types not implemented yet");
-}
+                               case TYPE_POINTER:
+                                       if (pointers_compatible(source_type, dest_type)) {
+                                               return create_cast_expression(expression, dest_type);
+                                       }
+                                       break;
 
-static bool is_atomic_type(const type_t *type, atomic_type_type_t atype)
-{
-       if(type->type != TYPE_ATOMIC)
-               return false;
-       const atomic_type_t *atomic_type = (const atomic_type_t*) type;
+                               case TYPE_ARRAY: {
+                                       array_type_t   *array_type = (array_type_t*) source_type;
+                                       pointer_type_t *pointer_type
+                                               = (pointer_type_t*) dest_type;
+                                       if (types_compatible(array_type->element_type,
+                                                                                pointer_type->points_to)) {
+                                               return create_cast_expression(expression, dest_type);
+                                       }
+                                       break;
+                               }
 
-       return atomic_type->atype == atype;
-}
+                               default:
+                                       panic("casting of non-atomic types not implemented yet");
+                       }
 
-static bool is_pointer(const type_t *type)
-{
-       return type->type == TYPE_POINTER;
-}
+                       type_error_incompatible("can't implicitly cast types",
+                                       expression->source_position, source_type, dest_type);
+                       return expression;
 
-static bool is_compound_type(const type_t *type)
-{
-       return type->type == TYPE_COMPOUND_STRUCT
-               || type->type == TYPE_COMPOUND_UNION;
+               default:
+                       panic("casting of non-atomic types not implemented yet");
+       }
 }
 
 /** Implements the rules from § 6.5.16.1 */
@@ -738,21 +742,24 @@ static void semantic_assign(type_t *orig_type_left, expression_t **right,
        type_t *const type_right = skip_typeref(orig_type_right);
 
        if ((is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) ||
-           (is_pointer(type_left) && is_null_expression(*right)) ||
-           (is_atomic_type(type_left, ATOMIC_TYPE_BOOL)
-               && is_pointer(type_right))) {
+           (is_type_pointer(type_left) && is_null_expression(*right)) ||
+           (is_type_atomic(type_left, ATOMIC_TYPE_BOOL)
+               && is_type_pointer(type_right))) {
                *right = create_implicit_cast(*right, type_left);
                return;
        }
 
-       if (is_pointer(type_left) && is_pointer(type_right)) {
+       if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
                pointer_type_t *pointer_type_left  = (pointer_type_t*) type_left;
                pointer_type_t *pointer_type_right = (pointer_type_t*) type_right;
                type_t         *points_to_left     = pointer_type_left->points_to;
                type_t         *points_to_right    = pointer_type_right->points_to;
 
-               if(!is_atomic_type(points_to_left, ATOMIC_TYPE_VOID)
-                               && !is_atomic_type(points_to_right, ATOMIC_TYPE_VOID)
+               points_to_left  = skip_typeref(points_to_left);
+               points_to_right = skip_typeref(points_to_right);
+
+               if(!is_type_atomic(points_to_left, ATOMIC_TYPE_VOID)
+                               && !is_type_atomic(points_to_right, ATOMIC_TYPE_VOID)
                                && !types_compatible(points_to_left, points_to_right)) {
                        goto incompatible_assign_types;
                }
@@ -776,7 +783,7 @@ static void semantic_assign(type_t *orig_type_left, expression_t **right,
                return;
        }
 
-       if (is_compound_type(type_left)
+       if (is_type_compound(type_left)
                        && types_compatible(type_left, type_right)) {
                *right = create_implicit_cast(*right, type_left);
                return;
@@ -933,19 +940,15 @@ static initializer_t *initializer_from_string(array_type_t *type,
        /* TODO: check len vs. size of array type */
        (void) type;
 
-       initializer_string_t *initializer
-               = allocate_ast_zero(sizeof(initializer[0]));
+       initializer_t *initializer = allocate_initializer(INITIALIZER_STRING);
+       initializer->string.string = string;
 
-       initializer->initializer.type = INITIALIZER_STRING;
-       initializer->string           = string;
-
-       return (initializer_t*) initializer;
+       return initializer;
 }
 
 static initializer_t *initializer_from_expression(type_t *type,
                                                   expression_t *expression)
 {
-
        /* TODO check that expression is a constant expression */
 
        /* § 6.7.8.14/15 char array may be initialized by string literals */
@@ -970,11 +973,10 @@ static initializer_t *initializer_from_expression(type_t *type,
 
        semantic_assign(type, &expression, "initializer");
 
-       initializer_value_t *result = allocate_ast_zero(sizeof(result[0]));
-       result->initializer.type = INITIALIZER_VALUE;
-       result->value            = expression;
+       initializer_t *result = allocate_initializer(INITIALIZER_VALUE);
+       result->value.value   = expression;
 
-       return (initializer_t*) result;
+       return result;
 }
 
 static initializer_t *parse_sub_initializer(type_t *type,
@@ -1025,15 +1027,14 @@ static initializer_t *parse_sub_initializer(type_t *type,
        /* TODO: ignore qualifiers, comparing pointers is probably
         * not correct */
        if(expression != NULL && expression_type == type) {
-               initializer_value_t *result = allocate_ast_zero(sizeof(result[0]));
-               result->initializer.type    = INITIALIZER_VALUE;
+               initializer_t *result = allocate_initializer(INITIALIZER_VALUE);
 
                if(type != NULL) {
                        semantic_assign(type, &expression, "initializer");
                }
-               result->value = expression;
+               result->value.value = expression;
 
-               return (initializer_t*) result;
+               return result;
        }
 
        bool read_paren = false;
@@ -1124,6 +1125,8 @@ static initializer_t *parse_sub_initializer(type_t *type,
                        if(token.type == '}')
                                break;
                        expect_block(',');
+                       if(token.type == '}')
+                               break;
 
                        type_t *iter_type = iter->type;
                        iter_type         = skip_typeref(iter_type);
@@ -1266,7 +1269,7 @@ static declaration_t *parse_compound_type_specifier(bool is_struct)
        return declaration;
 }
 
-static void parse_enum_entries(type_t *enum_type)
+static void parse_enum_entries(enum_type_t *const enum_type)
 {
        eat('{');
 
@@ -1285,7 +1288,7 @@ static void parse_enum_entries(type_t *enum_type)
                        return;
                }
                entry->storage_class   = STORAGE_CLASS_ENUM_ENTRY;
-               entry->type            = enum_type;
+               entry->type            = (type_t*) enum_type;
                entry->symbol          = token.v.symbol;
                entry->source_position = token.source_position;
                next_token();
@@ -1307,7 +1310,7 @@ static void parse_enum_entries(type_t *enum_type)
        expect_void('}');
 }
 
-static declaration_t *parse_enum_specifier(void)
+static type_t *parse_enum_specifier(void)
 {
        eat(T_enum);
 
@@ -1336,6 +1339,10 @@ static declaration_t *parse_enum_specifier(void)
                declaration->symbol          = symbol;
        }
 
+       enum_type_t *const enum_type = allocate_type_zero(sizeof(enum_type[0]));
+       enum_type->type.type         = TYPE_ENUM;
+       enum_type->declaration       = declaration;
+
        if(token.type == '{') {
                if(declaration->init.is_defined) {
                        parser_print_error_prefix();
@@ -1345,11 +1352,11 @@ static declaration_t *parse_enum_specifier(void)
                record_declaration(declaration);
                declaration->init.is_defined = 1;
 
-               parse_enum_entries(NULL);
+               parse_enum_entries(enum_type);
                parse_attributes();
        }
 
-       return declaration;
+       return (type_t*) enum_type;
 }
 
 /**
@@ -1542,31 +1549,24 @@ static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
                /* TODO: if type != NULL for the following rules should issue
                 * an error */
                case T_struct: {
-                       compound_type_t *compound_type
-                               = allocate_type_zero(sizeof(compound_type[0]));
-                       compound_type->type.type = TYPE_COMPOUND_STRUCT;
-                       compound_type->declaration = parse_compound_type_specifier(true);
+                       type = allocate_type_zero(sizeof(struct compound_type_t));
 
-                       type = (type_t*) compound_type;
+                       compound_type_t *compound_type = (compound_type_t*) type;
+                       compound_type->type.type   = TYPE_COMPOUND_STRUCT;
+                       compound_type->declaration = parse_compound_type_specifier(true);
                        break;
                }
                case T_union: {
-                       compound_type_t *compound_type
-                               = allocate_type_zero(sizeof(compound_type[0]));
-                       compound_type->type.type = TYPE_COMPOUND_UNION;
-                       compound_type->declaration = parse_compound_type_specifier(false);
+                       type = allocate_type_zero(sizeof(compound_type_t));
 
-                       type = (type_t*) compound_type;
+                       compound_type_t *compound_type = (compound_type_t*) type;
+                       compound_type->type.type   = TYPE_COMPOUND_UNION;
+                       compound_type->declaration = parse_compound_type_specifier(false);
                        break;
                }
-               case T_enum: {
-                       enum_type_t *enum_type = allocate_type_zero(sizeof(enum_type[0]));
-                       enum_type->type.type   = TYPE_ENUM;
-                       enum_type->declaration = parse_enum_specifier();
-
-                       type = (type_t*) enum_type;
+               case T_enum:
+                       type = parse_enum_specifier();
                        break;
-               }
                case T___typeof__:
                        type = parse_typeof();
                        break;
@@ -1732,9 +1732,9 @@ finish_specifiers:
        specifiers->type = result;
 }
 
-static unsigned parse_type_qualifiers(void)
+static type_qualifiers_t parse_type_qualifiers(void)
 {
-       unsigned type_qualifiers = TYPE_QUALIFIER_NONE;
+       type_qualifiers_t type_qualifiers = TYPE_QUALIFIER_NONE;
 
        while(true) {
                switch(token.type) {
@@ -1784,8 +1784,8 @@ static declaration_t *parse_parameter(void)
        if (declaration->type->type == TYPE_ARRAY) {
                const array_type_t *const arr_type =
                        (const array_type_t*)declaration->type;
-               declaration->type =
-                       make_pointer_type(arr_type->element_type, TYPE_QUALIFIER_NONE);
+               type_t *element_type = arr_type->element_type;
+               declaration->type = make_pointer_type(element_type, TYPE_QUALIFIER_NONE);
        }
 
        return declaration;
@@ -1868,7 +1868,7 @@ struct construct_type_t {
 typedef struct parsed_pointer_t parsed_pointer_t;
 struct parsed_pointer_t {
        construct_type_t  construct_type;
-       type_qualifier_t  type_qualifiers;
+       type_qualifiers_t type_qualifiers;
 };
 
 typedef struct construct_function_type_t construct_function_type_t;
@@ -1880,7 +1880,7 @@ struct construct_function_type_t {
 typedef struct parsed_array_t parsed_array_t;
 struct parsed_array_t {
        construct_type_t  construct_type;
-       type_qualifier_t  type_qualifiers;
+       type_qualifiers_t type_qualifiers;
        bool              is_static;
        bool              is_variable;
        expression_t     *size;
@@ -1917,7 +1917,7 @@ static construct_type_t *parse_array_declarator(void)
                next_token();
        }
 
-       type_qualifier_t type_qualifiers = parse_type_qualifiers();
+       type_qualifiers_t type_qualifiers = parse_type_qualifiers();
        if(type_qualifiers != 0) {
                if(token.type == T_static) {
                        array->is_static = true;
@@ -2221,13 +2221,11 @@ static void parse_init_declarators(const declaration_specifiers_t *specifiers)
                                        cnst->expression.datatype = type_size_t;
 
                                        if(initializer->type == INITIALIZER_LIST) {
-                                               initializer_list_t *list
-                                                       = (initializer_list_t*) initializer;
+                                               initializer_list_t *list = &initializer->list;
                                                cnst->v.int_value = list->len;
                                        } else {
                                                assert(initializer->type == INITIALIZER_STRING);
-                                               initializer_string_t *string
-                                                       = (initializer_string_t*) initializer;
+                                               initializer_string_t *string = &initializer->string;
                                                cnst->v.int_value = strlen(string->string) + 1;
                                        }
 
@@ -2511,6 +2509,110 @@ static declaration_t *create_implicit_function(symbol_t *symbol,
        return declaration;
 }
 
+static type_t *make_function_1_type(type_t *result_type, type_t *argument_type)
+{
+       function_parameter_t *parameter = allocate_type_zero(sizeof(parameter[0]));
+       parameter->type = argument_type;
+
+       function_type_t *type = allocate_type_zero(sizeof(type[0]));
+       type->type.type   = TYPE_FUNCTION;
+       type->result_type = result_type;
+       type->parameters  = parameter;
+
+       type_t *result = typehash_insert((type_t*) type);
+       if(result != (type_t*) type) {
+               free_type(type);
+       }
+
+       return result;
+}
+
+static type_t *get_builtin_symbol_type(symbol_t *symbol)
+{
+       switch(symbol->ID) {
+       case T___builtin_alloca:
+               return make_function_1_type(type_void_ptr, type_size_t);
+       default:
+               panic("not implemented builtin symbol found");
+       }
+}
+
+/**
+ * performs automatic type cast as described in § 6.3.2.1
+ */
+static type_t *automatic_type_conversion(type_t *type)
+{
+       if(type == NULL)
+               return NULL;
+
+       if(type->type == TYPE_ARRAY) {
+               array_type_t *array_type   = (array_type_t*) type;
+               type_t       *element_type = array_type->element_type;
+               unsigned      qualifiers   = array_type->type.qualifiers;
+
+               return make_pointer_type(element_type, qualifiers);
+       }
+
+       if(type->type == TYPE_FUNCTION) {
+               return make_pointer_type(type, TYPE_QUALIFIER_NONE);
+       }
+
+       return type;
+}
+
+/**
+ * reverts the automatic casts of array to pointer types and function
+ * to function-pointer types as defined § 6.3.2.1
+ */
+type_t *revert_automatic_type_conversion(const expression_t *expression)
+{
+       if(expression->datatype == NULL)
+               return NULL;
+
+       switch(expression->type) {
+       case EXPR_REFERENCE: {
+               const reference_expression_t *ref
+                       = (const reference_expression_t*) expression;
+               return ref->declaration->type;
+       }
+       case EXPR_SELECT: {
+               const select_expression_t *select
+                       = (const select_expression_t*) expression;
+               return select->compound_entry->type;
+       }
+       case EXPR_UNARY: {
+               const unary_expression_t *unary
+                       = (const unary_expression_t*) expression;
+               if(unary->type == UNEXPR_DEREFERENCE) {
+                       expression_t   *value        = unary->value;
+                       type_t         *type         = skip_typeref(value->datatype);
+                       pointer_type_t *pointer_type = (pointer_type_t*) type;
+
+                       return pointer_type->points_to;
+               }
+               break;
+       }
+       case EXPR_BUILTIN_SYMBOL: {
+               const builtin_symbol_expression_t *builtin
+                       = (const builtin_symbol_expression_t*) expression;
+               return get_builtin_symbol_type(builtin->symbol);
+       }
+       case EXPR_ARRAY_ACCESS: {
+               const array_access_expression_t *array_access
+                       = (const array_access_expression_t*) expression;
+               type_t *type_left  = skip_typeref(array_access->array_ref->datatype);
+               assert(is_type_pointer(type_left));
+               pointer_type_t *pointer_type = (pointer_type_t*) type_left;
+               return pointer_type->points_to;
+       }
+
+       default:
+               break;
+       }
+
+       return expression->datatype;
+}
+
 static expression_t *parse_reference(void)
 {
        reference_expression_t *ref = allocate_ast_zero(sizeof(ref[0]));
@@ -2542,8 +2644,13 @@ static expression_t *parse_reference(void)
                }
        }
 
+       type_t *type = declaration->type;
+       /* we always do the auto-type conversions; the & and sizeof parser contains
+        * code to revert this! */
+       type = automatic_type_conversion(type);
+
        ref->declaration         = declaration;
-       ref->expression.datatype = declaration->type;
+       ref->expression.datatype = type;
 
        return (expression_t*) ref;
 }
@@ -2753,24 +2860,6 @@ static expression_t *parse_va_arg(void)
        return (expression_t*) expression;
 }
 
-static type_t *make_function_1_type(type_t *result_type, type_t *argument_type)
-{
-       function_parameter_t *parameter = allocate_type_zero(sizeof(parameter[0]));
-       parameter->type = argument_type;
-
-       function_type_t *type = allocate_type_zero(sizeof(type[0]));
-       type->type.type   = TYPE_FUNCTION;
-       type->result_type = result_type;
-       type->parameters  = parameter;
-
-       type_t *result = typehash_insert((type_t*) type);
-       if(result != (type_t*) type) {
-               free_type(type);
-       }
-
-       return result;
-}
-
 static expression_t *parse_builtin_symbol(void)
 {
        builtin_symbol_expression_t *expression
@@ -2778,16 +2867,11 @@ static expression_t *parse_builtin_symbol(void)
        expression->expression.type = EXPR_BUILTIN_SYMBOL;
 
        expression->symbol = token.v.symbol;
-
-       type_t *type;
-       switch(token.type) {
-       case T___builtin_alloca:
-               type = make_function_1_type(type_void_ptr, type_size_t);
-               break;
-       }
-
        next_token();
 
+       type_t *type = get_builtin_symbol_type(expression->symbol);
+       type = automatic_type_conversion(type);
+
        expression->expression.datatype = type;
        return (expression_t*) expression;
 }
@@ -2832,45 +2916,46 @@ static expression_t *parse_primary_expression(void)
 }
 
 static expression_t *parse_array_expression(unsigned precedence,
-                                            expression_t *array_ref)
+                                            expression_t *left)
 {
        (void) precedence;
 
        eat('[');
 
-       expression_t *index = parse_expression();
+       expression_t *inside = parse_expression();
 
        array_access_expression_t *array_access
                = allocate_ast_zero(sizeof(array_access[0]));
 
        array_access->expression.type = EXPR_ARRAY_ACCESS;
-       array_access->array_ref       = array_ref;
-       array_access->index           = index;
-
-       type_t *type_left  = skip_typeref(array_ref->datatype);
-       type_t *type_right = skip_typeref(index->datatype);
-
-       if(type_left != NULL && type_right != NULL) {
-               if(type_left->type == TYPE_POINTER) {
-                       pointer_type_t *pointer           = (pointer_type_t*) type_left;
-                       array_access->expression.datatype = pointer->points_to;
-               } else if(type_left->type == TYPE_ARRAY) {
-                       array_type_t *array_type          = (array_type_t*) type_left;
-                       array_access->expression.datatype = array_type->element_type;
-               } else if(type_right->type == TYPE_POINTER) {
-                       pointer_type_t *pointer           = (pointer_type_t*) type_right;
-                       array_access->expression.datatype = pointer->points_to;
-               } else if(type_right->type == TYPE_ARRAY) {
-                       array_type_t *array_type          = (array_type_t*) type_right;
-                       array_access->expression.datatype = array_type->element_type;
+
+       type_t *type_left   = skip_typeref(left->datatype);
+       type_t *type_inside = skip_typeref(inside->datatype);
+       type_t *result_type;
+
+       if(type_left != NULL && type_inside != NULL) {
+               if(is_type_pointer(type_left)) {
+                       pointer_type_t *pointer = (pointer_type_t*) type_left;
+                       result_type             = pointer->points_to;
+                       array_access->array_ref = left;
+                       array_access->index     = inside;
+               } else if(is_type_pointer(type_inside)) {
+                       pointer_type_t *pointer = (pointer_type_t*) type_inside;
+                       result_type             = pointer->points_to;
+                       array_access->array_ref = inside;
+                       array_access->index     = left;
+                       array_access->flipped   = true;
                } else {
                        parser_print_error_prefix();
                        fprintf(stderr, "array access on object with non-pointer types ");
                        print_type_quoted(type_left);
                        fprintf(stderr, ", ");
-                       print_type_quoted(type_right);
+                       print_type_quoted(type_inside);
                        fprintf(stderr, "\n");
                }
+       } else {
+               array_access->array_ref = left;
+               array_access->index     = inside;
        }
 
        if(token.type != ']') {
@@ -2879,6 +2964,9 @@ static expression_t *parse_array_expression(unsigned precedence,
        }
        next_token();
 
+       result_type = automatic_type_conversion(result_type);
+       array_access->expression.datatype = result_type;
+
        return (expression_t*) array_access;
 }
 
@@ -2915,7 +3003,9 @@ static expression_t *parse_sizeof(unsigned precedence)
                sizeof_expression->type = parse_typename();
                expect(')');
        } else {
-               expression_t *expression           = parse_sub_expression(precedence);
+               expression_t *expression = parse_sub_expression(precedence);
+               expression->datatype     = revert_automatic_type_conversion(expression);
+
                sizeof_expression->type            = expression->datatype;
                sizeof_expression->size_expression = expression;
        }
@@ -3000,8 +3090,12 @@ static expression_t *parse_select_expression(unsigned precedence,
                return make_invalid_expression();
        }
 
+       /* we always do the auto-type conversions; the & and sizeof parser contains
+        * code to revert this! */
+       type_t *expression_type = automatic_type_conversion(iter->type);
+
        select->compound_entry      = iter;
-       select->expression.datatype = iter->type;
+       select->expression.datatype = expression_type;
        return (expression_t*) select;
 }
 
@@ -3015,26 +3109,31 @@ static expression_t *parse_call_expression(unsigned precedence,
 
        function_type_t *function_type;
        type_t          *orig_type     = expression->datatype;
-       type_t          *type          = skip_typeref(orig_type);
+       if(orig_type != NULL) {
+               function_type = NULL;
+               type_t *type  = skip_typeref(orig_type);
 
-       if(type->type == TYPE_POINTER) {
-               pointer_type_t *pointer_type = (pointer_type_t*) type;
+               if(is_type_pointer(type)) {
+                       pointer_type_t *pointer_type = (pointer_type_t*) type;
 
-               type = skip_typeref(pointer_type->points_to);
-       }
-       if (type->type == TYPE_FUNCTION) {
-               function_type             = (function_type_t*) type;
-               call->expression.datatype = function_type->result_type;
-       } else {
-               parser_print_error_prefix();
-               fputs("called object '", stderr);
-               print_expression(expression);
-               fputs("' (type ", stderr);
-               print_type_quoted(orig_type);
-               fputs(") is not a function\n", stderr);
+                       type = skip_typeref(pointer_type->points_to);
 
-               function_type             = NULL;
-               call->expression.datatype = NULL;
+                       if (type->type == TYPE_FUNCTION) {
+                               function_type             = (function_type_t*) type;
+                               call->expression.datatype = function_type->result_type;
+                       }
+               }
+               if(function_type == NULL) {
+                       parser_print_error_prefix();
+                       fputs("called object '", stderr);
+                       print_expression(expression);
+                       fputs("' (type ", stderr);
+                       print_type_quoted(orig_type);
+                       fputs(") is not a pointer to a function\n", stderr);
+
+                       function_type             = NULL;
+                       call->expression.datatype = NULL;
+               }
        }
 
        /* parse arguments */
@@ -3273,35 +3372,30 @@ static void semantic_dereference(unary_expression_t *expression)
                return;
 
        type_t *type = skip_typeref(orig_type);
-       switch (type->type) {
-               case TYPE_ARRAY: {
-                       array_type_t *const array_type  = (array_type_t*)type;
-                       expression->expression.datatype = array_type->element_type;
-                       break;
-               }
+       if(!is_type_pointer(type)) {
+               parser_print_error_prefix();
+               fputs("'Unary *' needs pointer or arrray type, but type ", stderr);
+               print_type_quoted(orig_type);
+               fputs(" given.\n", stderr);
+               return;
+       }
 
-               case TYPE_POINTER: {
-                       pointer_type_t *pointer_type    = (pointer_type_t*)type;
-                       expression->expression.datatype = pointer_type->points_to;
-                       break;
-               }
+       pointer_type_t *pointer_type = (pointer_type_t*)type;
+       type_t         *result_type  = pointer_type->points_to;
 
-               default:
-                       parser_print_error_prefix();
-                       fputs("'Unary *' needs pointer or arrray type, but type ", stderr);
-                       print_type_quoted(orig_type);
-                       fputs(" given.\n", stderr);
-                       return;
-       }
+       result_type = automatic_type_conversion(result_type);
+       expression->expression.datatype = result_type;
 }
 
 static void semantic_take_addr(unary_expression_t *expression)
 {
-       type_t *orig_type = expression->value->datatype;
+       expression_t *value = expression->value;
+       value->datatype     = revert_automatic_type_conversion(value);
+
+       type_t *orig_type = value->datatype;
        if(orig_type == NULL)
                return;
 
-       expression_t *value = expression->value;
        if(value->type == EXPR_REFERENCE) {
                reference_expression_t *reference   = (reference_expression_t*) value;
                declaration_t          *declaration = reference->declaration;
@@ -3310,7 +3404,7 @@ static void semantic_take_addr(unary_expression_t *expression)
                }
        }
 
-       expression->expression.datatype = make_pointer_type(orig_type, 0);
+       expression->expression.datatype = make_pointer_type(orig_type, TYPE_QUALIFIER_NONE);
 }
 
 #define CREATE_UNARY_EXPRESSION_PARSER(token_type, unexpression_type, sfunc)   \
@@ -3475,18 +3569,10 @@ static void semantic_add(binary_expression_t *expression)
                expression->right = create_implicit_cast(right, arithmetic_type);
                expression->expression.datatype = arithmetic_type;
                return;
-       } else if(type_left->type == TYPE_POINTER && is_type_integer(type_right)) {
+       } else if(is_type_pointer(type_left) && is_type_integer(type_right)) {
                expression->expression.datatype = type_left;
-       } else if(type_right->type == TYPE_POINTER && is_type_integer(type_left)) {
+       } else if(is_type_pointer(type_right) && is_type_integer(type_left)) {
                expression->expression.datatype = type_right;
-       } else if (type_left->type == TYPE_ARRAY && is_type_integer(type_right)) {
-               const array_type_t *const arr_type = (const array_type_t*)type_left;
-               expression->expression.datatype =
-                 make_pointer_type(arr_type->element_type, TYPE_QUALIFIER_NONE);
-       } else if (type_right->type == TYPE_ARRAY && is_type_integer(type_left)) {
-               const array_type_t *const arr_type = (const array_type_t*)type_right;
-               expression->expression.datatype =
-                       make_pointer_type(arr_type->element_type, TYPE_QUALIFIER_NONE);
        } else {
                parser_print_error_prefix();
                fprintf(stderr, "invalid operands to binary + (");
@@ -3660,6 +3746,13 @@ static void semantic_logical_op(binary_expression_t *expression)
        expression->expression.datatype = type_int;
 }
 
+static bool has_const_fields(type_t *type)
+{
+       (void) type;
+       /* TODO */
+       return false;
+}
+
 static void semantic_binexpr_assign(binary_expression_t *expression)
 {
        expression_t *left           = expression->left;
@@ -3668,13 +3761,17 @@ static void semantic_binexpr_assign(binary_expression_t *expression)
        if(orig_type_left == NULL)
                return;
 
-       type_t *type_left = skip_typeref(orig_type_left);
+       type_t *type_left = revert_automatic_type_conversion(left);
+       type_left = skip_typeref(orig_type_left);
 
+       /* must be a modifiable lvalue */
        if (type_left->type == TYPE_ARRAY) {
-               parse_error("Cannot assign to arrays.");
+               parser_print_error_prefix();
+               fprintf(stderr, "Cannot assign to arrays ('");
+               print_expression(left);
+               fprintf(stderr, "')\n");
                return;
        }
-
        if(type_left->qualifiers & TYPE_QUALIFIER_CONST) {
                parser_print_error_prefix();
                fprintf(stderr, "assignment to readonly location '");
@@ -3682,6 +3779,25 @@ static void semantic_binexpr_assign(binary_expression_t *expression)
                fprintf(stderr, "' (type ");
                print_type_quoted(orig_type_left);
                fprintf(stderr, ")\n");
+               return;
+       }
+       if(is_type_incomplete(type_left)) {
+               parser_print_error_prefix();
+               fprintf(stderr, "left-hand side of assignment '");
+               print_expression(left);
+               fprintf(stderr, "' has incomplete type ");
+               print_type_quoted(orig_type_left);
+               fprintf(stderr, "\n");
+               return;
+       }
+       if(is_type_compound(type_left) && has_const_fields(type_left)) {
+               parser_print_error_prefix();
+               fprintf(stderr, "can't assign to '");
+               print_expression(left);
+               fprintf(stderr, "' because compound type ");
+               print_type_quoted(orig_type_left);
+               fprintf(stderr, " has readonly fields\n");
+               return;
        }
 
        semantic_assign(orig_type_left, &expression->right, "assignment");
@@ -4436,17 +4552,17 @@ void init_parser(void)
        init_expression_parsers();
        obstack_init(&temp_obst);
 
-       type_int         = make_atomic_type(ATOMIC_TYPE_INT, 0);
-       type_uint        = make_atomic_type(ATOMIC_TYPE_UINT, 0);
-       type_long_double = make_atomic_type(ATOMIC_TYPE_LONG_DOUBLE, 0);
-       type_double      = make_atomic_type(ATOMIC_TYPE_DOUBLE, 0);
-       type_float       = make_atomic_type(ATOMIC_TYPE_FLOAT, 0);
-       type_size_t      = make_atomic_type(ATOMIC_TYPE_ULONG, 0);
-       type_ptrdiff_t   = make_atomic_type(ATOMIC_TYPE_LONG, 0);
-       type_const_char  = make_atomic_type(ATOMIC_TYPE_CHAR, TYPE_QUALIFIER_CONST);
-       type_void        = make_atomic_type(ATOMIC_TYPE_VOID, 0);
-       type_void_ptr    = make_pointer_type(type_void, 0);
-       type_string      = make_pointer_type(type_const_char, 0);
+       type_int         = make_atomic_type(ATOMIC_TYPE_INT, TYPE_QUALIFIER_NONE);
+       type_uint        = make_atomic_type(ATOMIC_TYPE_UINT, TYPE_QUALIFIER_NONE);
+       type_long_double = make_atomic_type(ATOMIC_TYPE_LONG_DOUBLE, TYPE_QUALIFIER_NONE);
+       type_double      = make_atomic_type(ATOMIC_TYPE_DOUBLE, TYPE_QUALIFIER_NONE);
+       type_float       = make_atomic_type(ATOMIC_TYPE_FLOAT, TYPE_QUALIFIER_NONE);
+       type_size_t      = make_atomic_type(ATOMIC_TYPE_ULONG, TYPE_QUALIFIER_NONE);
+       type_ptrdiff_t   = make_atomic_type(ATOMIC_TYPE_LONG, TYPE_QUALIFIER_NONE);
+       type_char        = make_atomic_type(ATOMIC_TYPE_CHAR, TYPE_QUALIFIER_NONE);
+       type_void        = make_atomic_type(ATOMIC_TYPE_VOID, TYPE_QUALIFIER_NONE);
+       type_void_ptr    = make_pointer_type(type_void, TYPE_QUALIFIER_NONE);
+       type_string      = make_pointer_type(type_char, TYPE_QUALIFIER_NONE);
 }
 
 void exit_parser(void)