+static int get_rank(const type_t *type)
+{
+ /* The C-standard allows promoting to int or unsigned int (see § 7.2.2
+ * and esp. footnote 108). However we can't fold constants (yet), so we
+ * can't decide wether unsigned int is possible, while int always works.
+ * (unsigned int would be preferable when possible... for stuff like
+ * struct { enum { ... } bla : 4; } ) */
+ if(type->type == TYPE_ENUM)
+ return ATOMIC_TYPE_INT;
+
+ assert(type->type == TYPE_ATOMIC);
+ atomic_type_t *atomic_type = (atomic_type_t*) type;
+ atomic_type_type_t atype = atomic_type->atype;
+ return atype;
+}
+
+static type_t *promote_integer(type_t *type)
+{
+ if(get_rank(type) < ATOMIC_TYPE_INT)
+ type = type_int;
+
+ return type;
+}
+
+static expression_t *create_cast_expression(expression_t *expression,
+ type_t *dest_type)
+{
+ unary_expression_t *cast = allocate_ast_zero(sizeof(cast[0]));
+
+ cast->expression.type = EXPR_UNARY;
+ cast->type = UNEXPR_CAST;
+ cast->value = expression;
+ cast->expression.datatype = dest_type;
+
+ return (expression_t*) cast;
+}
+
+static bool is_null_expression(const expression_t *const expr)
+{
+ if (expr->type != EXPR_CONST) return false;
+
+ type_t *const type = skip_typeref(expr->datatype);
+ if (!is_type_integer(type)) return false;
+
+ const const_t *const const_expr = (const const_t*)expr;
+ return const_expr->v.int_value == 0;
+}
+
+static expression_t *create_implicit_cast(expression_t *expression,
+ type_t *dest_type)
+{
+ type_t *source_type = expression->datatype;
+
+ if(source_type == NULL)
+ return expression;
+
+ source_type = skip_typeref(source_type);
+ dest_type = skip_typeref(dest_type);
+
+ 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;
+
+ 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;
+ }
+
+ default:
+ panic("casting of non-atomic types not implemented yet");
+ }
+
+ type_error_incompatible("can't implicitly cast types",
+ expression->source_position,
+ source_type, dest_type);
+ return 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)
+{
+ type_t *orig_type_right = (*right)->datatype;
+
+ if(orig_type_right == NULL)
+ return;
+
+ 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_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 (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;
+
+ 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;
+ }
+
+ /* 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);
+ parser_print_error_prefix();
+ print_type_quoted(type_left);
+ fputs(" <- ", stderr);
+ print_type_quoted(type_right);
+ fputs("\n", stderr);
+}
+