/*
* 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;
/* 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");
}
/**
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;
}
} 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)) {
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");
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;
break;
}
+ case EXPR_CLASS_CONSTANT:
case EXPR_CLASS_VARIABLE:
array_type->array.is_vla = true;
break;
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);
}
}
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;
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;
}
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) {
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);
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);
}
}
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);
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 {
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 = 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;
handle_entity_attributes(attributes, entity);
}
entity->declaration.attributes = attributes;
-
- append_entity(&compound->members, entity);
} else {
- entity = parse_declarator(specifiers,
- DECL_MAY_BE_ABSTRACT | DECL_CREATE_COMPOUND_MEMBER);
+ 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);
- }
+ continue;
+ }
+
+ 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(';');
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);
}
}
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);
}
}
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);
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");
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) {
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)
/**
* 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)
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");
}
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");
}
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);