implement semantic_assign like the C standard describes it
authorMatthias Braun <matze@braunis.de>
Sat, 24 Nov 2007 14:28:17 +0000 (14:28 +0000)
committerMatthias Braun <matze@braunis.de>
Sat, 24 Nov 2007 14:28:17 +0000 (14:28 +0000)
[r18524]

parser.c
type.c
type.h
type_t.h

index 7ea8225..fa8ad94 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -705,6 +705,27 @@ static expression_t *create_implicit_cast(expression_t *expression,
        panic("casting of non-atomic types not implemented yet");
 }
 
+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;
+
+       return atomic_type->atype == atype;
+}
+
+static bool is_pointer(const type_t *type)
+{
+       return type->type == TYPE_POINTER;
+}
+
+static bool is_compound_type(const type_t *type)
+{
+       return type->type == TYPE_COMPOUND_STRUCT
+               || type->type == TYPE_COMPOUND_UNION;
+}
+
+/** Implements the rules from ยง 6.5.16.1 */
 static void semantic_assign(type_t *orig_type_left, expression_t **right,
                             const char *context)
 {
@@ -716,40 +737,52 @@ static void semantic_assign(type_t *orig_type_left, expression_t **right,
        type_t *const type_left  = skip_typeref(orig_type_left);
        type_t *const type_right = skip_typeref(orig_type_right);
 
-       if (types_compatible(type_left, type_right)) {
-               return;
-       }
-
        if ((is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) ||
-           (type_left->type == TYPE_POINTER && is_null_expression(*right)) ||
-           (type_left->type == TYPE_POINTER && type_right->type == TYPE_POINTER)) {
+           (is_pointer(type_left) && is_null_expression(*right)) ||
+           (is_atomic_type(type_left, ATOMIC_TYPE_BOOL)
+               && is_pointer(type_right))) {
                *right = create_implicit_cast(*right, type_left);
                return;
        }
 
-       if (type_left->type == TYPE_POINTER) {
-               switch (type_right->type) {
-                       case TYPE_FUNCTION: {
-                               pointer_type_t *const ptr_type = (pointer_type_t*)type_left;
-                               if (ptr_type->points_to == type_right) {
-                                       return;
-                               }
-                               break;
-                       }
+       if (is_pointer(type_left) && is_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;
 
-                       case TYPE_ARRAY: {
-                               pointer_type_t *const ptr_type = (pointer_type_t*)type_left;
-                               array_type_t   *const arr_type = (array_type_t*)type_right;
-                               if (ptr_type->points_to == arr_type->element_type) {
-                                       return;
-                               }
-                               break;
-                       }
+               if(!is_atomic_type(points_to_left, ATOMIC_TYPE_VOID)
+                               && !is_atomic_type(points_to_right, ATOMIC_TYPE_VOID)
+                               && !types_compatible(points_to_left, points_to_right)) {
+                       goto incompatible_assign_types;
+               }
 
-                       default: break;
+               /* the left type has all qualifiers from the right type */
+               unsigned missing_qualifiers
+                       = points_to_right->qualifiers & ~points_to_left->qualifiers;
+               if(missing_qualifiers != 0) {
+                       parser_print_error_prefix();
+                       fprintf(stderr, "destination type ");
+                       print_type_quoted(type_left);
+                       fprintf(stderr, " in %s from type ", context);
+                       print_type_quoted(type_right);
+                       fprintf(stderr, " lacks qualifiers '");
+                       print_type_qualifiers(missing_qualifiers);
+                       fprintf(stderr, "' in pointed-to type\n");
+                       return;
                }
+
+               *right = create_implicit_cast(*right, type_left);
+               return;
+       }
+
+       if (is_compound_type(type_left)
+                       && types_compatible(type_left, type_right)) {
+               *right = create_implicit_cast(*right, type_left);
+               return;
        }
 
+incompatible_assign_types:
        /* TODO: improve error message */
        parser_print_error_prefix();
        fprintf(stderr, "incompatible types in %s\n", context);
diff --git a/type.c b/type.c
index 6653c3f..68880a2 100644 (file)
--- a/type.c
+++ b/type.c
@@ -40,7 +40,6 @@ void inc_type_visited(void)
        type_visited++;
 }
 
-static
 void print_type_qualifiers(unsigned qualifiers)
 {
        if(qualifiers & TYPE_QUALIFIER_CONST)    fputs("const ",    out);
@@ -500,28 +499,80 @@ bool is_type_incomplete(const type_t *type)
 
 bool types_compatible(const type_t *type1, const type_t *type2)
 {
+       /* TODO: really incomplete */
        if(type1 == type2)
                return true;
 
-       return true;
+       if(type1->type == TYPE_ATOMIC && type2->type == TYPE_ATOMIC) {
+               const atomic_type_t *atomic1 = (const atomic_type_t*) type1;
+               const atomic_type_t *atomic2 = (const atomic_type_t*) type2;
+
+               return atomic1->atype == atomic2->atype;
+       }
+
+       return false;
 }
 
 bool pointers_compatible(const type_t *type1, const type_t *type2)
 {
        assert(type1->type == TYPE_POINTER);
        assert(type2->type == TYPE_POINTER);
+#if 0
        pointer_type_t *pointer_type1 = (pointer_type_t*) type1;
        pointer_type_t *pointer_type2 = (pointer_type_t*) type2;
        return types_compatible(pointer_type1->points_to,
                                pointer_type2->points_to);
+#endif
+       return true;
+}
+
+static size_t get_type_size(type_t *type)
+{
+       switch(type->type) {
+       case TYPE_ATOMIC:          return sizeof(atomic_type_t); break;
+       case TYPE_COMPOUND_STRUCT:
+       case TYPE_COMPOUND_UNION:  return sizeof(compound_type_t); break;
+       case TYPE_ENUM:            return sizeof(enum_type_t); break;
+       case TYPE_FUNCTION:        return sizeof(function_type_t); break;
+       case TYPE_POINTER:         return sizeof(pointer_type_t); break;
+       case TYPE_ARRAY:           return sizeof(array_type_t); break;
+       case TYPE_BUILTIN:         return sizeof(builtin_type_t); break;
+       case TYPE_TYPEDEF:         return sizeof(typedef_type_t); break;
+       case TYPE_TYPEOF:          return sizeof(typeof_type_t); break;
+       case TYPE_INVALID:         panic("invalid type found"); break;
+       }
+       panic("unknown type found");
+}
+
+/**
+ * duplicates a type
+ * note that this does not produce a deep copy!
+ */
+static type_t *duplicate_type(type_t *type)
+{
+       size_t size = get_type_size(type);
+
+       type_t *copy = obstack_alloc(type_obst, size);
+       memcpy(copy, type, size);
+
+       (void) duplicate_type;
+
+       return type;
 }
 
 type_t *skip_typeref(type_t *type)
 {
+       unsigned qualifiers = type->qualifiers;
+
        while(1) {
                switch(type->type) {
                case TYPE_TYPEDEF: {
+                       qualifiers |= type->qualifiers;
                        const typedef_type_t *typedef_type = (const typedef_type_t*) type;
+                       if(typedef_type->resolved_type != NULL) {
+                               type = typedef_type->resolved_type;
+                               break;
+                       }
                        type = typedef_type->declaration->type;
                        continue;
                }
diff --git a/type.h b/type.h
index 0e6521e..44b721c 100644 (file)
--- a/type.h
+++ b/type.h
@@ -29,6 +29,8 @@ void print_type(type_t *type);
 void print_type_ext(type_t *type, const symbol_t *symbol,
                     const context_t *context);
 
+void print_type_qualifiers(unsigned qualifiers);
+
 void print_enum_definition(const declaration_t *declaration);
 void print_compound_definition(const declaration_t *declaration);
 
index dd7fcfd..57772d6 100644 (file)
--- a/type_t.h
+++ b/type_t.h
@@ -65,10 +65,10 @@ typedef enum {
 } type_qualifier_t;
 
 struct type_t {
-       type_type_t       type;
-       type_qualifier_t  qualifiers;
+       type_type_t  type;
+       unsigned     qualifiers;
 
-       ir_type          *firm_type;
+       ir_type     *firm_type;
 };
 
 struct atomic_type_t {
@@ -126,12 +126,14 @@ struct enum_type_t {
 struct typedef_type_t {
        type_t         type;
        declaration_t *declaration;
+       type_t        *resolved_type;
 };
 
 struct typeof_type_t {
        type_t        type;
        expression_t *expression;
        type_t       *typeof_type;
+       type_t       *resolved_type;
 };
 
 type_t *make_atomic_type(atomic_type_type_t type, type_qualifier_t qualifiers);