ast2firm: Implement casting from complex to real types.
[cparser] / parser.c
index d3f650e..19e165e 100644 (file)
--- a/parser.c
+++ b/parser.c
@@ -1,21 +1,6 @@
 /*
  * This file is part of cparser.
- * Copyright (C) 2007-2009 Matthias Braun <matze@braunis.de>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * as published by the Free Software Foundation; either version 2
- * of the License, or (at your option) any later version.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place - Suite 330, Boston, MA
- * 02111-1307, USA.
+ * Copyright (C) 2012 Matthias Braun <matze@braunis.de>
  */
 #include <config.h>
 
@@ -173,7 +158,8 @@ typedef enum declarator_flags_t {
 static entity_t *parse_declarator(const declaration_specifiers_t *specifiers,
                                   declarator_flags_t flags);
 
-static void semantic_comparison(binary_expression_t *expression);
+static void semantic_comparison(binary_expression_t *expression,
+                                bool is_relational);
 
 #define STORAGE_CLASSES       \
        STORAGE_CLASSES_NO_EXTERN \
@@ -273,7 +259,9 @@ static void semantic_comparison(binary_expression_t *expression);
        case T_false:                     \
        case T_sizeof:                    \
        case T_throw:                     \
-       case T_true:
+       case T_true:                      \
+       case T___imag__:                  \
+       case T___real__:
 
 /**
  * Returns the size of a statement node.
@@ -843,13 +831,6 @@ static void label_pop_to(size_t new_top)
        stack_pop_to(&label_stack, new_top);
 }
 
-static atomic_type_kind_t get_akind(const type_t *type)
-{
-       assert(type->kind == TYPE_ATOMIC || type->kind == TYPE_COMPLEX
-              || type->kind == TYPE_IMAGINARY || type->kind == TYPE_ENUM);
-       return type->atomic.akind;
-}
-
 /**
  * §6.3.1.1:2  Do integer promotion for a given type.
  *
@@ -858,7 +839,8 @@ static atomic_type_kind_t get_akind(const type_t *type)
  */
 static type_t *promote_integer(type_t *type)
 {
-       if (get_akind_rank(get_akind(type)) < get_akind_rank(ATOMIC_TYPE_INT))
+       atomic_type_kind_t akind = get_arithmetic_akind(type);
+       if (get_akind_rank(akind) < get_akind_rank(ATOMIC_TYPE_INT))
                type = type_int;
 
        return type;
@@ -1447,6 +1429,8 @@ static void mark_vars_read(expression_t *const expr, entity_t *lhs_ent)
                case EXPR_UNARY_PREFIX_INCREMENT:
                case EXPR_UNARY_PREFIX_DECREMENT:
                case EXPR_UNARY_ASSUME:
+               case EXPR_UNARY_IMAG:
+               case EXPR_UNARY_REAL:
 unary:
                        mark_vars_read(expr->unary.value, lhs_ent);
                        return;
@@ -1536,7 +1520,13 @@ static designator_t *parse_designation(void)
                        designator->pos = *HERE;
                        eat('[');
                        add_anchor_token(']');
+                       add_anchor_token(T_DOTDOTDOT);
                        designator->array_index = parse_constant_expression();
+                       if (accept(T_DOTDOTDOT)) {
+                               designator->range_last = parse_constant_expression();
+                               errorf(&designator->pos, "range initializer not supported");
+                       }
+                       rem_anchor_token(T_DOTDOTDOT);
                        rem_anchor_token(']');
                        expect(']');
                        break;
@@ -2861,11 +2851,19 @@ finish_specifiers:
        specifiers->attributes = parse_attributes(specifiers->attributes);
 
        if (type == NULL || (saw_error && type_specifiers != 0)) {
+               position_t const* const pos = &specifiers->pos;
                atomic_type_kind_t atomic_type;
 
                /* match valid basic types */
-               switch (type_specifiers) {
+               switch (type_specifiers & ~(SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY)) {
                case SPECIFIER_VOID:
+                       if (type_specifiers & (SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY)) {
+                               if (type_specifiers & SPECIFIER_COMPLEX)
+                                       errorf(pos, "_Complex specifier is invalid for void");
+                               if (type_specifiers & SPECIFIER_IMAGINARY)
+                                       errorf(pos, "_Imaginary specifier is invalid for void");
+                               type_specifiers &= ~(SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY);
+                       }
                        atomic_type = ATOMIC_TYPE_VOID;
                        break;
                case SPECIFIER_WCHAR_T:
@@ -2981,23 +2979,17 @@ warn_about_long_long:
                        atomic_type = ATOMIC_TYPE_LONG_DOUBLE;
                        break;
                case SPECIFIER_BOOL:
+                       if (type_specifiers & (SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY)) {
+                               if (type_specifiers & SPECIFIER_COMPLEX)
+                                       errorf(pos, "_Complex specifier is invalid for _Bool");
+                               if (type_specifiers & SPECIFIER_IMAGINARY)
+                                       errorf(pos, "_Imaginary specifier is invalid for _Bool");
+                               type_specifiers &= ~(SPECIFIER_COMPLEX|SPECIFIER_IMAGINARY);
+                       }
                        atomic_type = ATOMIC_TYPE_BOOL;
                        break;
-               case SPECIFIER_FLOAT | SPECIFIER_COMPLEX:
-               case SPECIFIER_FLOAT | SPECIFIER_IMAGINARY:
-                       atomic_type = ATOMIC_TYPE_FLOAT;
-                       break;
-               case SPECIFIER_DOUBLE | SPECIFIER_COMPLEX:
-               case SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY:
-                       atomic_type = ATOMIC_TYPE_DOUBLE;
-                       break;
-               case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_COMPLEX:
-               case SPECIFIER_LONG | SPECIFIER_DOUBLE | SPECIFIER_IMAGINARY:
-                       atomic_type = ATOMIC_TYPE_LONG_DOUBLE;
-                       break;
                default: {
                        /* invalid specifier combination, give an error message */
-                       position_t const* const pos = &specifiers->pos;
                        if (type_specifiers == 0) {
                                if (!saw_error) {
                                        /* ISO/IEC 14882:1998(E) §C.1.5:4 */
@@ -3009,6 +3001,10 @@ warn_about_long_long:
                                                errorf(pos, "no type specifiers given in declaration");
                                        }
                                }
+                       } else if (type_specifiers == SPECIFIER_COMPLEX) {
+                               warningf(WARN_OTHER, pos, "_Complex requires a type specifier; assuming '_Complex double'");
+                               atomic_type = ATOMIC_TYPE_DOUBLE;
+                               break;
                        } else if ((type_specifiers & SPECIFIER_SIGNED) &&
                                  (type_specifiers & SPECIFIER_UNSIGNED)) {
                                errorf(pos, "signed and unsigned specifiers given");
@@ -4075,9 +4071,7 @@ warn_redundant_declaration: ;
                                                                     decl->attributes);
                                        if (has_new_attrs) {
                                                merge_in_attributes(decl, prev_decl->attributes);
-                                       } else if (!is_definition        &&
-                                                       is_type_valid(prev_type) &&
-                                                       !pos->is_system_header) {
+                                       } else if (!is_definition && is_type_valid(prev_type)) {
                                                warningf(WARN_REDUNDANT_DECLS, pos, "redundant declaration for '%N' (declared %P)", entity, ppos);
                                        }
                                } else if (current_function == NULL) {
@@ -4130,10 +4124,11 @@ error_redeclaration:
                }
        } else if (entity->kind == ENTITY_VARIABLE) {
                if (current_scope                     == file_scope &&
-                               entity->declaration.storage_class == STORAGE_CLASS_NONE &&
-                               !entity->declaration.implicit) {
+                   entity->declaration.storage_class == STORAGE_CLASS_NONE &&
+                   !entity->declaration.implicit) {
 warn_missing_declaration:
-                       warningf(WARN_MISSING_DECLARATIONS, pos, "no previous declaration for '%#N'", entity);
+                       if (is_type_valid(skip_typeref(entity->declaration.type)))
+                               warningf(WARN_MISSING_DECLARATIONS, pos, "no previous declaration for '%#N'", entity);
                }
        }
 
@@ -5391,6 +5386,7 @@ static expression_t *create_select(const position_t *pos, expression_t *addr,
        check_deprecated(pos, entry);
 
        expression_t *select          = allocate_expression_zero(EXPR_SELECT);
+       select->base.pos              = *pos;
        select->select.compound       = addr;
        select->select.compound_entry = entry;
 
@@ -5441,7 +5437,6 @@ static expression_t *find_create_select(const position_t *pos,
                                continue;
 
                        expression_t *sub_addr = create_select(pos, addr, qualifiers, iter);
-                       sub_addr->base.pos      = *pos;
                        sub_addr->base.implicit = true;
                        return find_create_select(pos, sub_addr, qualifiers, sub_compound,
                                                  symbol);
@@ -5686,18 +5681,32 @@ static void check_integer_suffix(expression_t *const expr, char const *const suf
 {
        unsigned     spec = SPECIFIER_NONE;
        char const  *c    = suffix;
-       for (;;) {
+       while (*c != '\0') {
                specifiers_t add;
-               if (*c == 'L' || *c == 'l') {
+               switch (*c) {
+               case 'L':
+               case 'l':
                        add = SPECIFIER_LONG;
                        if (*c == c[1]) {
                                add |= SPECIFIER_LONG_LONG;
                                ++c;
                        }
-               } else if (*c == 'U' || *c == 'u') {
+                       break;
+               case 'u':
+               case 'U':
                        add = SPECIFIER_UNSIGNED;
-               } else {
                        break;
+               case 'i':
+               case 'I':
+               case 'j':
+               case 'J':
+                       if (!GNU_MODE)
+                               goto error;
+                       add = SPECIFIER_COMPLEX;
+                       break;
+
+               default:
+                       goto error;
                }
                ++c;
                if (spec & add)
@@ -5707,7 +5716,7 @@ static void check_integer_suffix(expression_t *const expr, char const *const suf
 
        if (*c == '\0') {
                type_t *type;
-               switch (spec) {
+               switch (spec & ~SPECIFIER_COMPLEX) {
                case SPECIFIER_NONE:                                            type = type_int;                break;
                case                      SPECIFIER_LONG:                       type = type_long;               break;
                case                      SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_long_long;          break;
@@ -5719,6 +5728,10 @@ static void check_integer_suffix(expression_t *const expr, char const *const suf
                if (spec != SPECIFIER_NONE && spec != SPECIFIER_LONG) {
                        warn_traditional_suffix(suffix);
                }
+               if (spec & SPECIFIER_COMPLEX) {
+                       assert(type->kind == TYPE_ATOMIC);
+                       type = make_complex_type(type->atomic.akind, TYPE_QUALIFIER_NONE);
+               }
                expr->base.type = type;
                /* Integer type depends on the size of the number and the size
                 * representable by the types. The backend/codegeneration has to
@@ -5733,16 +5746,32 @@ error:
 static void check_floatingpoint_suffix(expression_t *const expr, char const *const suffix)
 {
        type_t     *type;
-       char const *c    = suffix;
+       char const *c          = suffix;
+       bool        is_complex = false;
+next:
        switch (*c) {
        case 'F':
        case 'f': type = type_float;       ++c; break;
        case 'L':
        case 'l': type = type_long_double; ++c; break;
+       case 'i':
+       case 'I':
+       case 'j':
+       case 'J':
+               if (!GNU_MODE)
+                       break;
+               is_complex = true;
+               ++c;
+               goto next;
        default:  type = type_double;           break;
        }
 
        if (*c == '\0') {
+               if (is_complex) {
+                       assert(type->kind == TYPE_ATOMIC);
+                       type = make_complex_type(type->atomic.akind, TYPE_QUALIFIER_NONE);
+               }
+
                expr->base.type = type;
                if (suffix[0] != '\0') {
                        warn_traditional_suffix(suffix);
@@ -6147,7 +6176,8 @@ static bool semantic_cast(expression_t *cast)
        type_t     const *src_type        = skip_typeref(orig_type_right);
        position_t const *pos             = &cast->base.pos;
 
-       /* §6.5.4 A (void) cast is explicitly permitted, more for documentation than for utility. */
+       /* §6.5.4 A (void) cast is explicitly permitted, more for documentation
+        * than for utility. */
        if (is_type_void(dst_type))
                return true;
 
@@ -6182,6 +6212,34 @@ static bool semantic_cast(expression_t *cast)
        return true;
 }
 
+static void semantic_complex_extract(unary_expression_t *extract)
+{
+       type_t *orig_value_type = extract->value->base.type;
+       type_t *value_type      = skip_typeref(orig_value_type);
+       if (!is_type_valid(value_type)) {
+               extract->base.type = type_error_type;
+               return;
+       }
+
+       type_t *type = value_type;
+       if (!is_type_complex(type)) {
+               if (!is_type_arithmetic(type)) {
+                       errorf(&extract->base.pos,
+                                  "%s requires an argument with complex or arithmetic type, got '%T'",
+                                  extract->base.kind == EXPR_UNARY_IMAG ? "__imag__" : "__real__",
+                                  orig_value_type);
+                       extract->base.type = type_error_type;
+                       return;
+               }
+               atomic_type_kind_t const akind = get_arithmetic_akind(type);
+               type = make_complex_type(akind, TYPE_QUALIFIER_NONE);
+               extract->value = create_implicit_cast(extract->value, type);
+       }
+       assert(type->kind == TYPE_COMPLEX);
+       type = make_atomic_type(type->atomic.akind, TYPE_QUALIFIER_NONE);
+       extract->base.type = type;
+}
+
 static expression_t *parse_compound_literal(position_t const *const pos,
                                             type_t *type)
 {
@@ -6230,13 +6288,23 @@ static expression_t *parse_cast(void)
        cast->base.type   = type;
        cast->unary.value = value;
 
-       if (! semantic_cast(cast)) {
-               /* TODO: record the error in the AST. else it is impossible to detect it */
+       if (!semantic_cast(cast)) {
+               cast->base.type = type_error_type;
        }
 
        return cast;
 }
 
+static expression_t *parse_complex_extract_expression(expression_kind_t const kind)
+{
+       expression_t *extract = allocate_expression_zero(kind);
+       next_token();
+
+       extract->unary.value = parse_subexpression(PREC_CAST);
+       semantic_complex_extract(&extract->unary);
+       return extract;
+}
+
 /**
  * Parse a statement expression.
  */
@@ -6341,9 +6409,6 @@ static designator_t *parse_designator(void)
                        designator->array_index  = parse_expression();
                        rem_anchor_token(']');
                        expect(']');
-                       if (designator->array_index == NULL) {
-                               return NULL;
-                       }
 
                        last_designator->next = designator;
                        last_designator       = designator;
@@ -6510,7 +6575,7 @@ static expression_t *parse_builtin_constant(void)
 
        add_anchor_token(')');
        expect('(');
-       expression->builtin_constant.value = parse_assignment_expression();
+       expression->builtin_constant.value = parse_expression();
        rem_anchor_token(')');
        expect(')');
        expression->base.type = type_int;
@@ -6580,7 +6645,7 @@ static expression_t *parse_compare_builtin(void)
                                &expression->base.pos, orig_type_left, orig_type_right);
                }
        } else {
-               semantic_comparison(&expression->binary);
+               semantic_comparison(&expression->binary, true);
        }
 
        return expression;
@@ -6597,7 +6662,7 @@ static expression_t *parse_assume(void)
 
        add_anchor_token(')');
        expect('(');
-       expression->unary.value = parse_assignment_expression();
+       expression->unary.value = parse_expression();
        rem_anchor_token(')');
        expect(')');
 
@@ -6723,6 +6788,8 @@ static expression_t *parse_primary_expression(void)
 
        case '(':                            return parse_parenthesized_expression();
        case T___noop:                       return parse_noop_expression();
+       case T___imag__:                     return parse_complex_extract_expression(EXPR_UNARY_IMAG);
+       case T___real__:                     return parse_complex_extract_expression(EXPR_UNARY_REAL);
 
        /* Gracefully handle type names while parsing expressions. */
        case T_COLONCOLON:
@@ -7511,17 +7578,18 @@ static bool is_lvalue(const expression_t *expression)
 
 static void semantic_incdec(unary_expression_t *expression)
 {
-       type_t *const orig_type = expression->value->base.type;
-       type_t *const type      = skip_typeref(orig_type);
+       type_t *orig_type = expression->value->base.type;
+       type_t *type      = skip_typeref(orig_type);
        if (is_type_pointer(type)) {
                if (!check_pointer_arithmetic(&expression->base.pos, type, orig_type)) {
                        return;
                }
-       } else if (!is_type_real(type) && is_type_valid(type)) {
+       } else if (!is_type_real(type) &&
+                  (!GNU_MODE || !is_type_complex(type)) && is_type_valid(type)) {
                /* TODO: improve error message */
                errorf(&expression->base.pos,
                       "operation needs an arithmetic or pointer type");
-               return;
+               orig_type = type = type_error_type;
        }
        if (!is_lvalue(expression->value)) {
                /* TODO: improve error message */
@@ -7532,7 +7600,16 @@ static void semantic_incdec(unary_expression_t *expression)
 
 static void promote_unary_int_expr(unary_expression_t *const expr, type_t *const type)
 {
-       type_t *const res_type = promote_integer(type);
+       atomic_type_kind_t akind = get_arithmetic_akind(type);
+       type_t *res_type;
+       if (get_akind_rank(akind) < get_akind_rank(ATOMIC_TYPE_INT)) {
+               if (type->kind == TYPE_COMPLEX)
+                       res_type = make_complex_type(ATOMIC_TYPE_INT, TYPE_QUALIFIER_NONE);
+               else
+                       res_type = type_int;
+       } else {
+               res_type = type;
+       }
        expr->base.type = res_type;
        expr->value     = create_implicit_cast(expr->value, res_type);
 }
@@ -7572,14 +7649,18 @@ static void semantic_complement(unary_expression_t *expression)
 {
        type_t *const orig_type = expression->value->base.type;
        type_t *const type      = skip_typeref(orig_type);
-       if (!is_type_integer(type)) {
+       if (!is_type_integer(type) && (!GNU_MODE || !is_type_complex(type))) {
                if (is_type_valid(type)) {
                        errorf(&expression->base.pos, "operand of ~ must be of integer type");
                }
                return;
        }
 
-       promote_unary_int_expr(expression, type);
+       if (is_type_integer(type)) {
+               promote_unary_int_expr(expression, type);
+       } else {
+               expression->base.type = orig_type;
+       }
 }
 
 static void semantic_dereference(unary_expression_t *expression)
@@ -7701,67 +7782,78 @@ CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(T_MINUSMINUS,
                                        EXPR_UNARY_POSTFIX_DECREMENT,
                                        semantic_incdec)
 
-static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right)
+static atomic_type_kind_t semantic_arithmetic_(atomic_type_kind_t kind_left,
+                                               atomic_type_kind_t kind_right)
 {
-       /* TODO: handle complex + imaginary types */
-
-       type_left  = get_unqualified_type(type_left);
-       type_right = get_unqualified_type(type_right);
-
        /* §6.3.1.8 Usual arithmetic conversions */
-       if (type_left == type_long_double || type_right == type_long_double) {
-               return type_long_double;
-       } else if (type_left == type_double || type_right == type_double) {
-               return type_double;
-       } else if (type_left == type_float || type_right == type_float) {
-               return type_float;
-       }
-
-       type_left  = promote_integer(type_left);
-       type_right = promote_integer(type_right);
-
-       if (type_left == type_right)
-               return type_left;
-
-       bool     const signed_left  = is_type_signed(type_left);
-       bool     const signed_right = is_type_signed(type_right);
-       unsigned const rank_left    = get_akind_rank(get_akind(type_left));
-       unsigned const rank_right   = get_akind_rank(get_akind(type_right));
-
+       if (kind_left == ATOMIC_TYPE_LONG_DOUBLE
+        || kind_right == ATOMIC_TYPE_LONG_DOUBLE) {
+               return ATOMIC_TYPE_LONG_DOUBLE;
+       } else if (kind_left == ATOMIC_TYPE_DOUBLE
+               || kind_right == ATOMIC_TYPE_DOUBLE) {
+           return ATOMIC_TYPE_DOUBLE;
+       } else if (kind_left == ATOMIC_TYPE_FLOAT
+               || kind_right == ATOMIC_TYPE_FLOAT) {
+               return ATOMIC_TYPE_FLOAT;
+       }
+
+       unsigned       rank_left  = get_akind_rank(kind_left);
+       unsigned       rank_right = get_akind_rank(kind_right);
+       unsigned const rank_int   = get_akind_rank(ATOMIC_TYPE_INT);
+       if (rank_left < rank_int) {
+               kind_left = ATOMIC_TYPE_INT;
+               rank_left = rank_int;
+       }
+       if (rank_right < rank_int) {
+               kind_right = ATOMIC_TYPE_INT;
+               rank_right = rank_int;
+       }
+       if (kind_left == kind_right)
+               return kind_left;
+
+       bool const signed_left  = is_akind_signed(kind_left);
+       bool const signed_right = is_akind_signed(kind_right);
        if (signed_left == signed_right)
-               return rank_left >= rank_right ? type_left : type_right;
+               return rank_left >= rank_right ? kind_left : kind_right;
 
        unsigned           s_rank;
        unsigned           u_rank;
-       atomic_type_kind_t s_akind;
-       atomic_type_kind_t u_akind;
-       type_t *s_type;
-       type_t *u_type;
+       atomic_type_kind_t s_kind;
+       atomic_type_kind_t u_kind;
        if (signed_left) {
-               s_type = type_left;
-               u_type = type_right;
+               s_kind = kind_left;
+               s_rank = rank_left;
+               u_kind = kind_right;
+               u_rank = rank_right;
        } else {
-               s_type = type_right;
-               u_type = type_left;
+               s_kind = kind_right;
+               s_rank = rank_right;
+               u_kind = kind_left;
+               u_rank = rank_left;
        }
-       s_akind = get_akind(s_type);
-       u_akind = get_akind(u_type);
-       s_rank  = get_akind_rank(s_akind);
-       u_rank  = get_akind_rank(u_akind);
-
        if (u_rank >= s_rank)
-               return u_type;
-
-       if (get_atomic_type_size(s_akind) > get_atomic_type_size(u_akind))
-               return s_type;
+               return u_kind;
+       if (get_atomic_type_size(s_kind) > get_atomic_type_size(u_kind))
+               return s_kind;
+
+       switch (s_kind) {
+       case ATOMIC_TYPE_INT:      return ATOMIC_TYPE_UINT;
+       case ATOMIC_TYPE_LONG:     return ATOMIC_TYPE_ULONG;
+       case ATOMIC_TYPE_LONGLONG: return ATOMIC_TYPE_ULONGLONG;
+       default: panic("invalid atomic type");
+       }
+}
 
-       switch (s_akind) {
-       case ATOMIC_TYPE_INT:      return type_unsigned_int;
-       case ATOMIC_TYPE_LONG:     return type_unsigned_long;
-       case ATOMIC_TYPE_LONGLONG: return type_unsigned_long_long;
+static type_t *semantic_arithmetic(type_t *type_left, type_t *type_right)
+{
+       atomic_type_kind_t kind_left  = get_arithmetic_akind(type_left);
+       atomic_type_kind_t kind_right = get_arithmetic_akind(type_right);
+       atomic_type_kind_t kind_res   = semantic_arithmetic_(kind_left, kind_right);
 
-       default: panic("invalid atomic type");
+       if (type_left->kind == TYPE_COMPLEX || type_right->kind == TYPE_COMPLEX) {
+               return make_complex_type(kind_res, TYPE_QUALIFIER_NONE);
        }
+       return make_atomic_type(kind_res, TYPE_QUALIFIER_NONE);
 }
 
 /**
@@ -7799,7 +7891,8 @@ static void semantic_binexpr_integer(binary_expression_t *const expression)
        type_t       *const type_left       = skip_typeref(orig_type_left);
        type_t       *const type_right      = skip_typeref(orig_type_right);
 
-       if (!is_type_integer(type_left) || !is_type_integer(type_right)) {
+       if (!is_type_integer(type_left) || !is_type_integer(type_right)
+         || is_type_complex(type_left) || is_type_complex(type_right)) {
                if (is_type_valid(type_left) && is_type_valid(type_right)) {
                        position_t const *const pos = &expression->base.pos;
                        errorf(pos, "operands of binary expression must have integer types, but are '%T' and '%T'", orig_type_left, orig_type_right);
@@ -8041,10 +8134,9 @@ static void warn_comparison(position_t const *const pos, expression_t const *con
 
 /**
  * Check the semantics of comparison expressions.
- *
- * @param expression   The expression to check.
  */
-static void semantic_comparison(binary_expression_t *expression)
+static void semantic_comparison(binary_expression_t *expression,
+                                bool is_relational)
 {
        position_t const *const pos   = &expression->base.pos;
        expression_t     *const left  = expression->left;
@@ -8076,14 +8168,17 @@ static void semantic_comparison(binary_expression_t *expression)
                        }
                }
 
-               expression->left        = create_implicit_cast(left, arithmetic_type);
-               expression->right       = create_implicit_cast(right, arithmetic_type);
-               expression->base.type   = arithmetic_type;
-               if ((expression->base.kind == EXPR_BINARY_EQUAL ||
-                    expression->base.kind == EXPR_BINARY_NOTEQUAL) &&
-                   is_type_float(arithmetic_type)) {
+               expression->left      = create_implicit_cast(left, arithmetic_type);
+               expression->right     = create_implicit_cast(right, arithmetic_type);
+               expression->base.type = arithmetic_type;
+               if (!is_relational && is_type_float(arithmetic_type)) {
                        warningf(WARN_FLOAT_EQUAL, pos, "comparing floating point with == or != is unsafe");
                }
+               /* for relational ops we need real types, not just arithmetic */
+               if (is_relational
+                   && (!is_type_real(type_left) || !is_type_real(type_right))) {
+                       type_error_incompatible("invalid operands for relational operator", pos, type_left, type_right);
+               }
        } else if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
                /* TODO check compatibility */
        } else if (is_type_pointer(type_left)) {
@@ -8096,6 +8191,16 @@ static void semantic_comparison(binary_expression_t *expression)
        expression->base.type = c_mode & _CXX ? type_bool : type_int;
 }
 
+static void semantic_relational(binary_expression_t *expression)
+{
+       semantic_comparison(expression, true);
+}
+
+static void semantic_equality(binary_expression_t *expression)
+{
+       semantic_comparison(expression, false);
+}
+
 /**
  * Checks if a compound type has constant fields.
  */
@@ -8382,6 +8487,8 @@ static bool expression_has_effect(const expression_t *const expr)
                case EXPR_UNARY_NOT:                  return false;
                case EXPR_UNARY_DEREFERENCE:          return false;
                case EXPR_UNARY_TAKE_ADDRESS:         return false;
+               case EXPR_UNARY_REAL:                 return false;
+               case EXPR_UNARY_IMAG:                 return false;
                case EXPR_UNARY_POSTFIX_INCREMENT:    return true;
                case EXPR_UNARY_POSTFIX_DECREMENT:    return true;
                case EXPR_UNARY_PREFIX_INCREMENT:     return true;
@@ -8483,12 +8590,12 @@ CREATE_BINEXPR_PARSER('+',                    EXPR_BINARY_ADD,                PR
 CREATE_BINEXPR_PARSER('-',                    EXPR_BINARY_SUB,                PREC_MULTIPLICATIVE, semantic_sub)
 CREATE_BINEXPR_PARSER(T_LESSLESS,             EXPR_BINARY_SHIFTLEFT,          PREC_ADDITIVE,       semantic_shift_op)
 CREATE_BINEXPR_PARSER(T_GREATERGREATER,       EXPR_BINARY_SHIFTRIGHT,         PREC_ADDITIVE,       semantic_shift_op)
-CREATE_BINEXPR_PARSER('<',                    EXPR_BINARY_LESS,               PREC_SHIFT,          semantic_comparison)
-CREATE_BINEXPR_PARSER('>',                    EXPR_BINARY_GREATER,            PREC_SHIFT,          semantic_comparison)
-CREATE_BINEXPR_PARSER(T_LESSEQUAL,            EXPR_BINARY_LESSEQUAL,          PREC_SHIFT,          semantic_comparison)
-CREATE_BINEXPR_PARSER(T_GREATEREQUAL,         EXPR_BINARY_GREATEREQUAL,       PREC_SHIFT,          semantic_comparison)
-CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, EXPR_BINARY_NOTEQUAL,           PREC_RELATIONAL,     semantic_comparison)
-CREATE_BINEXPR_PARSER(T_EQUALEQUAL,           EXPR_BINARY_EQUAL,              PREC_RELATIONAL,     semantic_comparison)
+CREATE_BINEXPR_PARSER('<',                    EXPR_BINARY_LESS,               PREC_SHIFT,          semantic_relational)
+CREATE_BINEXPR_PARSER('>',                    EXPR_BINARY_GREATER,            PREC_SHIFT,          semantic_relational)
+CREATE_BINEXPR_PARSER(T_LESSEQUAL,            EXPR_BINARY_LESSEQUAL,          PREC_SHIFT,          semantic_relational)
+CREATE_BINEXPR_PARSER(T_GREATEREQUAL,         EXPR_BINARY_GREATEREQUAL,       PREC_SHIFT,          semantic_relational)
+CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, EXPR_BINARY_NOTEQUAL,           PREC_RELATIONAL,     semantic_equality)
+CREATE_BINEXPR_PARSER(T_EQUALEQUAL,           EXPR_BINARY_EQUAL,              PREC_RELATIONAL,     semantic_equality)
 CREATE_BINEXPR_PARSER('&',                    EXPR_BINARY_BITWISE_AND,        PREC_EQUALITY,       semantic_binexpr_integer)
 CREATE_BINEXPR_PARSER('^',                    EXPR_BINARY_BITWISE_XOR,        PREC_AND,            semantic_binexpr_integer)
 CREATE_BINEXPR_PARSER('|',                    EXPR_BINARY_BITWISE_OR,         PREC_XOR,            semantic_binexpr_integer)
@@ -9172,7 +9279,7 @@ static statement_t *parse_switch(void)
        type_t       *      type = skip_typeref(expr->base.type);
        if (is_type_integer(type)) {
                type = promote_integer(type);
-               if (get_akind_rank(get_akind(type)) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
+               if (get_akind_rank(get_arithmetic_akind(type)) >= get_akind_rank(ATOMIC_TYPE_LONG)) {
                        warningf(WARN_TRADITIONAL, &expr->base.pos,
                                 "'%T' switch expression not converted to '%T' in ISO C",
                                 type, type_int);