/*
* 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"
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 */
/* 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");
}
/**
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)) {
type_t *first_type = first->type;
first_type = skip_typeref(first_type);
if (is_type_array(first_type)) {
- size_t index = first->v.index;
- if (index > path->max_index)
- path->max_index = index;
+ path->max_index = MAX(path->max_index, first->v.index);
}
/* append to initializers 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;
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) {
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(';');
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(';');
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;
- while (*c != '\0') {
+ unsigned spec = SPECIFIER_NONE;
+ for (char const *c = suffix; *c != '\0'; ++c) {
specifiers_t add;
switch (*c) {
- case 'L':
- case 'l':
+ 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;
}
break;
- case 'u':
- case 'U':
+
+ case 'U': case 'u':
add = SPECIFIER_UNSIGNED;
break;
- case 'i':
- case 'I':
- case 'j':
- case 'J':
- if (!GNU_MODE)
- goto error;
+
+ 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 & ~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;
- default: panic("inconsistent suffix");
- }
- 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
- * 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);
- }
-}
-
-static void check_floatingpoint_suffix(expression_t *const expr, char const *const suffix)
-{
- type_t *type;
- 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;
+ errorf(HERE, "invalid suffix '%s' on %s constant", suffix, is_float ? "floatingpoint" : "integer");
+ return;
}
- if (*c == '\0') {
- if (is_complex) {
- assert(type->kind == TYPE_ATOMIC);
- type = make_complex_type(type->atomic.akind, TYPE_QUALIFIER_NONE);
- }
+ if (spec != SPECIFIER_NONE && spec != SPECIFIER_LONG && spec != SPECIFIER_DOUBLE)
+ warningf(WARN_TRADITIONAL, HERE, "traditional C rejects the '%s' suffix", suffix);
- 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);
}
}
return cast;
}
-static expression_t *parse_complex_extract_expression(void)
+static expression_t *parse_complex_extract_expression(expression_kind_t const kind)
{
- expression_kind_t kind;
- if (token.kind == T___imag__) {
- kind = EXPR_UNARY_IMAG;
- } else {
- assert(token.kind == T___real__);
- kind = EXPR_UNARY_REAL;
- }
expression_t *extract = allocate_expression_zero(kind);
next_token();
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;
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___real__:
- case T___imag__: return parse_complex_extract_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:
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)
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");
}