parser: Remove the unused attribute alignment from struct declaration_specifiers_t.
[cparser] / parser.c
index 57f8322..b95b756 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>
 
 #include <stdbool.h>
 
 #include "adt/strutil.h"
+#include "adt/util.h"
 #include "parser.h"
 #include "diagnostic.h"
 #include "format_check.h"
 #include "preprocessor.h"
 #include "symbol_t.h"
+#include "symbol_table.h"
 #include "token_t.h"
 #include "types.h"
 #include "type_t.h"
 #include "type_hash.h"
 #include "ast_t.h"
-#include "entity_t.h"
 #include "attribute_t.h"
 #include "lang_features.h"
 #include "walk.h"
 #include "warning.h"
 #include "printer.h"
 #include "ast2firm.h"
-#include "adt/bitfiddle.h"
 #include "adt/error.h"
 #include "adt/array.h"
 
@@ -59,7 +44,6 @@ typedef struct declaration_specifiers_t  declaration_specifiers_t;
 struct declaration_specifiers_t {
        position_t      pos;
        storage_class_t storage_class;
-       unsigned char   alignment;         /**< Alignment, 0 if not set. */
        bool            is_inline    : 1;
        bool            thread_local : 1;
        attribute_t    *attributes;        /**< list of attributes */
@@ -173,7 +157,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 +258,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 +830,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 +838,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;
@@ -874,18 +855,17 @@ static bool is_null_pointer_constant(const expression_t *expression)
        /* skip void* cast */
        if (expression->kind == EXPR_UNARY_CAST) {
                type_t *const type = skip_typeref(expression->base.type);
-               if (types_compatible(type, type_void_ptr))
+               if (type == type_void_ptr)
                        expression = expression->unary.value;
        }
 
-       type_t *const type = skip_typeref(expression->base.type);
-       if (!is_type_integer(type))
-               return false;
        switch (is_constant_expression(expression)) {
-               case EXPR_CLASS_ERROR:    return true;
-               case EXPR_CLASS_CONSTANT: return !fold_constant_to_bool(expression);
-               default:                  return false;
+               case EXPR_CLASS_VARIABLE:         return false;
+               case EXPR_CLASS_ERROR:            return true;
+               case EXPR_CLASS_CONSTANT:         return false;
+               case EXPR_CLASS_INTEGER_CONSTANT: return !fold_constant_to_bool(expression);
        }
+       panic("invalid expression classification");
 }
 
 /**
@@ -1447,6 +1427,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 +1518,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;
@@ -1848,7 +1836,7 @@ static bool walk_designator(type_path_t *path, const designator_t *designator,
                        }
                } else {
                        expression_t *array_index = designator->array_index;
-                       if (is_constant_expression(array_index) != EXPR_CLASS_CONSTANT)
+                       if (is_constant_expression(array_index) < EXPR_CLASS_CONSTANT)
                                return true;
 
                        if (!is_type_array(type)) {
@@ -2861,11 +2849,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 +2977,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 +2999,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");
@@ -3562,7 +3556,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
 
                        if (size_expression != NULL) {
                                switch (is_constant_expression(size_expression)) {
-                               case EXPR_CLASS_CONSTANT: {
+                               case EXPR_CLASS_INTEGER_CONSTANT: {
                                        long const size = fold_constant_to_int(size_expression);
                                        array_type->array.size          = size;
                                        array_type->array.size_constant = true;
@@ -3578,6 +3572,7 @@ static type_t *construct_declarator_type(construct_type_t *construct_list,
                                        break;
                                }
 
+                               case EXPR_CLASS_CONSTANT:
                                case EXPR_CLASS_VARIABLE:
                                        array_type->array.is_vla = true;
                                        break;
@@ -4075,9 +4070,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 +4123,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);
                }
        }
 
@@ -4150,13 +4144,13 @@ static void parser_error_multiple_definition(entity_t *entity,
        errorf(pos, "redefinition of '%N' (declared %P)", entity, &entity->base.pos);
 }
 
-static bool is_declaration_specifier(const token_t *token)
+static bool is_declaration_specifier(token_t const *const tk)
 {
-       switch (token->kind) {
+       switch (tk->kind) {
                DECLARATION_START
                        return true;
                case T_IDENTIFIER:
-                       return is_typedef_symbol(token->base.symbol);
+                       return is_typedef_symbol(tk->base.symbol);
 
                default:
                        return false;
@@ -4592,8 +4586,8 @@ static void check_declarations(void)
 static int determine_truth(expression_t const* const cond)
 {
        return
-               is_constant_expression(cond) != EXPR_CLASS_CONSTANT ? 0 :
-               fold_constant_to_bool(cond)                         ? 1 :
+               is_constant_expression(cond) < EXPR_CLASS_CONSTANT ? 0 :
+               fold_constant_to_bool(cond)                        ? 1 :
                -1;
 }
 
@@ -4801,7 +4795,7 @@ static void check_reachable(statement_t *const stmt)
                        if (!expression_returns(expr))
                                return;
 
-                       if (is_constant_expression(expr) == EXPR_CLASS_CONSTANT) {
+                       if (is_constant_expression(expr) >= EXPR_CLASS_CONSTANT) {
                                ir_tarval              *const val      = fold_constant_to_tarval(expr);
                                case_label_statement_t *      defaults = NULL;
                                for (case_label_statement_t *i = switchs->first_case; i != NULL; i = i->next) {
@@ -5218,42 +5212,42 @@ static void parse_external_declaration(void)
                return;
        }
 
-       assert(is_declaration(ndeclaration));
-       type_t *const orig_type = ndeclaration->declaration.type;
-       type_t *      type      = skip_typeref(orig_type);
+       {
+               assert(is_declaration(ndeclaration));
+               type_t *const orig_type = ndeclaration->declaration.type;
+               type_t *const type      = skip_typeref(orig_type);
 
-       if (!is_type_function(type)) {
-               if (is_type_valid(type)) {
-                       errorf(HERE, "declarator '%#N' has a body but is not a function type", ndeclaration);
+               if (!is_type_function(type)) {
+                       if (is_type_valid(type)) {
+                               errorf(HERE, "declarator '%#N' has a body but is not a function type", ndeclaration);
+                       }
+                       eat_block();
+                       return;
                }
-               eat_block();
-               return;
-       }
-
-       position_t const *const pos = &ndeclaration->base.pos;
-       if (is_typeref(orig_type)) {
-               /* §6.9.1:2 */
-               errorf(pos, "type of function definition '%#N' is a typedef", ndeclaration);
-       }
 
-       if (is_type_compound(skip_typeref(type->function.return_type))) {
-               warningf(WARN_AGGREGATE_RETURN, pos, "'%N' returns an aggregate", ndeclaration);
-       }
-       if (type->function.unspecified_parameters) {
-               warningf(WARN_OLD_STYLE_DEFINITION, pos, "old-style definition of '%N'", ndeclaration);
-       } else {
-               warningf(WARN_TRADITIONAL, pos, "traditional C rejects ISO C style definition of '%N'", ndeclaration);
-       }
+               position_t const *const pos = &ndeclaration->base.pos;
+               if (is_typeref(orig_type)) {
+                       /* §6.9.1:2 */
+                       errorf(pos, "type of function definition '%#N' is a typedef", ndeclaration);
+               }
 
-       /* §6.7.5.3:14 a function definition with () means no
-        * parameters (and not unspecified parameters) */
-       if (type->function.unspecified_parameters &&
-                       type->function.parameters == NULL) {
-               type_t *copy                          = duplicate_type(type);
-               copy->function.unspecified_parameters = false;
-               type                                  = identify_new_type(copy);
+               if (is_type_compound(skip_typeref(type->function.return_type))) {
+                       warningf(WARN_AGGREGATE_RETURN, pos, "'%N' returns an aggregate", ndeclaration);
+               }
+               if (type->function.unspecified_parameters) {
+                       warningf(WARN_OLD_STYLE_DEFINITION, pos, "old-style definition of '%N'", ndeclaration);
+               } else {
+                       warningf(WARN_TRADITIONAL, pos, "traditional C rejects ISO C style definition of '%N'", ndeclaration);
+               }
 
-               ndeclaration->declaration.type = type;
+               /* §6.7.5.3:14 a function definition with () means no
+                * parameters (and not unspecified parameters) */
+               if (type->function.unspecified_parameters &&
+                               type->function.parameters == NULL) {
+                       type_t *copy                          = duplicate_type(type);
+                       copy->function.unspecified_parameters = false;
+                       ndeclaration->declaration.type = identify_new_type(copy);
+               }
        }
 
        entity_t *const entity = record_entity(ndeclaration, true);
@@ -5312,8 +5306,7 @@ static void parse_external_declaration(void)
                                walk_statements(body, check_unreachable, NULL);
                        if (noreturn_candidate &&
                            !(function->base.modifiers & DM_NORETURN)) {
-                               position_t const *const pos = &body->base.pos;
-                               warningf(WARN_MISSING_NORETURN, pos, "function '%#N' is candidate for attribute 'noreturn'", entity);
+                               warningf(WARN_MISSING_NORETURN, &body->base.pos, "function '%#N' is candidate for attribute 'noreturn'", entity);
                        }
                }
 
@@ -5391,6 +5384,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 +5435,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);
@@ -5469,7 +5462,7 @@ static void parse_bitfield_member(entity_t *entity)
                           type);
        }
 
-       if (is_constant_expression(size) != EXPR_CLASS_CONSTANT) {
+       if (is_constant_expression(size) < EXPR_CLASS_CONSTANT) {
                /* error already reported by parse_constant_expression */
                size_long = get_type_size(type) * 8;
        } else {
@@ -5504,73 +5497,48 @@ static void parse_compound_declarators(compound_t *compound,
        add_anchor_token(';');
        add_anchor_token(',');
        do {
-               entity_t *entity;
-
-               if (token.kind == ':') {
-                       /* anonymous bitfield */
-                       type_t *type = specifiers->type;
-                       entity_t *const entity = allocate_entity_zero(ENTITY_COMPOUND_MEMBER, NAMESPACE_NORMAL, NULL, HERE);
-                       entity->declaration.declared_storage_class = STORAGE_CLASS_NONE;
-                       entity->declaration.storage_class          = STORAGE_CLASS_NONE;
-                       entity->declaration.type                   = type;
+               entity_t         *const entity = parse_declarator(specifiers, DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER);
+               position_t const *const pos    = &entity->base.pos;
+               if (entity->kind == ENTITY_TYPEDEF) {
+                       errorf(pos, "typedef not allowed as compound member");
+                       continue;
+               }
 
-                       parse_bitfield_member(entity);
+               assert(entity->kind == ENTITY_COMPOUND_MEMBER);
 
-                       attribute_t  *attributes = parse_attributes(NULL);
-                       attribute_t **anchor     = &attributes;
-                       while (*anchor != NULL)
-                               anchor = &(*anchor)->next;
-                       *anchor = specifiers->attributes;
-                       if (attributes != NULL) {
-                               handle_entity_attributes(attributes, entity);
+               /* make sure we don't define a symbol multiple times */
+               symbol_t *symbol = entity->base.symbol;
+               if (symbol != NULL) {
+                       entity_t *prev = find_compound_entry(compound, symbol);
+                       if (prev != NULL) {
+                               position_t const *const ppos = &prev->base.pos;
+                               errorf(pos, "multiple declarations of '%N' (declared %P)", entity, ppos);
                        }
-                       entity->declaration.attributes = attributes;
-
-                       append_entity(&compound->members, entity);
-               } else {
-                       entity = parse_declarator(specifiers,
-                                       DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER);
-                       position_t const *const pos = &entity->base.pos;
-                       if (entity->kind == ENTITY_TYPEDEF) {
-                               errorf(pos, "typedef not allowed as compound member");
-                       } else {
-                               assert(entity->kind == ENTITY_COMPOUND_MEMBER);
-
-                               /* make sure we don't define a symbol multiple times */
-                               symbol_t *symbol = entity->base.symbol;
-                               if (symbol != NULL) {
-                                       entity_t *prev = find_compound_entry(compound, symbol);
-                                       if (prev != NULL) {
-                                               position_t const *const ppos = &prev->base.pos;
-                                               errorf(pos, "multiple declarations of '%N' (declared %P)", entity, ppos);
-                                       }
-                               }
+               }
 
-                               if (token.kind == ':') {
-                                       parse_bitfield_member(entity);
+               if (token.kind == ':') {
+                       parse_bitfield_member(entity);
 
-                                       attribute_t *attributes = parse_attributes(NULL);
-                                       handle_entity_attributes(attributes, entity);
-                               } else {
-                                       type_t *orig_type = entity->declaration.type;
-                                       type_t *type      = skip_typeref(orig_type);
-                                       if (is_type_function(type)) {
-                                               errorf(pos, "'%N' must not have function type '%T'", entity, orig_type);
-                                       } else if (is_type_incomplete(type)) {
-                                               /* §6.7.2.1:16 flexible array member */
-                                               if (!is_type_array(type)       ||
-                                                               token.kind          != ';' ||
-                                                               look_ahead(1)->kind != '}') {
-                                                       errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type);
-                                               } else if (compound->members.entities == NULL) {
-                                                       errorf(pos, "flexible array member in otherwise empty struct");
-                                               }
-                                       }
+                       attribute_t *attributes = parse_attributes(NULL);
+                       handle_entity_attributes(attributes, entity);
+               } else {
+                       type_t *orig_type = entity->declaration.type;
+                       type_t *type      = skip_typeref(orig_type);
+                       if (is_type_function(type)) {
+                               errorf(pos, "'%N' must not have function type '%T'", entity, orig_type);
+                       } else if (is_type_incomplete(type)) {
+                               /* §6.7.2.1:16 flexible array member */
+                               if (!is_type_array(type)       ||
+                                               token.kind          != ';' ||
+                                               look_ahead(1)->kind != '}') {
+                                       errorf(pos, "'%N' has incomplete type '%T'", entity, orig_type);
+                               } else if (compound->members.entities == NULL) {
+                                       errorf(pos, "flexible array member in otherwise empty struct");
                                }
-
-                               append_entity(&compound->members, entity);
                        }
                }
+
+               append_entity(&compound->members, entity);
        } while (accept(','));
        rem_anchor_token(',');
        rem_anchor_token(';');
@@ -5677,78 +5645,77 @@ static expression_t *parse_boolean_literal(bool value)
        return literal;
 }
 
-static void warn_traditional_suffix(char const *const suffix)
+static void check_number_suffix(expression_t *const expr, char const *const suffix, bool const is_float)
 {
-       warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%s' suffix", suffix);
-}
-
-static void check_integer_suffix(expression_t *const expr, char const *const suffix)
-{
-       unsigned     spec = SPECIFIER_NONE;
-       char const  *c    = suffix;
-       for (;;) {
+       unsigned spec = SPECIFIER_NONE;
+       for (char const *c = suffix; *c != '\0'; ++c) {
                specifiers_t add;
-               if (*c == 'L' || *c == 'l') {
+               switch (*c) {
+               case 'F': case 'f':
+                       add = SPECIFIER_FLOAT;
+                       break;
+
+               case 'L': case 'l':
                        add = SPECIFIER_LONG;
-                       if (*c == c[1]) {
+                       if (*c == c[1] && !is_float) {
                                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':
+                       add = SPECIFIER_COMPLEX;
+                       break;
+
+               default:
+                       goto error;
                }
-               ++c;
                if (spec & add)
                        goto error;
                spec |= add;
        }
 
-       if (*c == '\0') {
-               type_t *type;
-               switch (spec) {
-               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;
-               case SPECIFIER_UNSIGNED:                                        type = type_unsigned_int;       break;
-               case SPECIFIER_UNSIGNED | SPECIFIER_LONG:                       type = type_unsigned_long;      break;
-               case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_unsigned_long_long; break;
-               default: panic("inconsistent suffix");
-               }
-               if (spec != SPECIFIER_NONE && spec != SPECIFIER_LONG) {
-                       warn_traditional_suffix(suffix);
-               }
-               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
-                * determine that. */
-               determine_literal_type(&expr->literal);
-       } else {
+       if (!(spec & SPECIFIER_FLOAT) && is_float)
+               spec |= SPECIFIER_DOUBLE;
+
+       if (!(spec & (SPECIFIER_FLOAT | SPECIFIER_DOUBLE)) == is_float)
+               goto error;
+
+       type_t *type;
+       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;
+       case SPECIFIER_UNSIGNED:                                        type = type_unsigned_int;       break;
+       case SPECIFIER_UNSIGNED | SPECIFIER_LONG:                       type = type_unsigned_long;      break;
+       case SPECIFIER_UNSIGNED | SPECIFIER_LONG | SPECIFIER_LONG_LONG: type = type_unsigned_long_long; break;
+       case SPECIFIER_FLOAT:                                           type = type_float;              break;
+       case SPECIFIER_DOUBLE:                                          type = type_double;             break;
+       case SPECIFIER_DOUBLE   | SPECIFIER_LONG:                       type = type_long_double;        break;
+
+       default:
 error:
-               errorf(HERE, "invalid suffix '%s' on integer constant", suffix);
+               errorf(HERE, "invalid suffix '%s' on %s constant", suffix, is_float ? "floatingpoint" : "integer");
+               return;
        }
-}
 
-static void check_floatingpoint_suffix(expression_t *const expr, char const *const suffix)
-{
-       type_t     *type;
-       char const *c    = suffix;
-       switch (*c) {
-       case 'F':
-       case 'f': type = type_float;       ++c; break;
-       case 'L':
-       case 'l': type = type_long_double; ++c; break;
-       default:  type = type_double;           break;
-       }
+       if (spec != SPECIFIER_NONE && spec != SPECIFIER_LONG && spec != SPECIFIER_DOUBLE)
+               warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%s' suffix", suffix);
 
-       if (*c == '\0') {
-               expr->base.type = type;
-               if (suffix[0] != '\0') {
-                       warn_traditional_suffix(suffix);
-               }
-       } else {
-               errorf(HERE, "invalid suffix '%s' on floatingpoint constant", suffix);
+       if (spec & SPECIFIER_COMPLEX)
+               type = make_complex_type(get_arithmetic_akind(type), TYPE_QUALIFIER_NONE);
+
+       expr->base.type = type;
+       if (!is_float) {
+               /* Integer type depends on the size of the number and the size
+                * representable by the types. The backend/codegeneration has to
+                * determine that. */
+               determine_literal_type(&expr->literal);
        }
 }
 
@@ -5865,11 +5832,7 @@ done:;
                        errorf(HERE, "invalid digit in %K", &token);
                } else {
                        expr->literal.suffix = i;
-                       if (is_float) {
-                               check_floatingpoint_suffix(expr, i);
-                       } else {
-                               check_integer_suffix(expr, i);
-                       }
+                       check_number_suffix(expr, i, is_float);
                }
        }
 
@@ -6147,7 +6110,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 +6146,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)
 {
@@ -6237,6 +6229,16 @@ static expression_t *parse_cast(void)
        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 +6343,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 +6509,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 +6579,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 +6596,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 +6722,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 +7512,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 +7534,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 +7583,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 +7716,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 +7825,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);
@@ -7821,7 +7848,7 @@ static void warn_div_by_zero(binary_expression_t const *const expression)
        expression_t const *const right = expression->right;
        /* The type of the right operand can be different for /= */
        if (is_type_integer(skip_typeref(right->base.type))      &&
-           is_constant_expression(right) == EXPR_CLASS_CONSTANT &&
+           is_constant_expression(right) >= EXPR_CLASS_CONSTANT &&
            !fold_constant_to_bool(right)) {
                position_t const *const pos = &expression->base.pos;
                warningf(WARN_DIV_BY_ZERO, pos, "division by zero");
@@ -7881,7 +7908,7 @@ static bool semantic_shift(binary_expression_t *expression)
 
        type_left = promote_integer(type_left);
 
-       if (is_constant_expression(right) == EXPR_CLASS_CONSTANT) {
+       if (is_constant_expression(right) >= EXPR_CLASS_CONSTANT) {
                position_t const *const pos   = &right->base.pos;
                long              const count = fold_constant_to_int(right);
                if (count < 0) {
@@ -8007,10 +8034,12 @@ static void warn_string_literal_address(expression_t const* expr)
 static bool maybe_negative(expression_t const *const expr)
 {
        switch (is_constant_expression(expr)) {
-               case EXPR_CLASS_ERROR:    return false;
-               case EXPR_CLASS_CONSTANT: return constant_is_negative(expr);
-               default:                  return true;
+               case EXPR_CLASS_VARIABLE:         return true;
+               case EXPR_CLASS_ERROR:            return false;
+               case EXPR_CLASS_CONSTANT:
+               case EXPR_CLASS_INTEGER_CONSTANT: return constant_is_negative(expr);
        }
+       panic("invalid expression classification");
 }
 
 static void warn_comparison(position_t const *const pos, expression_t const *const expr, expression_t const *const other)
@@ -8041,10 +8070,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 +8104,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 +8127,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 +8423,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 +8526,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)
@@ -8880,7 +8923,7 @@ static statement_t *parse_case_statement(void)
 
        statement->case_label.expression = expression;
        expression_classification_t const expr_class = is_constant_expression(expression);
-       if (expr_class != EXPR_CLASS_CONSTANT) {
+       if (expr_class < EXPR_CLASS_CONSTANT) {
                if (expr_class != EXPR_CLASS_ERROR) {
                        errorf(pos, "case label does not reduce to an integer constant");
                }
@@ -8904,7 +8947,7 @@ static statement_t *parse_case_statement(void)
                        end_range = create_implicit_cast(end_range, type);
                        statement->case_label.end_range = end_range;
                        expression_classification_t const end_class = is_constant_expression(end_range);
-                       if (end_class != EXPR_CLASS_CONSTANT) {
+                       if (end_class < EXPR_CLASS_CONSTANT) {
                                if (end_class != EXPR_CLASS_ERROR) {
                                        errorf(pos, "case range does not reduce to an integer constant");
                                }
@@ -9172,7 +9215,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);