/*
* 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>
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 \
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.
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.
*
*/
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;
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;
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;
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:
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 */
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");
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) {
}
} 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);
}
}
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;
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);
{
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)
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;
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
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);
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;
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)
{
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.
*/
designator->array_index = parse_expression();
rem_anchor_token(']');
expect(']');
- if (designator->array_index == NULL) {
- return NULL;
- }
last_designator->next = designator;
last_designator = designator;
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;
&expression->base.pos, orig_type_left, orig_type_right);
}
} else {
- semantic_comparison(&expression->binary);
+ semantic_comparison(&expression->binary, true);
}
return expression;
add_anchor_token(')');
expect('(');
- expression->unary.value = parse_assignment_expression();
+ expression->unary.value = parse_expression();
rem_anchor_token(')');
expect(')');
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:
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 */
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);
}
{
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)
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);
}
/**
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);
/**
* 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;
}
}
- 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)) {
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.
*/
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;
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)
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);