#include "type_hash.h"
#include "ast_t.h"
#include "lang_features.h"
+#include "walk_statements.h"
#include "warning.h"
#include "adt/bitfiddle.h"
#include "adt/error.h"
typedef declaration_t* (*parsed_declaration_func) (declaration_t *declaration, bool is_definition);
+/** The current token. */
static token_t token;
+/** The lookahead ring-buffer. */
static token_t lookahead_buffer[MAX_LOOKAHEAD];
+/** Position of the next token in the lookahead buffer. */
static int lookahead_bufpos;
static stack_entry_t *environment_stack = NULL;
static stack_entry_t *label_stack = NULL;
static stack_entry_t *local_label_stack = NULL;
-static scope_t *global_scope = NULL;
+/** The global file scope. */
+static scope_t *file_scope = NULL;
+/** The current scope. */
static scope_t *scope = NULL;
static declaration_t *last_declaration = NULL;
+/** Point to the current function declaration if inside a function. */
static declaration_t *current_function = NULL;
static declaration_t *current_init_decl = NULL;
static switch_statement_t *current_switch = NULL;
static goto_statement_t *goto_last = NULL;
static label_statement_t *label_first = NULL;
static label_statement_t *label_last = NULL;
+/** current translation unit. */
static translation_unit_t *unit = NULL;
+/** true if we are in a type property context (evaluation only for type. */
+static bool in_type_prop = false;
+/** true in we are in a __extension__ context. */
+static bool in_gcc_extension = false;
static struct obstack temp_obst;
+
#define PUSH_PARENT(stmt) \
statement_t *const prev_parent = current_parent; \
- current_parent = (stmt);
+ ((void)(current_parent = (stmt)))
#define POP_PARENT ((void)(current_parent = prev_parent))
-static source_position_t null_position = { NULL, 0 };
-
/** special symbol used for anonymous entities. */
static const symbol_t *sym_anonymous = NULL;
/** The current source position. */
#define HERE (&token.source_position)
+/** true if we are in GCC mode. */
+#define GNU_MODE ((c_mode & _GNUC) || in_gcc_extension)
+
static type_t *type_valist;
static statement_t *parse_compound_statement(bool inside_expression_statement);
static statement_t *parse_statement(void);
-static expression_t *parse_sub_expression(unsigned precedence);
+static expression_t *parse_sub_expression(precedence_t);
static expression_t *parse_expression(void);
static type_t *parse_typename(void);
size_t size = get_statement_struct_size(kind);
statement_t *res = allocate_ast_zero(size);
- res->base.kind = kind;
- res->base.parent = current_parent;
+ res->base.kind = kind;
+ res->base.parent = current_parent;
+ res->base.source_position = token.source_position;
return res;
}
*/
static statement_t *create_invalid_statement(void)
{
- statement_t *statement = allocate_statement_zero(STATEMENT_INVALID);
- statement->base.source_position = token.source_position;
- return statement;
+ return allocate_statement_zero(STATEMENT_INVALID);
}
/**
*/
static statement_t *create_empty_statement(void)
{
- statement_t *statement = allocate_statement_zero(STATEMENT_EMPTY);
- statement->base.source_position = token.source_position;
- return statement;
+ return allocate_statement_zero(STATEMENT_EMPTY);
}
/**
* fields with zero.
*
* @param kind type kind to allocate
- * @param source_position the source position of the type definition
*/
-static type_t *allocate_type_zero(type_kind_t kind, const source_position_t *source_position)
+static type_t *allocate_type_zero(type_kind_t kind)
{
size_t size = get_type_struct_size(kind);
type_t *res = obstack_alloc(type_obst, size);
memset(res, 0, size);
+ res->base.kind = kind;
- res->base.kind = kind;
- res->base.source_position = *source_position;
return res;
}
*/
static void eat_until_anchor(void)
{
- if (token.type == T_EOF)
- return;
while (token_anchor_set[token.type] == 0) {
if (token.type == '(' || token.type == '{' || token.type == '[')
eat_until_matching_token(token.type);
- if (token.type == T_EOF)
- break;
next_token();
}
}
next_token();
}
-/**
- * eat all token until a ';' is reached or a stop token is found.
- */
-static void eat_statement(void)
-{
- eat_until_matching_token(';');
- if (token.type == ';')
- next_token();
-}
-
#define eat(token_type) do { assert(token.type == token_type); next_token(); } while (0)
/**
next_token(); \
} while (0)
-static void set_scope(scope_t *new_scope)
+static void scope_push(scope_t *new_scope)
{
if (scope != NULL) {
scope->last_declaration = last_declaration;
+ new_scope->depth = scope->depth + 1;
}
- scope = new_scope;
+ new_scope->parent = scope;
+ scope = new_scope;
last_declaration = new_scope->last_declaration;
}
+static void scope_pop(void)
+{
+ scope->last_declaration = last_declaration;
+ scope = scope->parent;
+ last_declaration = scope->last_declaration;
+}
+
/**
* Search a symbol in a given namespace and returns its declaration or
* NULL if this symbol was not found.
namespace_t namespc = (namespace_t) declaration->namespc;
/* replace/add declaration into declaration list of the symbol */
- declaration_t *iter = symbol->declaration;
- if (iter == NULL) {
- symbol->declaration = declaration;
- } else {
- declaration_t *iter_last = NULL;
- for( ; iter != NULL; iter_last = iter, iter = iter->symbol_next) {
- /* replace an entry? */
- if (iter->namespc == namespc) {
- if (iter_last == NULL) {
- symbol->declaration = declaration;
- } else {
- iter_last->symbol_next = declaration;
- }
- declaration->symbol_next = iter->symbol_next;
- break;
- }
- }
- if (iter == NULL) {
- assert(iter_last->symbol_next == NULL);
- iter_last->symbol_next = declaration;
+ declaration_t **anchor;
+ declaration_t *iter;
+ for (anchor = &symbol->declaration;; anchor = &iter->symbol_next) {
+ iter = *anchor;
+ if (iter == NULL)
+ break;
+
+ /* replace an entry? */
+ if (iter->namespc == namespc) {
+ declaration->symbol_next = iter->symbol_next;
+ break;
}
}
+ *anchor = declaration;
/* remember old declaration */
stack_entry_t entry;
namespace_t namespc = (namespace_t)entry->namespc;
/* replace/remove declaration */
- declaration_t *declaration = symbol->declaration;
- assert(declaration != NULL);
- if (declaration->namespc == namespc) {
- if (old_declaration == NULL) {
- symbol->declaration = declaration->symbol_next;
- } else {
- symbol->declaration = old_declaration;
- }
- } else {
- declaration_t *iter_last = declaration;
- declaration_t *iter = declaration->symbol_next;
- for( ; iter != NULL; iter_last = iter, iter = iter->symbol_next) {
- /* replace an entry? */
- if (iter->namespc == namespc) {
- assert(iter_last != NULL);
- iter_last->symbol_next = old_declaration;
- if (old_declaration != NULL) {
- old_declaration->symbol_next = iter->symbol_next;
- }
- break;
- }
- }
+ declaration_t **anchor;
+ declaration_t *iter;
+ for (anchor = &symbol->declaration;; anchor = &iter->symbol_next) {
+ iter = *anchor;
assert(iter != NULL);
+ /* replace an entry? */
+ if (iter->namespc == namespc)
+ break;
+ }
+
+ /* Not all declarations adhere scopes (e.g. jump labels), so this
+ * correction is necessary */
+ if (old_declaration != NULL) {
+ old_declaration->symbol_next = iter->symbol_next;
+ *anchor = old_declaration;
+ } else {
+ *anchor = iter->symbol_next;
}
}
return;
case ASSIGN_ERROR_POINTER_QUALIFIER_MISSING: {
- type_t *points_to_left
- = skip_typeref(type_left->pointer.points_to);
- type_t *points_to_right
- = skip_typeref(type_right->pointer.points_to);
-
- /* the left type has all qualifiers from the right type */
- unsigned missing_qualifiers
- = points_to_right->base.qualifiers & ~points_to_left->base.qualifiers;
- warningf(source_position,
- "destination type '%T' in %s from type '%T' lacks qualifiers '%Q' in pointer target type",
- orig_type_left, context, orig_type_right, missing_qualifiers);
+ if (warning.other) {
+ type_t *points_to_left = skip_typeref(type_left->pointer.points_to);
+ type_t *points_to_right = skip_typeref(type_right->pointer.points_to);
+
+ /* the left type has all qualifiers from the right type */
+ unsigned missing_qualifiers
+ = points_to_right->base.qualifiers & ~points_to_left->base.qualifiers;
+ warningf(source_position,
+ "destination type '%T' in %s from type '%T' lacks qualifiers '%Q' in pointer target type",
+ orig_type_left, context, orig_type_right, missing_qualifiers);
+ }
return;
}
case ASSIGN_WARNING_POINTER_INCOMPATIBLE:
- warningf(source_position,
- "destination type '%T' in %s is incompatible with '%E' of type '%T'",
- orig_type_left, context, right, orig_type_right);
+ if (warning.other) {
+ warningf(source_position,
+ "destination type '%T' in %s is incompatible with '%E' of type '%T'",
+ orig_type_left, context, right, orig_type_right);
+ }
return;
case ASSIGN_WARNING_POINTER_FROM_INT:
- warningf(source_position,
- "%s makes pointer '%T' from integer '%T' without a cast",
- context, orig_type_left, orig_type_right);
+ if (warning.other) {
+ warningf(source_position,
+ "%s makes pointer '%T' from integer '%T' without a cast",
+ context, orig_type_left, orig_type_right);
+ }
return;
case ASSIGN_WARNING_INT_FROM_POINTER:
- warningf(source_position,
- "%s makes integer '%T' from pointer '%T' without a cast",
- context, orig_type_left, orig_type_right);
+ if (warning.other) {
+ warningf(source_position,
+ "%s makes integer '%T' from pointer '%T' without a cast",
+ context, orig_type_left, orig_type_right);
+ }
return;
default:
static expression_t *parse_constant_expression(void)
{
- /* start parsing at precedence 7 (conditional expression) */
- expression_t *result = parse_sub_expression(7);
+ expression_t *result = parse_sub_expression(PREC_CONDITIONAL);
if (!is_constant_expression(result)) {
errorf(&result->base.source_position,
static expression_t *parse_assignment_expression(void)
{
- /* start parsing at precedence 2 (assignment expression) */
- return parse_sub_expression(2);
+ return parse_sub_expression(PREC_ASSIGNMENT);
}
static type_t *make_global_typedef(const char *name, type_t *type)
record_declaration(declaration, false);
- type_t *typedef_type = allocate_type_zero(TYPE_TYPEDEF, &builtin_source_position);
+ type_t *typedef_type = allocate_type_zero(TYPE_TYPEDEF);
typedef_type->typedeft.declaration = declaration;
return typedef_type;
} else if (strcmp_underscore("DI", symbol_str) == 0) {
attribute->u.akind = ATOMIC_TYPE_LONGLONG;
} else {
- warningf(HERE, "ignoring unknown mode '%s'", symbol_str);
+ if (warning.other)
+ warningf(HERE, "ignoring unknown mode '%s'", symbol_str);
attribute->invalid = true;
}
next_token();
}
switch(kind) {
- case GNU_AK_CONST:
case GNU_AK_VOLATILE:
case GNU_AK_NAKED:
case GNU_AK_MALLOC:
case GNU_AK_UNUSED: modifiers |= DM_UNUSED; goto no_arg;
case GNU_AK_USED: modifiers |= DM_USED; goto no_arg;
case GNU_AK_PURE: modifiers |= DM_PURE; goto no_arg;
+ case GNU_AK_CONST: modifiers |= DM_CONST; goto no_arg;
case GNU_AK_ALWAYS_INLINE: modifiers |= DM_FORCEINLINE; goto no_arg;
case GNU_AK_DLLIMPORT: modifiers |= DM_DLLIMPORT; goto no_arg;
case GNU_AK_DLLEXPORT: modifiers |= DM_DLLEXPORT; goto no_arg;
case T___thiscall:
/* TODO record modifier */
- warningf(HERE, "Ignoring declaration modifier %K", &token);
+ if (warning.other)
+ warningf(HERE, "Ignoring declaration modifier %K", &token);
break;
end_error:
}
}
+static void mark_decls_read(expression_t *expr, declaration_t *lhs_decl);
+
+static declaration_t *determine_lhs_decl(expression_t *const expr, declaration_t *lhs_decl)
+{
+ switch (expr->kind) {
+ case EXPR_REFERENCE: {
+ declaration_t *const decl = expr->reference.declaration;
+ return decl;
+ }
+
+ case EXPR_ARRAY_ACCESS: {
+ expression_t *const ref = expr->array_access.array_ref;
+ declaration_t * decl = NULL;
+ if (is_type_array(skip_typeref(revert_automatic_type_conversion(ref)))) {
+ decl = determine_lhs_decl(ref, lhs_decl);
+ lhs_decl = decl;
+ } else {
+ mark_decls_read(expr->select.compound, lhs_decl);
+ }
+ mark_decls_read(expr->array_access.index, lhs_decl);
+ return decl;
+ }
+
+ case EXPR_SELECT: {
+ if (is_type_compound(skip_typeref(expr->base.type))) {
+ return determine_lhs_decl(expr->select.compound, lhs_decl);
+ } else {
+ mark_decls_read(expr->select.compound, lhs_decl);
+ return NULL;
+ }
+ }
+
+ case EXPR_UNARY_DEREFERENCE: {
+ expression_t *const val = expr->unary.value;
+ if (val->kind == EXPR_UNARY_TAKE_ADDRESS) {
+ /* *&x is a NOP */
+ return determine_lhs_decl(val->unary.value, lhs_decl);
+ } else {
+ mark_decls_read(val, NULL);
+ return NULL;
+ }
+ }
+
+ default:
+ mark_decls_read(expr, NULL);
+ return NULL;
+ }
+}
+
+#define DECL_ANY ((declaration_t*)-1)
+
+/**
+ * Mark declarations, which are read. This is used to deted variables, which
+ * are never read.
+ * Example:
+ * x = x + 1;
+ * x is not marked as "read", because it is only read to calculate its own new
+ * value.
+ *
+ * x += y; y += x;
+ * x and y are not detected as "not read", because multiple variables are
+ * involved.
+ */
+static void mark_decls_read(expression_t *const expr, declaration_t *lhs_decl)
+{
+ switch (expr->kind) {
+ case EXPR_REFERENCE: {
+ declaration_t *const decl = expr->reference.declaration;
+ if (lhs_decl != decl && lhs_decl != DECL_ANY)
+ decl->read = true;
+ return;
+ }
+
+ case EXPR_CALL:
+ // TODO respect pure/const
+ mark_decls_read(expr->call.function, NULL);
+ for (call_argument_t *arg = expr->call.arguments; arg != NULL; arg = arg->next) {
+ mark_decls_read(arg->expression, NULL);
+ }
+ return;
+
+ case EXPR_CONDITIONAL:
+ // TODO lhs_decl should depend on whether true/false have an effect
+ mark_decls_read(expr->conditional.condition, NULL);
+ if (expr->conditional.true_expression != NULL)
+ mark_decls_read(expr->conditional.true_expression, lhs_decl);
+ mark_decls_read(expr->conditional.false_expression, lhs_decl);
+ return;
+
+ case EXPR_SELECT:
+ if (lhs_decl == DECL_ANY && !is_type_compound(skip_typeref(expr->base.type)))
+ lhs_decl = NULL;
+ mark_decls_read(expr->select.compound, lhs_decl);
+ return;
+
+ case EXPR_ARRAY_ACCESS: {
+ expression_t *const ref = expr->array_access.array_ref;
+ mark_decls_read(ref, lhs_decl);
+ lhs_decl = determine_lhs_decl(ref, lhs_decl);
+ mark_decls_read(expr->array_access.index, lhs_decl);
+ return;
+ }
+
+ case EXPR_VA_ARG:
+ mark_decls_read(expr->va_arge.ap, lhs_decl);
+ return;
+
+ case EXPR_UNARY_CAST:
+ /* Special case: Use void cast to mark a variable as "read" */
+ if (is_type_atomic(skip_typeref(expr->base.type), ATOMIC_TYPE_VOID))
+ lhs_decl = NULL;
+ goto unary;
+
+ case EXPR_UNARY_DEREFERENCE:
+ if (lhs_decl == DECL_ANY)
+ lhs_decl = NULL;
+ goto unary;
+
+ case EXPR_UNARY_NEGATE:
+ case EXPR_UNARY_PLUS:
+ case EXPR_UNARY_BITWISE_NEGATE:
+ case EXPR_UNARY_NOT:
+ case EXPR_UNARY_TAKE_ADDRESS:
+ case EXPR_UNARY_POSTFIX_INCREMENT:
+ case EXPR_UNARY_POSTFIX_DECREMENT:
+ case EXPR_UNARY_PREFIX_INCREMENT:
+ case EXPR_UNARY_PREFIX_DECREMENT:
+ case EXPR_UNARY_CAST_IMPLICIT:
+ case EXPR_UNARY_ASSUME:
+unary:
+ mark_decls_read(expr->unary.value, lhs_decl);
+ return;
+
+ case EXPR_BINARY_ADD:
+ case EXPR_BINARY_SUB:
+ case EXPR_BINARY_MUL:
+ case EXPR_BINARY_DIV:
+ case EXPR_BINARY_MOD:
+ case EXPR_BINARY_EQUAL:
+ case EXPR_BINARY_NOTEQUAL:
+ case EXPR_BINARY_LESS:
+ case EXPR_BINARY_LESSEQUAL:
+ case EXPR_BINARY_GREATER:
+ case EXPR_BINARY_GREATEREQUAL:
+ case EXPR_BINARY_BITWISE_AND:
+ case EXPR_BINARY_BITWISE_OR:
+ case EXPR_BINARY_BITWISE_XOR:
+ case EXPR_BINARY_LOGICAL_AND:
+ case EXPR_BINARY_LOGICAL_OR:
+ case EXPR_BINARY_SHIFTLEFT:
+ case EXPR_BINARY_SHIFTRIGHT:
+ case EXPR_BINARY_COMMA:
+ case EXPR_BINARY_ISGREATER:
+ case EXPR_BINARY_ISGREATEREQUAL:
+ case EXPR_BINARY_ISLESS:
+ case EXPR_BINARY_ISLESSEQUAL:
+ case EXPR_BINARY_ISLESSGREATER:
+ case EXPR_BINARY_ISUNORDERED:
+ mark_decls_read(expr->binary.left, lhs_decl);
+ mark_decls_read(expr->binary.right, lhs_decl);
+ return;
+
+ case EXPR_BINARY_ASSIGN:
+ case EXPR_BINARY_MUL_ASSIGN:
+ case EXPR_BINARY_DIV_ASSIGN:
+ case EXPR_BINARY_MOD_ASSIGN:
+ case EXPR_BINARY_ADD_ASSIGN:
+ case EXPR_BINARY_SUB_ASSIGN:
+ case EXPR_BINARY_SHIFTLEFT_ASSIGN:
+ case EXPR_BINARY_SHIFTRIGHT_ASSIGN:
+ case EXPR_BINARY_BITWISE_AND_ASSIGN:
+ case EXPR_BINARY_BITWISE_XOR_ASSIGN:
+ case EXPR_BINARY_BITWISE_OR_ASSIGN: {
+ if (lhs_decl == DECL_ANY)
+ lhs_decl = NULL;
+ lhs_decl = determine_lhs_decl(expr->binary.left, lhs_decl);
+ mark_decls_read(expr->binary.right, lhs_decl);
+ return;
+ }
+
+ case EXPR_VA_START:
+ determine_lhs_decl(expr->va_starte.ap, lhs_decl);
+ return;
+
+ case EXPR_UNKNOWN:
+ case EXPR_INVALID:
+ case EXPR_CONST:
+ case EXPR_CHARACTER_CONSTANT:
+ case EXPR_WIDE_CHARACTER_CONSTANT:
+ case EXPR_STRING_LITERAL:
+ case EXPR_WIDE_STRING_LITERAL:
+ case EXPR_COMPOUND_LITERAL: // TODO init?
+ case EXPR_SIZEOF:
+ case EXPR_CLASSIFY_TYPE:
+ case EXPR_ALIGNOF:
+ case EXPR_FUNCNAME:
+ case EXPR_BUILTIN_SYMBOL:
+ case EXPR_BUILTIN_CONSTANT_P:
+ case EXPR_BUILTIN_PREFETCH:
+ case EXPR_OFFSETOF:
+ case EXPR_STATEMENT: // TODO
+ case EXPR_LABEL_ADDRESS:
+ case EXPR_BINARY_BUILTIN_EXPECT:
+ return;
+ }
+
+ panic("unhandled expression");
+}
+
static designator_t *parse_designation(void)
{
designator_t *result = NULL;
&expression->base.source_position);
initializer_t *const result = allocate_initializer_zero(INITIALIZER_VALUE);
+#if 0
+ if (type->kind == TYPE_BITFIELD) {
+ type = type->bitfield.base_type;
+ }
+#endif
result->value.value = create_implicit_cast(expression, type);
return result;
/* there might be extra {} hierarchies */
int braces = 0;
if (token.type == '{') {
- warningf(HERE, "extra curly braces around scalar initializer");
+ if (warning.other)
+ warningf(HERE, "extra curly braces around scalar initializer");
do {
++braces;
next_token();
}
expression_t *expression = parse_assignment_expression();
+ mark_decls_read(expression, NULL);
if (must_be_constant && !is_initializer_constant(expression)) {
errorf(&expression->base.source_position,
"Initialisation expression '%E' is not constant\n",
next_token();
}
if (token.type != '}') {
- if (!additional_warning_displayed) {
+ if (!additional_warning_displayed && warning.other) {
warningf(HERE, "additional elements in scalar initializer");
additional_warning_displayed = true;
}
"'.%Y' designator used for non-compound type '%T'",
symbol, orig_type);
}
- goto failed;
- }
- declaration_t *declaration = type->compound.declaration;
- declaration_t *iter = declaration->scope.declarations;
- for( ; iter != NULL; iter = iter->next) {
- if (iter->symbol == symbol) {
- break;
+ top->type = type_error_type;
+ top->v.compound_entry = NULL;
+ orig_type = type_error_type;
+ } else {
+ declaration_t *declaration = type->compound.declaration;
+ declaration_t *iter = declaration->scope.declarations;
+ for( ; iter != NULL; iter = iter->next) {
+ if (iter->symbol == symbol) {
+ break;
+ }
}
- }
- if (iter == NULL) {
- errorf(&designator->source_position,
- "'%T' has no member named '%Y'", orig_type, symbol);
- goto failed;
- }
- if (used_in_offsetof) {
- type_t *real_type = skip_typeref(iter->type);
- if (real_type->kind == TYPE_BITFIELD) {
+ if (iter == NULL) {
errorf(&designator->source_position,
- "offsetof designator '%Y' may not specify bitfield",
- symbol);
+ "'%T' has no member named '%Y'", orig_type, symbol);
goto failed;
}
- }
+ if (used_in_offsetof) {
+ type_t *real_type = skip_typeref(iter->type);
+ if (real_type->kind == TYPE_BITFIELD) {
+ errorf(&designator->source_position,
+ "offsetof designator '%Y' may not specify bitfield",
+ symbol);
+ goto failed;
+ }
+ }
- top->type = orig_type;
- top->v.compound_entry = iter;
- orig_type = iter->type;
+ top->type = orig_type;
+ top->v.compound_entry = iter;
+ orig_type = iter->type;
+ }
} else {
expression_t *array_index = designator->array_index;
assert(designator->array_index != NULL);
}
goto failed;
}
- if (!is_type_valid(array_index->base.type)) {
- goto failed;
- }
long index = fold_constant(array_index);
if (!used_in_offsetof) {
if (index < 0) {
errorf(&designator->source_position,
"array index [%E] must be positive", array_index);
- goto failed;
- }
- if (type->array.size_constant == true) {
+ } else if (type->array.size_constant) {
long array_size = type->array.size;
if (index >= array_size) {
errorf(&designator->source_position,
"designator [%E] (%d) exceeds array size %d",
array_index, index, array_size);
- goto failed;
}
}
}
path->top_type = entry->type;
return;
}
- } else {
+ } else if (is_type_array(type)) {
assert(is_type_array(type));
top->v.index++;
if (!type->array.size_constant || top->v.index < type->array.size) {
return;
}
+ } else {
+ assert(!is_type_valid(type));
+ return;
}
/* we're past the last member of the current sub-aggregate, try if we
/* We are initializing an empty compound. */
} else {
type = skip_typeref(orig_type);
-
- /* we can't do usefull stuff if we didn't even parse the type. Skip the
- * initializers in this case. */
- if (!is_type_valid(type)) {
- skip_initializers();
- return create_empty_initializer();
- }
}
initializer_t **initializers = NEW_ARR_F(initializer_t*, 0);
if (type == NULL) {
/* we are already outside, ... */
- if (is_type_compound(outer_type) &&
- !outer_type->compound.declaration->init.complete) {
+ type_t *const outer_type_skip = skip_typeref(outer_type);
+ if (is_type_compound(outer_type_skip) &&
+ !outer_type_skip->compound.declaration->init.complete) {
goto error_parse_next;
}
goto error_excess;
if (token.type == ',') {
next_token();
}
- if (token.type != '}') {
+ if (token.type != '}' && warning.other) {
warningf(HERE, "excessive elements in initializer for type '%T'",
orig_type);
}
ARR_APP1(initializer_t*, initializers, sub);
} else {
error_excess:
- if (env->declaration != NULL)
- warningf(HERE, "excess elements in struct initializer for '%Y'",
- env->declaration->symbol);
- else
- warningf(HERE, "excess elements in struct initializer");
+ if (warning.other) {
+ if (env->declaration != NULL) {
+ warningf(HERE, "excess elements in struct initializer for '%Y'",
+ env->declaration->symbol);
+ } else {
+ warningf(HERE, "excess elements in struct initializer");
+ }
+ }
}
error_parse_next:
declaration->parent_scope = scope;
}
- type_t *const type = allocate_type_zero(TYPE_ENUM, &declaration->source_position);
+ type_t *const type = allocate_type_zero(TYPE_ENUM);
type->enumt.declaration = declaration;
if (token.type == '{') {
expression_t *expression = NULL;
-restart:
- switch(token.type) {
- case T___extension__:
- /* This can be a prefix to a typename or an expression. We simply eat
- * it now. */
- do {
- next_token();
- } while (token.type == T___extension__);
- goto restart;
+ bool old_type_prop = in_type_prop;
+ bool old_gcc_extension = in_gcc_extension;
+ in_type_prop = true;
+ while (token.type == T___extension__) {
+ /* This can be a prefix to a typename or an expression. */
+ next_token();
+ in_gcc_extension = true;
+ }
+ switch (token.type) {
case T_IDENTIFIER:
if (is_typedef_symbol(token.v.symbol)) {
type = parse_typename();
type = expression->base.type;
break;
}
+ in_type_prop = old_type_prop;
+ in_gcc_extension = old_gcc_extension;
rem_anchor_token(')');
expect(')');
- type_t *typeof_type = allocate_type_zero(TYPE_TYPEOF, &expression->base.source_position);
+ type_t *typeof_type = allocate_type_zero(TYPE_TYPEOF);
typeof_type->typeoft.expression = expression;
typeof_type->typeoft.typeof_type = type;
static type_t *create_builtin_type(symbol_t *const symbol,
type_t *const real_type)
{
- type_t *type = allocate_type_zero(TYPE_BUILTIN, &builtin_source_position);
+ type_t *type = allocate_type_zero(TYPE_BUILTIN);
type->builtin.symbol = symbol;
type->builtin.real_type = real_type;
declaration->storage_class != STORAGE_CLASS_TYPEDEF)
return NULL;
- type_t *type = allocate_type_zero(TYPE_TYPEDEF, &declaration->source_position);
+ type_t *type = allocate_type_zero(TYPE_TYPEDEF);
type->typedeft.declaration = declaration;
return type;
return false;
}
unsigned v = (unsigned)intvalue;
- for(unsigned i = 1; i <= 8192; i += i) {
+ for (unsigned i = 1; i <= 8192; i += i) {
if (i == v)
return true;
}
}
#define DET_MOD(name, tag) do { \
- if (*modifiers & tag) warningf(HERE, #name " used more than once"); \
+ if (*modifiers & tag && warning.other) warningf(HERE, #name " used more than once"); \
*modifiers |= tag; \
} while (0)
if (token.type != T_INTEGER)
goto end_error;
if (check_alignment_value(token.v.intvalue)) {
- if (specifiers->alignment != 0)
+ if (specifiers->alignment != 0 && warning.other)
warningf(HERE, "align used more than once");
specifiers->alignment = (unsigned char)token.v.intvalue;
}
} else if (symbol == sym_property) {
next_token();
expect('(');
- for(;;) {
+ for (;;) {
bool is_get = false;
if (token.type != T_IDENTIFIER)
goto end_error;
expect(')');
} else if (symbol == sym_deprecated) {
next_token();
- if (specifiers->deprecated != 0)
+ if (specifiers->deprecated != 0 && warning.other)
warningf(HERE, "deprecated used more than once");
specifiers->deprecated = 1;
if (token.type == '(') {
next_token();
DET_MOD(noalias, DM_NOALIAS);
} else {
- warningf(HERE, "Unknown modifier %Y ignored", token.v.symbol);
+ if (warning.other)
+ warningf(HERE, "Unknown modifier %Y ignored", token.v.symbol);
next_token();
if (token.type == '(')
skip_until(')');
decl->source_position = *HERE;
decl->declared_storage_class = storage_class;
decl->storage_class =
- storage_class != STORAGE_CLASS_NONE || scope == global_scope ?
+ storage_class != STORAGE_CLASS_NONE || scope == file_scope ?
storage_class : STORAGE_CLASS_AUTO;
decl->symbol = symbol;
decl->implicit = true;
static void parse_declaration_specifiers(declaration_specifiers_t *specifiers)
{
- type_t *type = NULL;
- type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
- type_modifiers_t modifiers = TYPE_MODIFIER_NONE;
- unsigned type_specifiers = 0;
- bool newtype = false;
- bool saw_error = false;
+ type_t *type = NULL;
+ type_qualifiers_t qualifiers = TYPE_QUALIFIER_NONE;
+ type_modifiers_t modifiers = TYPE_MODIFIER_NONE;
+ unsigned type_specifiers = 0;
+ bool newtype = false;
+ bool saw_error = false;
+ bool old_gcc_extension = in_gcc_extension;
specifiers->source_position = token.source_position;
if (specifiers->modifiers & DM_TRANSPARENT_UNION)
modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
- switch(token.type) {
+ switch (token.type) {
/* storage class */
#define MATCH_STORAGE_CLASS(token, class) \
MATCH_TYPE_QUALIFIER(T___sptr, TYPE_QUALIFIER_SPTR);
case T___extension__:
- /* TODO */
next_token();
+ in_gcc_extension = true;
break;
/* type specifiers */
break;
case T_struct: {
- type = allocate_type_zero(TYPE_COMPOUND_STRUCT, HERE);
+ type = allocate_type_zero(TYPE_COMPOUND_STRUCT);
type->compound.declaration = parse_compound_type_specifier(true);
finish_struct_type(&type->compound);
break;
}
case T_union: {
- type = allocate_type_zero(TYPE_COMPOUND_UNION, HERE);
+ type = allocate_type_zero(TYPE_COMPOUND_UNION);
type->compound.declaration = parse_compound_type_specifier(false);
if (type->compound.declaration->modifiers & DM_TRANSPARENT_UNION)
modifiers |= TYPE_MODIFIER_TRANSPARENT_UNION;
- break;
finish_union_type(&type->compound);
+ break;
}
case T_enum:
type = parse_enum_specifier();
declaration_t *const decl =
create_error_declaration(token.v.symbol, STORAGE_CLASS_TYPEDEF);
- type = allocate_type_zero(TYPE_TYPEDEF, HERE);
+ type = allocate_type_zero(TYPE_TYPEDEF);
type->typedeft.declaration = decl;
next_token();
}
finish_specifiers:
+ in_gcc_extension = old_gcc_extension;
+
if (type == NULL || (saw_error && type_specifiers != 0)) {
atomic_type_kind_t atomic_type;
default:
/* invalid specifier combination, give an error message */
if (type_specifiers == 0) {
- if (saw_error) {
- specifiers->type = type_error_type;
- return;
- }
+ if (saw_error)
+ goto end_error;
if (!strict_mode) {
if (warning.implicit_int) {
} else {
errorf(HERE, "multiple datatypes in declaration");
}
- atomic_type = ATOMIC_TYPE_INVALID;
+ goto end_error;
}
- if (type_specifiers & SPECIFIER_COMPLEX &&
- atomic_type != ATOMIC_TYPE_INVALID) {
- type = allocate_type_zero(TYPE_COMPLEX, &builtin_source_position);
+ if (type_specifiers & SPECIFIER_COMPLEX) {
+ type = allocate_type_zero(TYPE_COMPLEX);
type->complex.akind = atomic_type;
- } else if (type_specifiers & SPECIFIER_IMAGINARY &&
- atomic_type != ATOMIC_TYPE_INVALID) {
- type = allocate_type_zero(TYPE_IMAGINARY, &builtin_source_position);
+ } else if (type_specifiers & SPECIFIER_IMAGINARY) {
+ type = allocate_type_zero(TYPE_IMAGINARY);
type->imaginary.akind = atomic_type;
} else {
- type = allocate_type_zero(TYPE_ATOMIC, &builtin_source_position);
+ type = allocate_type_zero(TYPE_ATOMIC);
type->atomic.akind = atomic_type;
}
newtype = true;
}
}
-static declaration_t *parse_identifier_list(void)
+/**
+ * Parses an K&R identifier list and return a list of declarations.
+ *
+ * @param last points to the last declaration in the list
+ * @return the list of declarations
+ */
+static declaration_t *parse_identifier_list(declaration_t **last)
{
declaration_t *declarations = NULL;
declaration_t *last_declaration = NULL;
next_token();
} while (token.type == T_IDENTIFIER);
+ *last = last_declaration;
return declarations;
}
return declaration;
}
-static declaration_t *parse_parameters(function_type_t *type)
+/**
+ * Parses a function type parameter list and return a list of declarations.
+ *
+ * @param last point to the last element of the list
+ * @return the parameter list
+ */
+static declaration_t *parse_parameters(function_type_t *type, declaration_t **last)
{
declaration_t *declarations = NULL;
token_type_t la1_type = (token_type_t)look_ahead(1)->type;
if (la1_type == ',' || la1_type == ')') {
type->kr_style_parameters = true;
- declarations = parse_identifier_list();
+ declarations = parse_identifier_list(last);
goto parameters_finished;
}
}
expect(')');
restore_anchor_state(',', saved_comma_state);
+ *last = last_declaration;
return declarations;
end_error:
restore_anchor_state(',', saved_comma_state);
+ *last = NULL;
return NULL;
}
rem_anchor_token(']');
expect(']');
- return (construct_type_t*) array;
end_error:
- return NULL;
+ return (construct_type_t*) array;
}
static construct_type_t *parse_function_declarator(declaration_t *declaration)
{
type_t *type;
if (declaration != NULL) {
- type = allocate_type_zero(TYPE_FUNCTION, &declaration->source_position);
+ type = allocate_type_zero(TYPE_FUNCTION);
unsigned mask = declaration->modifiers & (DM_CDECL|DM_STDCALL|DM_FASTCALL|DM_THISCALL);
else if (declaration->modifiers & DM_THISCALL)
type->function.calling_convention = CC_THISCALL;
} else {
- type = allocate_type_zero(TYPE_FUNCTION, HERE);
+ type = allocate_type_zero(TYPE_FUNCTION);
}
- declaration_t *parameters = parse_parameters(&type->function);
+ declaration_t *last;
+ declaration_t *parameters = parse_parameters(&type->function, &last);
if (declaration != NULL) {
- declaration->scope.declarations = parameters;
+ declaration->scope.declarations = parameters;
+ declaration->scope.last_declaration = last;
}
construct_function_type_t *construct_function_type =
if (may_be_abstract)
break;
parse_error_expected("while parsing declarator", T_IDENTIFIER, '(', NULL);
- /* avoid a loop in the outermost scope, because eat_statement doesn't
- * eat '}' */
- if (token.type == '}' && current_function == NULL) {
- next_token();
- } else {
- eat_statement();
- }
+ eat_until_anchor();
return NULL;
}
function_type->function.return_type = type;
type_t *skipped_return_type = skip_typeref(type);
+ /* §6.7.5.3(1) */
if (is_type_function(skipped_return_type)) {
errorf(HERE, "function returning function is not allowed");
- type = type_error_type;
} else if (is_type_array(skipped_return_type)) {
errorf(HERE, "function returning array is not allowed");
- type = type_error_type;
} else {
- type = function_type;
+ if (skipped_return_type->base.qualifiers != 0 && warning.other) {
+ warningf(HERE,
+ "type qualifiers in return type of function type are meaningless");
+ }
}
+
+ type = function_type;
break;
}
case CONSTRUCT_POINTER: {
parsed_pointer_t *parsed_pointer = (parsed_pointer_t*) iter;
- type_t *pointer_type = allocate_type_zero(TYPE_POINTER, &null_position);
- pointer_type->pointer.points_to = type;
- pointer_type->base.qualifiers = parsed_pointer->type_qualifiers;
-
- type = pointer_type;
- break;
+ type = make_pointer_type(type, parsed_pointer->type_qualifiers);
+ continue;
}
case CONSTRUCT_ARRAY: {
parsed_array_t *parsed_array = (parsed_array_t*) iter;
- type_t *array_type = allocate_type_zero(TYPE_ARRAY, &null_position);
+ type_t *array_type = allocate_type_zero(TYPE_ARRAY);
expression_t *size_expression = parsed_array->size;
if (size_expression != NULL) {
}
type_t *skipped_type = skip_typeref(type);
- if (is_type_atomic(skipped_type, ATOMIC_TYPE_VOID)) {
- errorf(HERE, "array of void is not allowed");
- type = type_error_type;
- } else {
- type = array_type;
+ /* §6.7.5.2(1) */
+ if (is_type_incomplete(skipped_type)) {
+ errorf(HERE, "array of incomplete type '%T' is not allowed", type);
+ } else if (is_type_function(skipped_type)) {
+ errorf(HERE, "array of functions is not allowed");
}
+ type = array_type;
break;
}
}
declaration->is_inline = specifiers->is_inline;
declaration->storage_class = specifiers->declared_storage_class;
- if (declaration->storage_class == STORAGE_CLASS_NONE
- && scope != global_scope) {
+ if (declaration->storage_class == STORAGE_CLASS_NONE &&
+ scope != file_scope) {
declaration->storage_class = STORAGE_CLASS_AUTO;
}
warningf(&decl->source_position,
"'main' is normally a non-static function");
}
- if (skip_typeref(func_type->return_type) != type_int) {
+ if (!types_compatible(skip_typeref(func_type->return_type), type_int)) {
warningf(&decl->source_position,
"return type of 'main' should be 'int', but is '%T'",
func_type->return_type);
previous_declaration == NULL) {
warningf(&declaration->source_position,
"function declaration '%#T' is not a prototype",
- orig_type, declaration->symbol);
+ orig_type, symbol);
}
if (warning.main && is_type_function(type) && is_sym_main(symbol)) {
if (warning.nested_externs &&
declaration->storage_class == STORAGE_CLASS_EXTERN &&
- scope != global_scope) {
+ scope != file_scope) {
warningf(&declaration->source_position,
"nested extern declaration of '%#T'", declaration->type, symbol);
}
assert(declaration != previous_declaration);
- if (previous_declaration != NULL
- && previous_declaration->parent_scope == scope) {
+ if (previous_declaration != NULL &&
+ previous_declaration->parent_scope == ¤t_function->scope &&
+ scope->depth == previous_declaration->parent_scope->depth + 1) {
+ errorf(&declaration->source_position,
+ "declaration '%#T' redeclares the parameter '%#T' (declared %P)",
+ orig_type, symbol, previous_declaration->type, symbol,
+ &previous_declaration->source_position);
+ goto finish;
+ }
+ if (previous_declaration != NULL &&
+ previous_declaration->parent_scope == scope) {
/* can happen for K&R style declarations */
if (previous_declaration->type == NULL) {
previous_declaration->type = declaration->type;
}
} else {
if (warning.missing_declarations &&
- scope == global_scope && (
+ scope == file_scope && (
declaration->storage_class == STORAGE_CLASS_NONE ||
declaration->storage_class == STORAGE_CLASS_THREAD
)) {
"no previous declaration for '%#T'", orig_type, symbol);
}
}
-
+finish:
assert(declaration->parent_scope == NULL);
assert(scope != NULL);
static bool is_declaration_specifier(const token_t *token,
bool only_specifiers_qualifiers)
{
- switch(token->type) {
+ switch (token->type) {
TYPE_SPECIFIERS
TYPE_QUALIFIERS
return true;
}
bool must_be_constant = false;
- if (declaration->storage_class == STORAGE_CLASS_STATIC
- || declaration->storage_class == STORAGE_CLASS_THREAD_STATIC
- || declaration->parent_scope == global_scope) {
+ if (declaration->storage_class == STORAGE_CLASS_STATIC ||
+ declaration->storage_class == STORAGE_CLASS_THREAD_STATIC ||
+ declaration->parent_scope == file_scope) {
must_be_constant = true;
}
{
eat(';');
- declaration_t *const declaration = allocate_declaration_zero();
- declaration->type = specifiers->type;
- declaration->declared_storage_class = specifiers->declared_storage_class;
- declaration->source_position = specifiers->source_position;
- declaration->modifiers = specifiers->modifiers;
-
- if (declaration->declared_storage_class != STORAGE_CLASS_NONE) {
- warningf(&declaration->source_position,
- "useless storage class in empty declaration");
- }
- declaration->storage_class = STORAGE_CLASS_NONE;
+ if (warning.other) {
+ if (specifiers->declared_storage_class != STORAGE_CLASS_NONE) {
+ warningf(&specifiers->source_position,
+ "useless storage class in empty declaration");
+ }
- type_t *type = declaration->type;
- switch (type->kind) {
- case TYPE_COMPOUND_STRUCT:
- case TYPE_COMPOUND_UNION: {
- if (type->compound.declaration->symbol == NULL) {
- warningf(&declaration->source_position,
- "unnamed struct/union that defines no instances");
+ type_t *type = specifiers->type;
+ switch (type->kind) {
+ case TYPE_COMPOUND_STRUCT:
+ case TYPE_COMPOUND_UNION: {
+ if (type->compound.declaration->symbol == NULL) {
+ warningf(&specifiers->source_position,
+ "unnamed struct/union that defines no instances");
+ }
+ break;
}
- break;
- }
- case TYPE_ENUM:
- break;
+ case TYPE_ENUM:
+ break;
- default:
- warningf(&declaration->source_position, "empty declaration");
- break;
+ default:
+ warningf(&specifiers->source_position, "empty declaration");
+ break;
+ }
}
+#ifdef RECORD_EMPTY_DECLARATIONS
+ declaration_t *const declaration = allocate_declaration_zero();
+ declaration->type = specifiers->type;
+ declaration->declared_storage_class = specifiers->declared_storage_class;
+ declaration->source_position = specifiers->source_position;
+ declaration->modifiers = specifiers->modifiers;
+ declaration->storage_class = STORAGE_CLASS_NONE;
+
append_declaration(declaration);
+#endif
}
static void parse_declaration_rest(declaration_t *ndeclaration,
parsed_declaration_func finished_declaration)
{
add_anchor_token(';');
- add_anchor_token('=');
add_anchor_token(',');
while(true) {
declaration_t *declaration =
type_t *orig_type = declaration->type;
type_t *type = skip_typeref(orig_type);
- if (type->kind != TYPE_FUNCTION &&
- declaration->is_inline &&
+ if (warning.other &&
+ type->kind != TYPE_FUNCTION &&
+ declaration->is_inline &&
is_type_valid(type)) {
warningf(&declaration->source_position,
"variable '%Y' declared 'inline'\n", declaration->symbol);
break;
eat(',');
+ add_anchor_token('=');
ndeclaration = parse_declarator(specifiers, /*may_be_abstract=*/false);
+ rem_anchor_token('=');
}
expect(';');
end_error:
rem_anchor_token(';');
- rem_anchor_token('=');
rem_anchor_token(',');
}
{
declaration_specifiers_t specifiers;
memset(&specifiers, 0, sizeof(specifiers));
+
+ add_anchor_token(';');
parse_declaration_specifiers(&specifiers);
+ rem_anchor_token(';');
if (token.type == ';') {
parse_anonymous_declaration_rest(&specifiers);
if (!type->function.kr_style_parameters)
return;
+ add_anchor_token('{');
+
/* push function parameters */
- int top = environment_top();
- scope_t *last_scope = scope;
- set_scope(&declaration->scope);
+ size_t const top = environment_top();
+ scope_push(&declaration->scope);
declaration_t *parameter = declaration->scope.declarations;
for ( ; parameter != NULL; parameter = parameter->next) {
/* pop function parameters */
assert(scope == &declaration->scope);
- set_scope(last_scope);
+ scope_pop();
environment_pop_to(top);
/* update function type */
}
declaration->type = type;
+
+ rem_anchor_token('{');
}
static bool first_err = true;
label_first = label_last = NULL;
}
+static void warn_unused_decl(declaration_t *decl, declaration_t *end, char const *const what)
+{
+ for (; decl != NULL; decl = decl->next) {
+ if (decl->implicit)
+ continue;
+
+ if (!decl->used) {
+ print_in_function();
+ warningf(&decl->source_position, "%s '%Y' is unused", what, decl->symbol);
+ } else if (!decl->read) {
+ print_in_function();
+ warningf(&decl->source_position, "%s '%Y' is never read", what, decl->symbol);
+ }
+
+ if (decl == end)
+ break;
+ }
+}
+
+static void check_unused_variables(statement_t *const stmt, void *const env)
+{
+ (void)env;
+
+ switch (stmt->kind) {
+ case STATEMENT_DECLARATION: {
+ declaration_statement_t const *const decls = &stmt->declaration;
+ warn_unused_decl(decls->declarations_begin, decls->declarations_end, "variable");
+ return;
+ }
+
+ case STATEMENT_FOR:
+ warn_unused_decl(stmt->fors.scope.declarations, NULL, "variable");
+ return;
+
+ default:
+ return;
+ }
+}
+
/**
* Check declarations of current_function for unused entities.
*/
if (warning.unused_parameter) {
const scope_t *scope = ¤t_function->scope;
- if (is_sym_main(current_function->symbol)) {
- /* do not issue unused warnings for main */
- return;
- }
- const declaration_t *parameter = scope->declarations;
- for (; parameter != NULL; parameter = parameter->next) {
- if (! parameter->used) {
- print_in_function();
- warningf(¶meter->source_position,
- "unused parameter '%Y'", parameter->symbol);
- }
+ /* do not issue unused warnings for main */
+ if (!is_sym_main(current_function->symbol)) {
+ warn_unused_decl(scope->declarations, NULL, "parameter");
}
}
if (warning.unused_variable) {
+ walk_statements(current_function->init.statement, check_unused_variables, NULL);
}
}
check_reachable(next);
}
-static void check_unreachable(statement_t const* const stmt)
+static void check_unreachable(statement_t* const stmt, void *const env)
{
- if (!stmt->base.reachable &&
- stmt->kind != STATEMENT_DO_WHILE &&
- stmt->kind != STATEMENT_FOR &&
- (stmt->kind != STATEMENT_COMPOUND || stmt->compound.statements == NULL)) {
- warningf(&stmt->base.source_position, "statement is unreachable");
- }
+ (void)env;
switch (stmt->kind) {
- case STATEMENT_INVALID:
- case STATEMENT_EMPTY:
- case STATEMENT_RETURN:
- case STATEMENT_DECLARATION:
- case STATEMENT_EXPRESSION:
- case STATEMENT_CONTINUE:
- case STATEMENT_BREAK:
- case STATEMENT_GOTO:
- case STATEMENT_ASM:
- case STATEMENT_LEAVE:
- break;
-
- case STATEMENT_COMPOUND:
- if (stmt->compound.statements)
- check_unreachable(stmt->compound.statements);
- break;
-
- case STATEMENT_IF:
- check_unreachable(stmt->ifs.true_statement);
- if (stmt->ifs.false_statement != NULL)
- check_unreachable(stmt->ifs.false_statement);
- break;
-
- case STATEMENT_SWITCH:
- check_unreachable(stmt->switchs.body);
- break;
-
- case STATEMENT_LABEL:
- check_unreachable(stmt->label.statement);
- break;
-
- case STATEMENT_CASE_LABEL:
- check_unreachable(stmt->case_label.statement);
- break;
-
- case STATEMENT_WHILE:
- check_unreachable(stmt->whiles.body);
- break;
-
case STATEMENT_DO_WHILE:
- check_unreachable(stmt->do_while.body);
if (!stmt->base.reachable) {
expression_t const *const cond = stmt->do_while.condition;
if (determine_truth(cond) >= 0) {
"condition of do-while-loop is unreachable");
}
}
- break;
+ return;
case STATEMENT_FOR: {
for_statement_t const* const fors = &stmt->fors;
"step of for-statement is unreachable");
}
}
-
- check_unreachable(fors->body);
- break;
+ return;
}
- case STATEMENT_MS_TRY: {
- ms_try_statement_t const *const ms_try = &stmt->ms_try;
- check_unreachable(ms_try->try_statement);
- check_unreachable(ms_try->final_statement);
- }
- }
+ case STATEMENT_COMPOUND:
+ if (stmt->compound.statements != NULL)
+ return;
+ /* FALLTHROUGH*/
- if (stmt->base.next)
- check_unreachable(stmt->base.next);
+ default:
+ if (!stmt->base.reachable)
+ warningf(&stmt->base.source_position, "statement is unreachable");
+ return;
+ }
}
static void parse_external_declaration(void)
add_anchor_token(',');
add_anchor_token('=');
add_anchor_token(';');
+ add_anchor_token('{');
/* declarator is common to both function-definitions and declarations */
declaration_t *ndeclaration = parse_declarator(&specifiers, /*may_be_abstract=*/false);
- rem_anchor_token(',');
- rem_anchor_token('=');
+ rem_anchor_token('{');
rem_anchor_token(';');
+ rem_anchor_token('=');
+ rem_anchor_token(',');
/* must be a declaration */
switch (token.type) {
type = skip_typeref(declaration->type);
/* push function parameters and switch scope */
- int top = environment_top();
- scope_t *last_scope = scope;
- set_scope(&declaration->scope);
+ size_t const top = environment_top();
+ scope_push(&declaration->scope);
declaration_t *parameter = declaration->scope.declarations;
for( ; parameter != NULL; parameter = parameter->next) {
noreturn_candidate = true;
check_reachable(body);
if (warning.unreachable_code)
- check_unreachable(body);
+ walk_statements(body, check_unreachable, NULL);
if (warning.missing_noreturn &&
noreturn_candidate &&
!(declaration->modifiers & DM_NORETURN)) {
}
assert(scope == &declaration->scope);
- set_scope(last_scope);
+ scope_pop();
environment_pop_to(top);
}
source_position_t *source_position,
const symbol_t *symbol)
{
- type_t *type = allocate_type_zero(TYPE_BITFIELD, source_position);
+ type_t *type = allocate_type_zero(TYPE_BITFIELD);
type->bitfield.base_type = base_type;
type->bitfield.size_expression = size;
eat('{');
add_anchor_token('}');
- while (token.type != '}' && token.type != T_EOF) {
+ while (token.type != '}') {
+ if (token.type == T_EOF) {
+ errorf(HERE, "EOF while parsing struct");
+ break;
+ }
declaration_specifiers_t specifiers;
memset(&specifiers, 0, sizeof(specifiers));
parse_declaration_specifiers(&specifiers);
parse_compound_declarators(compound_declaration, &specifiers);
}
rem_anchor_token('}');
-
- if (token.type == T_EOF) {
- errorf(HERE, "EOF while parsing struct");
- }
next_token();
}
-typedef expression_t* (*parse_expression_function) (unsigned precedence);
-typedef expression_t* (*parse_expression_infix_function) (unsigned precedence,
- expression_t *left);
+typedef expression_t* (*parse_expression_function)(void);
+typedef expression_t* (*parse_expression_infix_function)(expression_t *left);
typedef struct expression_parser_function_t expression_parser_function_t;
struct expression_parser_function_t {
- unsigned precedence;
parse_expression_function parser;
unsigned infix_precedence;
parse_expression_infix_function infix_parser;
cnst->conste.v.character = token.v.string;
if (cnst->conste.v.character.size != 1) {
- if (warning.multichar && (c_mode & _GNUC)) {
- /* TODO */
+ if (warning.multichar && GNU_MODE) {
warningf(HERE, "multi-character character constant");
} else {
errorf(HERE, "more than 1 characters in character constant");
cnst->conste.v.wide_character = token.v.wide_string;
if (cnst->conste.v.wide_character.size != 1) {
- if (warning.multichar && (c_mode & _GNUC)) {
- /* TODO */
+ if (warning.multichar && GNU_MODE) {
warningf(HERE, "multi-character character constant");
} else {
errorf(HERE, "more than 1 characters in character constant");
static declaration_t *create_implicit_function(symbol_t *symbol,
const source_position_t *source_position)
{
- type_t *ntype = allocate_type_zero(TYPE_FUNCTION, source_position);
+ type_t *ntype = allocate_type_zero(TYPE_FUNCTION);
ntype->function.return_type = type_int;
ntype->function.unspecified_parameters = true;
parameter1->type = argument_type1;
parameter1->next = parameter2;
- type_t *type = allocate_type_zero(TYPE_FUNCTION, &builtin_source_position);
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
type->function.return_type = return_type;
type->function.parameters = parameter1;
memset(parameter, 0, sizeof(parameter[0]));
parameter->type = argument_type;
- type_t *type = allocate_type_zero(TYPE_FUNCTION, &builtin_source_position);
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
type->function.return_type = return_type;
type->function.parameters = parameter;
static type_t *make_function_0_type(type_t *return_type)
{
- type_t *type = allocate_type_zero(TYPE_FUNCTION, &builtin_source_position);
+ type_t *type = allocate_type_zero(TYPE_FUNCTION);
type->function.return_type = return_type;
type->function.parameters = NULL;
return make_function_1_type(type_void_ptr, type_size_t);
case T___builtin_huge_val:
return make_function_0_type(type_double);
+ case T___builtin_inf:
+ return make_function_0_type(type_double);
+ case T___builtin_inff:
+ return make_function_0_type(type_float);
+ case T___builtin_infl:
+ return make_function_0_type(type_long_double);
case T___builtin_nan:
return make_function_1_type(type_double, type_char_ptr);
case T___builtin_nanf:
return make_function_1_type(type_float, type_char_ptr);
- case T___builtin_nand:
+ case T___builtin_nanl:
return make_function_1_type(type_long_double, type_char_ptr);
case T___builtin_va_end:
return make_function_1_type(type_void, type_valist);
}
}
- type_t *type = declaration->type;
+ type_t *orig_type = declaration->type;
/* we always do the auto-type conversions; the & and sizeof parser contains
* code to revert this! */
- type = automatic_type_conversion(type);
+ type_t *type = automatic_type_conversion(orig_type);
ref->declaration = declaration;
ref->base.type = type;
/* this declaration is used */
declaration->used = true;
+ if (declaration->parent_scope != file_scope &&
+ declaration->parent_scope->depth < current_function->scope.depth &&
+ is_type_valid(orig_type) && !is_type_function(orig_type)) {
+ /* access of a variable from an outer function */
+ declaration->address_taken = true;
+ current_function->need_closure = true;
+ }
+
/* check for deprecated functions */
if (warning.deprecated_declarations &&
declaration->modifiers & DM_DEPRECATED) {
declaration->symbol, &declaration->source_position);
}
}
- if (warning.init_self && declaration == current_init_decl) {
+ if (warning.init_self && declaration == current_init_decl && !in_type_prop) {
current_init_decl = NULL;
warningf(HERE, "variable '%#T' is initialized by itself",
declaration->type, declaration->symbol);
expression_t *cast = allocate_expression_zero(EXPR_UNARY_CAST);
cast->base.source_position = source_position;
- expression_t *value = parse_sub_expression(20);
+ expression_t *value = parse_sub_expression(PREC_CAST);
cast->base.type = type;
cast->unary.value = value;
if (stmt->kind == STATEMENT_EXPRESSION) {
type = stmt->expression.expression->base.type;
}
- } else {
+ } else if (warning.other) {
warningf(&expression->base.source_position, "empty statement expression ({})");
}
expression->base.type = type;
break;
default:
internal_errorf(HERE, "invalid compare builtin found");
- break;
}
expression->base.source_position = *HERE;
next_token();
candidate = get_declaration(symbol, NAMESPACE_LOCAL_LABEL);
/* if we found a local label, we already created the declaration */
if (candidate != NULL) {
- assert(candidate->parent_scope == scope);
+ if (candidate->parent_scope != scope) {
+ assert(candidate->parent_scope->depth < scope->depth);
+ current_function->goto_to_outer = true;
+ }
return candidate;
}
case T___builtin_va_arg: return parse_va_arg();
case T___builtin_expect:
case T___builtin_alloca:
+ case T___builtin_inf:
+ case T___builtin_inff:
+ case T___builtin_infl:
case T___builtin_nan:
- case T___builtin_nand:
case T___builtin_nanf:
+ case T___builtin_nanl:
case T___builtin_huge_val:
case T___builtin_va_end: return parse_builtin_symbol();
case T___builtin_isgreater:
case T___builtin_prefetch: return parse_builtin_prefetch();
case T__assume: return parse_assume();
case T_ANDAND:
- if (c_mode & _GNUC)
+ if (GNU_MODE)
return parse_label_address();
break;
}
}
-static expression_t *parse_array_expression(unsigned precedence,
- expression_t *left)
+static expression_t *parse_array_expression(expression_t *left)
{
- (void) precedence;
-
eat('[');
add_anchor_token(']');
}
static expression_t *parse_typeprop(expression_kind_t const kind,
- source_position_t const pos,
- unsigned const precedence)
+ source_position_t const pos)
{
- expression_t *tp_expression = allocate_expression_zero(kind);
+ expression_t *tp_expression = allocate_expression_zero(kind);
tp_expression->base.type = type_size_t;
tp_expression->base.source_position = pos;
char const* const what = kind == EXPR_SIZEOF ? "sizeof" : "alignof";
+ /* we only refer to a type property, mark this case */
+ bool old = in_type_prop;
+ in_type_prop = true;
if (token.type == '(' && is_declaration_specifier(look_ahead(1), true)) {
next_token();
add_anchor_token(')');
rem_anchor_token(')');
expect(')');
} else {
- expression_t *expression = parse_sub_expression(precedence);
+ expression_t *expression = parse_sub_expression(PREC_UNARY);
type_t* const orig_type = revert_automatic_type_conversion(expression);
expression->base.type = orig_type;
}
end_error:
+ in_type_prop = old;
return tp_expression;
}
-static expression_t *parse_sizeof(unsigned precedence)
+static expression_t *parse_sizeof(void)
{
source_position_t pos = *HERE;
eat(T_sizeof);
- return parse_typeprop(EXPR_SIZEOF, pos, precedence);
+ return parse_typeprop(EXPR_SIZEOF, pos);
}
-static expression_t *parse_alignof(unsigned precedence)
+static expression_t *parse_alignof(void)
{
source_position_t pos = *HERE;
eat(T___alignof__);
- return parse_typeprop(EXPR_ALIGNOF, pos, precedence);
+ return parse_typeprop(EXPR_ALIGNOF, pos);
}
-static expression_t *parse_select_expression(unsigned precedence,
- expression_t *compound)
+static expression_t *parse_select_expression(expression_t *compound)
{
- (void) precedence;
assert(token.type == '.' || token.type == T_MINUSGREATER);
bool is_pointer = (token.type == T_MINUSGREATER);
*
* @param expression the function address
*/
-static expression_t *parse_call_expression(unsigned precedence,
- expression_t *expression)
+static expression_t *parse_call_expression(expression_t *expression)
{
- (void) precedence;
expression_t *result = allocate_expression_zero(EXPR_CALL);
result->base.source_position = expression->base.source_position;
*
* @param expression the conditional expression
*/
-static expression_t *parse_conditional_expression(unsigned precedence,
- expression_t *expression)
+static expression_t *parse_conditional_expression(expression_t *expression)
{
expression_t *result = allocate_expression_zero(EXPR_CONDITIONAL);
expression_t *true_expression = expression;
bool gnu_cond = false;
- if ((c_mode & _GNUC) && token.type == ':') {
+ if (GNU_MODE && token.type == ':') {
gnu_cond = true;
} else
true_expression = parse_expression();
rem_anchor_token(':');
expect(':');
- expression_t *false_expression = parse_sub_expression(precedence);
+ expression_t *false_expression = parse_sub_expression(PREC_CONDITIONAL);
type_t *const orig_true_type = true_expression->base.type;
type_t *const orig_false_type = false_expression->base.type;
/* 6.5.15.3 */
type_t *result_type;
- if (is_type_atomic(true_type, ATOMIC_TYPE_VOID) ||
- is_type_atomic(false_type, ATOMIC_TYPE_VOID)) {
- if (!is_type_atomic(true_type, ATOMIC_TYPE_VOID)
- || !is_type_atomic(false_type, ATOMIC_TYPE_VOID)) {
+ if (is_type_atomic(true_type, ATOMIC_TYPE_VOID) ||
+ is_type_atomic(false_type, ATOMIC_TYPE_VOID)) {
+ if (warning.other && (
+ !is_type_atomic(true_type, ATOMIC_TYPE_VOID) ||
+ !is_type_atomic(false_type, ATOMIC_TYPE_VOID)
+ )) {
warningf(&conditional->base.source_position,
"ISO C forbids conditional expression with only one void side");
}
get_unqualified_type(to2))) {
to = to1;
} else {
- warningf(&conditional->base.source_position,
- "pointer types '%T' and '%T' in conditional expression are incompatible",
- true_type, false_type);
+ if (warning.other) {
+ warningf(&conditional->base.source_position,
+ "pointer types '%T' and '%T' in conditional expression are incompatible",
+ true_type, false_type);
+ }
to = type_void;
}
get_qualified_type(to, to1->base.qualifiers | to2->base.qualifiers);
result_type = make_pointer_type(type, TYPE_QUALIFIER_NONE);
} else if (is_type_integer(other_type)) {
- warningf(&conditional->base.source_position,
- "pointer/integer type mismatch in conditional expression ('%T' and '%T')", true_type, false_type);
+ if (warning.other) {
+ warningf(&conditional->base.source_position,
+ "pointer/integer type mismatch in conditional expression ('%T' and '%T')", true_type, false_type);
+ }
result_type = pointer_type;
} else {
- type_error_incompatible("while parsing conditional",
- &expression->base.source_position, true_type, false_type);
+ if (is_type_valid(other_type)) {
+ type_error_incompatible("while parsing conditional",
+ &expression->base.source_position, true_type, false_type);
+ }
result_type = type_error_type;
}
} else {
- /* TODO: one pointer to void*, other some pointer */
-
if (is_type_valid(true_type) && is_type_valid(false_type)) {
type_error_incompatible("while parsing conditional",
&conditional->base.source_position, true_type,
/**
* Parse an extension expression.
*/
-static expression_t *parse_extension(unsigned precedence)
+static expression_t *parse_extension(void)
{
eat(T___extension__);
- /* TODO enable extensions */
- expression_t *expression = parse_sub_expression(precedence);
- /* TODO disable extensions */
+ bool old_gcc_extension = in_gcc_extension;
+ in_gcc_extension = true;
+ expression_t *expression = parse_sub_expression(PREC_UNARY);
+ in_gcc_extension = old_gcc_extension;
return expression;
}
/**
* Parse a __builtin_classify_type() expression.
*/
-static expression_t *parse_builtin_classify_type(const unsigned precedence)
+static expression_t *parse_builtin_classify_type(void)
{
eat(T___builtin_classify_type);
expect('(');
add_anchor_token(')');
- expression_t *expression = parse_sub_expression(precedence);
+ expression_t *expression = parse_expression();
rem_anchor_token(')');
expect(')');
result->classify_type.type_expression = expression;
points_to = skip_typeref(points_to);
if (is_type_incomplete(points_to)) {
- if (!(c_mode & _GNUC) || !is_type_atomic(points_to, ATOMIC_TYPE_VOID)) {
+ if (!GNU_MODE || !is_type_atomic(points_to, ATOMIC_TYPE_VOID)) {
errorf(source_position,
"arithmetic with pointer to incomplete type '%T' not allowed",
orig_pointer_type);
orig_pointer_type);
}
} else if (is_type_function(points_to)) {
- if (!(c_mode && _GNUC)) {
+ if (!GNU_MODE) {
errorf(source_position,
"arithmetic with pointer to function type '%T' not allowed",
orig_pointer_type);
return true;
default:
- return false;
+ /* Claim it is an lvalue, if the type is invalid. There was a parse
+ * error before, which maybe prevented properly recognizing it as
+ * lvalue. */
+ return !is_type_valid(skip_typeref(expression->base.type));
}
}
"traditional C rejects the unary plus operator");
}
+static expression_t const *get_reference_address(expression_t const *expr)
+{
+ bool regular_take_address = true;
+ for (;;) {
+ if (expr->kind == EXPR_UNARY_TAKE_ADDRESS) {
+ expr = expr->unary.value;
+ } else {
+ regular_take_address = false;
+ }
+
+ if (expr->kind != EXPR_UNARY_DEREFERENCE)
+ break;
+
+ expr = expr->unary.value;
+ }
+
+ if (expr->kind != EXPR_REFERENCE)
+ return NULL;
+
+ if (!regular_take_address &&
+ !is_type_function(skip_typeref(expr->reference.declaration->type))) {
+ return NULL;
+ }
+
+ return expr;
+}
+
+static void warn_function_address_as_bool(expression_t const* expr)
+{
+ if (!warning.address)
+ return;
+
+ expr = get_reference_address(expr);
+ if (expr != NULL) {
+ warningf(&expr->base.source_position,
+ "the address of '%Y' will always evaluate as 'true'",
+ expr->reference.declaration->symbol);
+ }
+}
+
static void semantic_not(unary_expression_t *expression)
{
type_t *const orig_type = expression->value->base.type;
"operand of ! must be of scalar type");
}
+ warn_function_address_as_bool(expression->value);
+
expression->base.type = type_int;
}
value->base.type = revert_automatic_type_conversion(value);
type_t *orig_type = value->base.type;
- if (!is_type_valid(orig_type))
+ if (!is_type_valid(skip_typeref(orig_type)))
return;
set_address_taken(value, false);
expression->base.type = make_pointer_type(orig_type, TYPE_QUALIFIER_NONE);
}
-#define CREATE_UNARY_EXPRESSION_PARSER(token_type, unexpression_type, sfunc) \
-static expression_t *parse_##unexpression_type(unsigned precedence) \
-{ \
- expression_t *unary_expression \
- = allocate_expression_zero(unexpression_type); \
- unary_expression->base.source_position = *HERE; \
- eat(token_type); \
- unary_expression->unary.value = parse_sub_expression(precedence); \
- \
- sfunc(&unary_expression->unary); \
- \
- return unary_expression; \
+#define CREATE_UNARY_EXPRESSION_PARSER(token_type, unexpression_type, sfunc) \
+static expression_t *parse_##unexpression_type(void) \
+{ \
+ expression_t *unary_expression \
+ = allocate_expression_zero(unexpression_type); \
+ unary_expression->base.source_position = *HERE; \
+ eat(token_type); \
+ unary_expression->unary.value = parse_sub_expression(PREC_UNARY); \
+ \
+ sfunc(&unary_expression->unary); \
+ \
+ return unary_expression; \
}
CREATE_UNARY_EXPRESSION_PARSER('-', EXPR_UNARY_NEGATE,
#define CREATE_UNARY_POSTFIX_EXPRESSION_PARSER(token_type, unexpression_type, \
sfunc) \
-static expression_t *parse_##unexpression_type(unsigned precedence, \
- expression_t *left) \
+static expression_t *parse_##unexpression_type(expression_t *left) \
{ \
- (void) precedence; \
- \
expression_t *unary_expression \
= allocate_expression_zero(unexpression_type); \
unary_expression->base.source_position = *HERE; \
"subtracting pointers to incompatible types '%T' and '%T'",
orig_type_left, orig_type_right);
} else if (!is_type_object(unqual_left)) {
- if (is_type_atomic(unqual_left, ATOMIC_TYPE_VOID)) {
- warningf(pos, "subtracting pointers to void");
- } else {
+ if (!is_type_atomic(unqual_left, ATOMIC_TYPE_VOID)) {
errorf(pos, "subtracting pointers to non-object types '%T'",
orig_type_left);
+ } else if (warning.other) {
+ warningf(pos, "subtracting pointers to void");
}
}
expression->base.type = type_ptrdiff_t;
}
}
+static void warn_string_literal_address(expression_t const* expr)
+{
+ while (expr->kind == EXPR_UNARY_TAKE_ADDRESS) {
+ expr = expr->unary.value;
+ if (expr->kind != EXPR_UNARY_DEREFERENCE)
+ return;
+ expr = expr->unary.value;
+ }
+
+ if (expr->kind == EXPR_STRING_LITERAL ||
+ expr->kind == EXPR_WIDE_STRING_LITERAL) {
+ warningf(&expr->base.source_position,
+ "comparison with string literal results in unspecified behaviour");
+ }
+}
+
/**
* Check the semantics of comparison expressions.
*
*/
static void semantic_comparison(binary_expression_t *expression)
{
- expression_t *left = expression->left;
- expression_t *right = expression->right;
- type_t *orig_type_left = left->base.type;
- type_t *orig_type_right = right->base.type;
+ expression_t *left = expression->left;
+ expression_t *right = expression->right;
- type_t *type_left = skip_typeref(orig_type_left);
- type_t *type_right = skip_typeref(orig_type_right);
+ if (warning.address) {
+ warn_string_literal_address(left);
+ warn_string_literal_address(right);
+
+ expression_t const* const func_left = get_reference_address(left);
+ if (func_left != NULL && is_null_pointer_constant(right)) {
+ warningf(&expression->base.source_position,
+ "the address of '%Y' will never be NULL",
+ func_left->reference.declaration->symbol);
+ }
+
+ expression_t const* const func_right = get_reference_address(right);
+ if (func_right != NULL && is_null_pointer_constant(right)) {
+ warningf(&expression->base.source_position,
+ "the address of '%Y' will never be NULL",
+ func_right->reference.declaration->symbol);
+ }
+ }
+
+ type_t *orig_type_left = left->base.type;
+ type_t *orig_type_right = right->base.type;
+ type_t *type_left = skip_typeref(orig_type_left);
+ type_t *type_right = skip_typeref(orig_type_right);
/* TODO non-arithmetic types */
if (is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
type_t *const type_left = skip_typeref(orig_type_left);
type_t *const type_right = skip_typeref(orig_type_right);
+ warn_function_address_as_bool(left);
+ warn_function_address_as_bool(right);
+
if (!is_type_scalar(type_left) || !is_type_scalar(type_right)) {
/* TODO: improve error message */
if (is_type_valid(type_left) && is_type_valid(type_right)) {
expression->base.type = expression->right->base.type;
}
-#define CREATE_BINEXPR_PARSER(token_type, binexpression_type, sfunc, lr) \
-static expression_t *parse_##binexpression_type(unsigned precedence, \
- expression_t *left) \
-{ \
- expression_t *binexpr = allocate_expression_zero(binexpression_type); \
- binexpr->base.source_position = *HERE; \
- binexpr->binary.left = left; \
- eat(token_type); \
- \
- expression_t *right = parse_sub_expression(precedence + lr); \
- \
- binexpr->binary.right = right; \
- sfunc(&binexpr->binary); \
- \
- return binexpr; \
-}
-
-CREATE_BINEXPR_PARSER(',', EXPR_BINARY_COMMA, semantic_comma, 1)
-CREATE_BINEXPR_PARSER('*', EXPR_BINARY_MUL, semantic_binexpr_arithmetic, 1)
-CREATE_BINEXPR_PARSER('/', EXPR_BINARY_DIV, semantic_divmod_arithmetic, 1)
-CREATE_BINEXPR_PARSER('%', EXPR_BINARY_MOD, semantic_divmod_arithmetic, 1)
-CREATE_BINEXPR_PARSER('+', EXPR_BINARY_ADD, semantic_add, 1)
-CREATE_BINEXPR_PARSER('-', EXPR_BINARY_SUB, semantic_sub, 1)
-CREATE_BINEXPR_PARSER('<', EXPR_BINARY_LESS, semantic_comparison, 1)
-CREATE_BINEXPR_PARSER('>', EXPR_BINARY_GREATER, semantic_comparison, 1)
-CREATE_BINEXPR_PARSER('=', EXPR_BINARY_ASSIGN, semantic_binexpr_assign, 0)
-
-CREATE_BINEXPR_PARSER(T_EQUALEQUAL, EXPR_BINARY_EQUAL,
- semantic_comparison, 1)
-CREATE_BINEXPR_PARSER(T_EXCLAMATIONMARKEQUAL, EXPR_BINARY_NOTEQUAL,
- semantic_comparison, 1)
-CREATE_BINEXPR_PARSER(T_LESSEQUAL, EXPR_BINARY_LESSEQUAL,
- semantic_comparison, 1)
-CREATE_BINEXPR_PARSER(T_GREATEREQUAL, EXPR_BINARY_GREATEREQUAL,
- semantic_comparison, 1)
-
-CREATE_BINEXPR_PARSER('&', EXPR_BINARY_BITWISE_AND,
- semantic_binexpr_arithmetic, 1)
-CREATE_BINEXPR_PARSER('|', EXPR_BINARY_BITWISE_OR,
- semantic_binexpr_arithmetic, 1)
-CREATE_BINEXPR_PARSER('^', EXPR_BINARY_BITWISE_XOR,
- semantic_binexpr_arithmetic, 1)
-CREATE_BINEXPR_PARSER(T_ANDAND, EXPR_BINARY_LOGICAL_AND,
- semantic_logical_op, 1)
-CREATE_BINEXPR_PARSER(T_PIPEPIPE, EXPR_BINARY_LOGICAL_OR,
- semantic_logical_op, 1)
-CREATE_BINEXPR_PARSER(T_LESSLESS, EXPR_BINARY_SHIFTLEFT,
- semantic_shift_op, 1)
-CREATE_BINEXPR_PARSER(T_GREATERGREATER, EXPR_BINARY_SHIFTRIGHT,
- semantic_shift_op, 1)
-CREATE_BINEXPR_PARSER(T_PLUSEQUAL, EXPR_BINARY_ADD_ASSIGN,
- semantic_arithmetic_addsubb_assign, 0)
-CREATE_BINEXPR_PARSER(T_MINUSEQUAL, EXPR_BINARY_SUB_ASSIGN,
- semantic_arithmetic_addsubb_assign, 0)
-CREATE_BINEXPR_PARSER(T_ASTERISKEQUAL, EXPR_BINARY_MUL_ASSIGN,
- semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_SLASHEQUAL, EXPR_BINARY_DIV_ASSIGN,
- semantic_divmod_assign, 0)
-CREATE_BINEXPR_PARSER(T_PERCENTEQUAL, EXPR_BINARY_MOD_ASSIGN,
- semantic_divmod_assign, 0)
-CREATE_BINEXPR_PARSER(T_LESSLESSEQUAL, EXPR_BINARY_SHIFTLEFT_ASSIGN,
- semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_GREATERGREATEREQUAL, EXPR_BINARY_SHIFTRIGHT_ASSIGN,
- semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_ANDEQUAL, EXPR_BINARY_BITWISE_AND_ASSIGN,
- semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_PIPEEQUAL, EXPR_BINARY_BITWISE_OR_ASSIGN,
- semantic_arithmetic_assign, 0)
-CREATE_BINEXPR_PARSER(T_CARETEQUAL, EXPR_BINARY_BITWISE_XOR_ASSIGN,
- semantic_arithmetic_assign, 0)
-
-static expression_t *parse_sub_expression(unsigned precedence)
+/**
+ * @param prec_r precedence of the right operand
+ */
+#define CREATE_BINEXPR_PARSER(token_type, binexpression_type, prec_r, sfunc) \
+static expression_t *parse_##binexpression_type(expression_t *left) \
+{ \
+ expression_t *binexpr = allocate_expression_zero(binexpression_type); \
+ binexpr->base.source_position = *HERE; \
+ binexpr->binary.left = left; \
+ eat(token_type); \
+ \
+ expression_t *right = parse_sub_expression(prec_r); \
+ \
+ binexpr->binary.right = right; \
+ sfunc(&binexpr->binary); \
+ \
+ return binexpr; \
+}
+
+CREATE_BINEXPR_PARSER('*', EXPR_BINARY_MUL, PREC_CAST, semantic_binexpr_arithmetic)
+CREATE_BINEXPR_PARSER('/', EXPR_BINARY_DIV, PREC_CAST, semantic_divmod_arithmetic)
+CREATE_BINEXPR_PARSER('%', EXPR_BINARY_MOD, PREC_CAST, semantic_divmod_arithmetic)
+CREATE_BINEXPR_PARSER('+', EXPR_BINARY_ADD, PREC_MULTIPLICATIVE, semantic_add)
+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_BITWISE_AND, PREC_EQUALITY, semantic_binexpr_arithmetic)
+CREATE_BINEXPR_PARSER('^', EXPR_BINARY_BITWISE_XOR, PREC_AND, semantic_binexpr_arithmetic)
+CREATE_BINEXPR_PARSER('|', EXPR_BINARY_BITWISE_OR, PREC_XOR, semantic_binexpr_arithmetic)
+CREATE_BINEXPR_PARSER(T_ANDAND, EXPR_BINARY_LOGICAL_AND, PREC_OR, semantic_logical_op)
+CREATE_BINEXPR_PARSER(T_PIPEPIPE, EXPR_BINARY_LOGICAL_OR, PREC_LOGICAL_AND, semantic_logical_op)
+CREATE_BINEXPR_PARSER('=', EXPR_BINARY_ASSIGN, PREC_ASSIGNMENT, semantic_binexpr_assign)
+CREATE_BINEXPR_PARSER(T_PLUSEQUAL, EXPR_BINARY_ADD_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_addsubb_assign)
+CREATE_BINEXPR_PARSER(T_MINUSEQUAL, EXPR_BINARY_SUB_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_addsubb_assign)
+CREATE_BINEXPR_PARSER(T_ASTERISKEQUAL, EXPR_BINARY_MUL_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
+CREATE_BINEXPR_PARSER(T_SLASHEQUAL, EXPR_BINARY_DIV_ASSIGN, PREC_ASSIGNMENT, semantic_divmod_assign)
+CREATE_BINEXPR_PARSER(T_PERCENTEQUAL, EXPR_BINARY_MOD_ASSIGN, PREC_ASSIGNMENT, semantic_divmod_assign)
+CREATE_BINEXPR_PARSER(T_LESSLESSEQUAL, EXPR_BINARY_SHIFTLEFT_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
+CREATE_BINEXPR_PARSER(T_GREATERGREATEREQUAL, EXPR_BINARY_SHIFTRIGHT_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
+CREATE_BINEXPR_PARSER(T_ANDEQUAL, EXPR_BINARY_BITWISE_AND_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
+CREATE_BINEXPR_PARSER(T_PIPEEQUAL, EXPR_BINARY_BITWISE_OR_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
+CREATE_BINEXPR_PARSER(T_CARETEQUAL, EXPR_BINARY_BITWISE_XOR_ASSIGN, PREC_ASSIGNMENT, semantic_arithmetic_assign)
+CREATE_BINEXPR_PARSER(',', EXPR_BINARY_COMMA, PREC_ASSIGNMENT, semantic_comma)
+
+
+static expression_t *parse_sub_expression(precedence_t precedence)
{
if (token.type < 0) {
return expected_expression_error();
expression_t *left;
if (parser->parser != NULL) {
- left = parser->parser(parser->precedence);
+ left = parser->parser();
} else {
left = parse_primary_expression();
}
if (parser->infix_precedence < precedence)
break;
- left = parser->infix_parser(parser->infix_precedence, left);
+ left = parser->infix_parser(left);
assert(left != NULL);
assert(left->kind != EXPR_UNKNOWN);
*/
static expression_t *parse_expression(void)
{
- return parse_sub_expression(1);
+ return parse_sub_expression(PREC_EXPRESSION);
}
/**
- * Register a parser for a prefix-like operator with given precedence.
+ * Register a parser for a prefix-like operator.
*
* @param parser the parser function
* @param token_type the token type of the prefix token
- * @param precedence the precedence of the operator
*/
static void register_expression_parser(parse_expression_function parser,
- int token_type, unsigned precedence)
+ int token_type)
{
expression_parser_function_t *entry = &expression_parsers[token_type];
diagnosticf("for token '%k'\n", (token_type_t)token_type);
panic("trying to register multiple expression parsers for a token");
}
- entry->parser = parser;
- entry->precedence = precedence;
+ entry->parser = parser;
}
/**
{
memset(&expression_parsers, 0, sizeof(expression_parsers));
- register_infix_parser(parse_array_expression, '[', 30);
- register_infix_parser(parse_call_expression, '(', 30);
- register_infix_parser(parse_select_expression, '.', 30);
- register_infix_parser(parse_select_expression, T_MINUSGREATER, 30);
- register_infix_parser(parse_EXPR_UNARY_POSTFIX_INCREMENT,
- T_PLUSPLUS, 30);
- register_infix_parser(parse_EXPR_UNARY_POSTFIX_DECREMENT,
- T_MINUSMINUS, 30);
-
- register_infix_parser(parse_EXPR_BINARY_MUL, '*', 17);
- register_infix_parser(parse_EXPR_BINARY_DIV, '/', 17);
- register_infix_parser(parse_EXPR_BINARY_MOD, '%', 17);
- register_infix_parser(parse_EXPR_BINARY_ADD, '+', 16);
- register_infix_parser(parse_EXPR_BINARY_SUB, '-', 16);
- register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT, T_LESSLESS, 15);
- register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT, T_GREATERGREATER, 15);
- register_infix_parser(parse_EXPR_BINARY_LESS, '<', 14);
- register_infix_parser(parse_EXPR_BINARY_GREATER, '>', 14);
- register_infix_parser(parse_EXPR_BINARY_LESSEQUAL, T_LESSEQUAL, 14);
- register_infix_parser(parse_EXPR_BINARY_GREATEREQUAL, T_GREATEREQUAL, 14);
- register_infix_parser(parse_EXPR_BINARY_EQUAL, T_EQUALEQUAL, 13);
- register_infix_parser(parse_EXPR_BINARY_NOTEQUAL,
- T_EXCLAMATIONMARKEQUAL, 13);
- register_infix_parser(parse_EXPR_BINARY_BITWISE_AND, '&', 12);
- register_infix_parser(parse_EXPR_BINARY_BITWISE_XOR, '^', 11);
- register_infix_parser(parse_EXPR_BINARY_BITWISE_OR, '|', 10);
- register_infix_parser(parse_EXPR_BINARY_LOGICAL_AND, T_ANDAND, 9);
- register_infix_parser(parse_EXPR_BINARY_LOGICAL_OR, T_PIPEPIPE, 8);
- register_infix_parser(parse_conditional_expression, '?', 7);
- register_infix_parser(parse_EXPR_BINARY_ASSIGN, '=', 2);
- register_infix_parser(parse_EXPR_BINARY_ADD_ASSIGN, T_PLUSEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_SUB_ASSIGN, T_MINUSEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_MUL_ASSIGN, T_ASTERISKEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_DIV_ASSIGN, T_SLASHEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_MOD_ASSIGN, T_PERCENTEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT_ASSIGN,
- T_LESSLESSEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT_ASSIGN,
- T_GREATERGREATEREQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_BITWISE_AND_ASSIGN,
- T_ANDEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_BITWISE_OR_ASSIGN,
- T_PIPEEQUAL, 2);
- register_infix_parser(parse_EXPR_BINARY_BITWISE_XOR_ASSIGN,
- T_CARETEQUAL, 2);
-
- register_infix_parser(parse_EXPR_BINARY_COMMA, ',', 1);
-
- register_expression_parser(parse_EXPR_UNARY_NEGATE, '-', 25);
- register_expression_parser(parse_EXPR_UNARY_PLUS, '+', 25);
- register_expression_parser(parse_EXPR_UNARY_NOT, '!', 25);
- register_expression_parser(parse_EXPR_UNARY_BITWISE_NEGATE, '~', 25);
- register_expression_parser(parse_EXPR_UNARY_DEREFERENCE, '*', 25);
- register_expression_parser(parse_EXPR_UNARY_TAKE_ADDRESS, '&', 25);
- register_expression_parser(parse_EXPR_UNARY_PREFIX_INCREMENT,
- T_PLUSPLUS, 25);
- register_expression_parser(parse_EXPR_UNARY_PREFIX_DECREMENT,
- T_MINUSMINUS, 25);
- register_expression_parser(parse_sizeof, T_sizeof, 25);
- register_expression_parser(parse_alignof, T___alignof__, 25);
- register_expression_parser(parse_extension, T___extension__, 25);
- register_expression_parser(parse_builtin_classify_type,
- T___builtin_classify_type, 25);
+ register_infix_parser(parse_array_expression, '[', PREC_POSTFIX);
+ register_infix_parser(parse_call_expression, '(', PREC_POSTFIX);
+ register_infix_parser(parse_select_expression, '.', PREC_POSTFIX);
+ register_infix_parser(parse_select_expression, T_MINUSGREATER, PREC_POSTFIX);
+ register_infix_parser(parse_EXPR_UNARY_POSTFIX_INCREMENT, T_PLUSPLUS, PREC_POSTFIX);
+ register_infix_parser(parse_EXPR_UNARY_POSTFIX_DECREMENT, T_MINUSMINUS, PREC_POSTFIX);
+ register_infix_parser(parse_EXPR_BINARY_MUL, '*', PREC_MULTIPLICATIVE);
+ register_infix_parser(parse_EXPR_BINARY_DIV, '/', PREC_MULTIPLICATIVE);
+ register_infix_parser(parse_EXPR_BINARY_MOD, '%', PREC_MULTIPLICATIVE);
+ register_infix_parser(parse_EXPR_BINARY_ADD, '+', PREC_ADDITIVE);
+ register_infix_parser(parse_EXPR_BINARY_SUB, '-', PREC_ADDITIVE);
+ register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT, T_LESSLESS, PREC_SHIFT);
+ register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT, T_GREATERGREATER, PREC_SHIFT);
+ register_infix_parser(parse_EXPR_BINARY_LESS, '<', PREC_RELATIONAL);
+ register_infix_parser(parse_EXPR_BINARY_GREATER, '>', PREC_RELATIONAL);
+ register_infix_parser(parse_EXPR_BINARY_LESSEQUAL, T_LESSEQUAL, PREC_RELATIONAL);
+ register_infix_parser(parse_EXPR_BINARY_GREATEREQUAL, T_GREATEREQUAL, PREC_RELATIONAL);
+ register_infix_parser(parse_EXPR_BINARY_EQUAL, T_EQUALEQUAL, PREC_EQUALITY);
+ register_infix_parser(parse_EXPR_BINARY_NOTEQUAL, T_EXCLAMATIONMARKEQUAL, PREC_EQUALITY);
+ register_infix_parser(parse_EXPR_BINARY_BITWISE_AND, '&', PREC_AND);
+ register_infix_parser(parse_EXPR_BINARY_BITWISE_XOR, '^', PREC_XOR);
+ register_infix_parser(parse_EXPR_BINARY_BITWISE_OR, '|', PREC_OR);
+ register_infix_parser(parse_EXPR_BINARY_LOGICAL_AND, T_ANDAND, PREC_LOGICAL_AND);
+ register_infix_parser(parse_EXPR_BINARY_LOGICAL_OR, T_PIPEPIPE, PREC_LOGICAL_OR);
+ register_infix_parser(parse_conditional_expression, '?', PREC_CONDITIONAL);
+ register_infix_parser(parse_EXPR_BINARY_ASSIGN, '=', PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_ADD_ASSIGN, T_PLUSEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_SUB_ASSIGN, T_MINUSEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_MUL_ASSIGN, T_ASTERISKEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_DIV_ASSIGN, T_SLASHEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_MOD_ASSIGN, T_PERCENTEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_SHIFTLEFT_ASSIGN, T_LESSLESSEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_SHIFTRIGHT_ASSIGN, T_GREATERGREATEREQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_BITWISE_AND_ASSIGN, T_ANDEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_BITWISE_OR_ASSIGN, T_PIPEEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_BITWISE_XOR_ASSIGN, T_CARETEQUAL, PREC_ASSIGNMENT);
+ register_infix_parser(parse_EXPR_BINARY_COMMA, ',', PREC_EXPRESSION);
+
+ register_expression_parser(parse_EXPR_UNARY_NEGATE, '-');
+ register_expression_parser(parse_EXPR_UNARY_PLUS, '+');
+ register_expression_parser(parse_EXPR_UNARY_NOT, '!');
+ register_expression_parser(parse_EXPR_UNARY_BITWISE_NEGATE, '~');
+ register_expression_parser(parse_EXPR_UNARY_DEREFERENCE, '*');
+ register_expression_parser(parse_EXPR_UNARY_TAKE_ADDRESS, '&');
+ register_expression_parser(parse_EXPR_UNARY_PREFIX_INCREMENT, T_PLUSPLUS);
+ register_expression_parser(parse_EXPR_UNARY_PREFIX_DECREMENT, T_MINUSMINUS);
+ register_expression_parser(parse_sizeof, T_sizeof);
+ register_expression_parser(parse_alignof, T___alignof__);
+ register_expression_parser(parse_extension, T___extension__);
+ register_expression_parser(parse_builtin_classify_type, T___builtin_classify_type);
}
/**
errorf(&expression->base.source_position,
"asm output argument is not an lvalue");
}
+
+ if (argument->constraints.begin[0] == '+')
+ mark_decls_read(expression, NULL);
+ } else {
+ mark_decls_read(expression, NULL);
}
argument->expression = expression;
expect(')');
*/
static statement_t *parse_asm_statement(void)
{
- eat(T_asm);
-
- statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
- statement->base.source_position = token.source_position;
-
+ statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
asm_statement_t *asm_statement = &statement->asms;
+ eat(T_asm);
+
if (token.type == T_volatile) {
next_token();
asm_statement->is_volatile = true;
*/
static statement_t *parse_case_statement(void)
{
- eat(T_case);
-
statement_t *const statement = allocate_statement_zero(STATEMENT_CASE_LABEL);
source_position_t *const pos = &statement->base.source_position;
- *pos = token.source_position;
+ eat(T_case);
+
expression_t *const expression = parse_expression();
statement->case_label.expression = expression;
if (!is_constant_expression(expression)) {
/* This check does not prevent the error message in all cases of an
* prior error while parsing the expression. At least it catches the
* common case of a mistyped enum entry. */
- if (is_type_valid(expression->base.type)) {
+ if (is_type_valid(skip_typeref(expression->base.type))) {
errorf(pos, "case label does not reduce to an integer constant");
}
statement->case_label.is_bad = true;
statement->case_label.last_case = val;
}
- if (c_mode & _GNUC) {
+ if (GNU_MODE) {
if (token.type == T_DOTDOTDOT) {
next_token();
expression_t *const end_range = parse_expression();
/* This check does not prevent the error message in all cases of an
* prior error while parsing the expression. At least it catches the
* common case of a mistyped enum entry. */
- if (is_type_valid(end_range->base.type)) {
+ if (is_type_valid(skip_typeref(end_range->base.type))) {
errorf(pos, "case range does not reduce to an integer constant");
}
statement->case_label.is_bad = true;
long const val = fold_constant(end_range);
statement->case_label.last_case = val;
- if (val < statement->case_label.first_case) {
+ if (warning.other && val < statement->case_label.first_case) {
statement->case_label.is_empty_range = true;
warningf(pos, "empty range specified");
}
*/
static statement_t *parse_default_statement(void)
{
- eat(T_default);
-
statement_t *statement = allocate_statement_zero(STATEMENT_CASE_LABEL);
- statement->base.source_position = token.source_position;
+
+ eat(T_default);
PUSH_PARENT(statement);
static statement_t *parse_label_statement(void)
{
assert(token.type == T_IDENTIFIER);
- symbol_t *symbol = token.v.symbol;
- next_token();
-
- declaration_t *label = get_label(symbol);
+ symbol_t *symbol = token.v.symbol;
+ declaration_t *label = get_label(symbol);
statement_t *const statement = allocate_statement_zero(STATEMENT_LABEL);
- statement->base.source_position = token.source_position;
- statement->label.label = label;
+ statement->label.label = label;
+
+ next_token();
PUSH_PARENT(statement);
if (token.type == '}') {
/* TODO only warn? */
- if (false) {
+ if (warning.other && false) {
warningf(HERE, "label at end of compound statement");
statement->label.statement = create_empty_statement();
} else {
*/
static statement_t *parse_if(void)
{
- eat(T_if);
+ statement_t *statement = allocate_statement_zero(STATEMENT_IF);
- statement_t *statement = allocate_statement_zero(STATEMENT_IF);
- statement->base.source_position = token.source_position;
+ eat(T_if);
PUSH_PARENT(statement);
+ add_anchor_token('{');
+
expect('(');
add_anchor_token(')');
- statement->ifs.condition = parse_expression();
+ expression_t *const expr = parse_expression();
+ statement->ifs.condition = expr;
+ mark_decls_read(expr, NULL);
rem_anchor_token(')');
expect(')');
+end_error:
+ rem_anchor_token('{');
+
add_anchor_token(T_else);
statement->ifs.true_statement = parse_statement();
rem_anchor_token(T_else);
POP_PARENT;
return statement;
-end_error:
- POP_PARENT;
- return create_invalid_statement();
}
/**
*/
static statement_t *parse_switch(void)
{
- eat(T_switch);
+ statement_t *statement = allocate_statement_zero(STATEMENT_SWITCH);
- statement_t *statement = allocate_statement_zero(STATEMENT_SWITCH);
- statement->base.source_position = token.source_position;
+ eat(T_switch);
PUSH_PARENT(statement);
expect('(');
add_anchor_token(')');
expression_t *const expr = parse_expression();
+ mark_decls_read(expr, NULL);
type_t * type = skip_typeref(expr->base.type);
if (is_type_integer(type)) {
type = promote_integer(type);
*/
static statement_t *parse_while(void)
{
- eat(T_while);
+ statement_t *statement = allocate_statement_zero(STATEMENT_WHILE);
- statement_t *statement = allocate_statement_zero(STATEMENT_WHILE);
- statement->base.source_position = token.source_position;
+ eat(T_while);
PUSH_PARENT(statement);
expect('(');
add_anchor_token(')');
- statement->whiles.condition = parse_expression();
+ expression_t *const cond = parse_expression();
+ statement->whiles.condition = cond;
+ mark_decls_read(cond, NULL);
rem_anchor_token(')');
expect(')');
*/
static statement_t *parse_do(void)
{
- eat(T_do);
-
statement_t *statement = allocate_statement_zero(STATEMENT_DO_WHILE);
- statement->base.source_position = token.source_position;
- PUSH_PARENT(statement)
+ eat(T_do);
+
+ PUSH_PARENT(statement);
add_anchor_token(T_while);
statement->do_while.body = parse_loop_body(statement);
expect(T_while);
expect('(');
add_anchor_token(')');
- statement->do_while.condition = parse_expression();
+ expression_t *const cond = parse_expression();
+ statement->do_while.condition = cond;
+ mark_decls_read(cond, NULL);
rem_anchor_token(')');
expect(')');
expect(';');
*/
static statement_t *parse_for(void)
{
- eat(T_for);
+ statement_t *statement = allocate_statement_zero(STATEMENT_FOR);
- statement_t *statement = allocate_statement_zero(STATEMENT_FOR);
- statement->base.source_position = token.source_position;
+ eat(T_for);
PUSH_PARENT(statement);
- int top = environment_top();
- scope_t *last_scope = scope;
- set_scope(&statement->fors.scope);
+ size_t const top = environment_top();
+ scope_push(&statement->fors.scope);
expect('(');
add_anchor_token(')');
add_anchor_token(';');
expression_t *const init = parse_expression();
statement->fors.initialisation = init;
+ mark_decls_read(init, DECL_ANY);
if (warning.unused_value && !expression_has_effect(init)) {
warningf(&init->base.source_position,
"initialisation of 'for'-statement has no effect");
if (token.type != ';') {
add_anchor_token(';');
- statement->fors.condition = parse_expression();
+ expression_t *const cond = parse_expression();
+ statement->fors.condition = cond;
+ mark_decls_read(cond, NULL);
rem_anchor_token(';');
}
expect(';');
if (token.type != ')') {
expression_t *const step = parse_expression();
statement->fors.step = step;
+ mark_decls_read(step, DECL_ANY);
if (warning.unused_value && !expression_has_effect(step)) {
warningf(&step->base.source_position,
"step of 'for'-statement has no effect");
statement->fors.body = parse_loop_body(statement);
assert(scope == &statement->fors.scope);
- set_scope(last_scope);
+ scope_pop();
environment_pop_to(top);
POP_PARENT;
POP_PARENT;
rem_anchor_token(')');
assert(scope == &statement->fors.scope);
- set_scope(last_scope);
+ scope_pop();
environment_pop_to(top);
return create_invalid_statement();
*/
static statement_t *parse_goto(void)
{
- source_position_t source_position = token.source_position;
+ statement_t *statement = allocate_statement_zero(STATEMENT_GOTO);
eat(T_goto);
- statement_t *statement;
- if (c_mode & _GNUC && token.type == '*') {
+ if (GNU_MODE && token.type == '*') {
next_token();
expression_t *expression = parse_expression();
+ mark_decls_read(expression, NULL);
/* Argh: although documentation say the expression must be of type void *,
* gcc excepts anything that can be casted into void * without error */
if (type != type_error_type) {
if (!is_type_pointer(type) && !is_type_integer(type)) {
- errorf(&source_position, "cannot convert to a pointer type");
- } else if (type != type_void_ptr) {
- warningf(&source_position,
+ errorf(&expression->base.source_position,
+ "cannot convert to a pointer type");
+ } else if (warning.other && type != type_void_ptr) {
+ warningf(&expression->base.source_position,
"type of computed goto expression should be 'void*' not '%T'", type);
}
expression = create_implicit_cast(expression, type_void_ptr);
}
- statement = allocate_statement_zero(STATEMENT_GOTO);
- statement->base.source_position = source_position;
- statement->gotos.expression = expression;
+ statement->gotos.expression = expression;
} else {
if (token.type != T_IDENTIFIER) {
- if (c_mode & _GNUC)
+ if (GNU_MODE)
parse_error_expected("while parsing goto", T_IDENTIFIER, '*', NULL);
else
parse_error_expected("while parsing goto", T_IDENTIFIER, NULL);
- eat_statement();
+ eat_until_anchor();
goto end_error;
}
symbol_t *symbol = token.v.symbol;
next_token();
- statement = allocate_statement_zero(STATEMENT_GOTO);
- statement->base.source_position = source_position;
- statement->gotos.label = get_label(symbol);
+ statement->gotos.label = get_label(symbol);
}
/* remember the goto's in a list for later checking */
}
statement_t *statement = allocate_statement_zero(STATEMENT_CONTINUE);
- statement->base.source_position = token.source_position;
eat(T_continue);
expect(';');
}
statement_t *statement = allocate_statement_zero(STATEMENT_BREAK);
- statement->base.source_position = token.source_position;
eat(T_break);
expect(';');
}
statement_t *statement = allocate_statement_zero(STATEMENT_LEAVE);
- statement->base.source_position = token.source_position;
eat(T___leave);
expect(';');
*/
static statement_t *parse_return(void)
{
- statement_t *statement = allocate_statement_zero(STATEMENT_RETURN);
- statement->base.source_position = token.source_position;
-
eat(T_return);
+ statement_t *statement = allocate_statement_zero(STATEMENT_RETURN);
+
expression_t *return_value = NULL;
if (token.type != ';') {
return_value = parse_expression();
+ mark_decls_read(return_value, NULL);
}
const type_t *const func_type = current_function->type;
if (return_value != NULL) {
type_t *return_value_type = skip_typeref(return_value->base.type);
- if (is_type_atomic(return_type, ATOMIC_TYPE_VOID)
- && !is_type_atomic(return_value_type, ATOMIC_TYPE_VOID)) {
- warningf(&statement->base.source_position,
- "'return' with a value, in function returning void");
+ if (is_type_atomic(return_type, ATOMIC_TYPE_VOID) &&
+ !is_type_atomic(return_value_type, ATOMIC_TYPE_VOID)) {
+ if (warning.other) {
+ warningf(&statement->base.source_position,
+ "'return' with a value, in function returning void");
+ }
return_value = NULL;
} else {
assign_error_t error = semantic_assign(return_type, return_value);
return_value = create_implicit_cast(return_value, return_type);
}
/* check for returning address of a local var */
- if (return_value != NULL &&
+ if (warning.other &&
+ return_value != NULL &&
return_value->base.kind == EXPR_UNARY_TAKE_ADDRESS) {
const expression_t *expression = return_value->unary.value;
if (is_local_variable(expression)) {
"function returns address of local variable");
}
}
- } else {
- if (!is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
- warningf(&statement->base.source_position,
- "'return' without value, in function returning non-void");
- }
+ } else if (warning.other && !is_type_atomic(return_type, ATOMIC_TYPE_VOID)) {
+ warningf(&statement->base.source_position,
+ "'return' without value, in function returning non-void");
}
statement->returns.value = return_value;
{
statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION);
- statement->base.source_position = token.source_position;
-
declaration_t *before = last_declaration;
- parse_declaration(record_declaration);
+ if (GNU_MODE)
+ parse_external_declaration();
+ else
+ parse_declaration(record_declaration);
if (before == NULL) {
statement->declaration.declarations_begin = scope->declarations;
{
statement_t *statement = allocate_statement_zero(STATEMENT_EXPRESSION);
- statement->base.source_position = token.source_position;
expression_t *const expr = parse_expression();
statement->expression.expression = expr;
+ mark_decls_read(expr, DECL_ANY);
expect(';');
static statement_t *parse_ms_try_statment(void)
{
statement_t *statement = allocate_statement_zero(STATEMENT_MS_TRY);
- statement->base.source_position = token.source_position;
eat(T___try);
PUSH_PARENT(statement);
expect('(');
add_anchor_token(')');
expression_t *const expr = parse_expression();
+ mark_decls_read(expr, NULL);
type_t * type = skip_typeref(expr->base.type);
if (is_type_integer(type)) {
type = promote_integer(type);
static statement_t *parse_local_label_declaration(void) {
statement_t *statement = allocate_statement_zero(STATEMENT_DECLARATION);
- statement->base.source_position = token.source_position;
eat(T___label__);
do {
next_token();
} while (token.type == T___extension__);
+ bool old_gcc_extension = in_gcc_extension;
+ in_gcc_extension = true;
statement = parse_statement();
+ in_gcc_extension = old_gcc_extension;
break;
DECLARATION_START
case T_do: statement = parse_do(); break;
case T_for: statement = parse_for(); break;
case T_goto: statement = parse_goto(); break;
- case T_if: statement = parse_if (); break;
+ case T_if: statement = parse_if(); break;
case T_return: statement = parse_return(); break;
case T_switch: statement = parse_switch(); break;
case T_while: statement = parse_while(); break;
case T___builtin_islessequal:
case T___builtin_islessgreater:
case T___builtin_isunordered:
+ case T___builtin_inf:
+ case T___builtin_inff:
+ case T___builtin_infl:
case T___builtin_nan:
- case T___builtin_nand:
case T___builtin_nanf:
+ case T___builtin_nanl:
case T___builtin_offsetof:
case T___builtin_prefetch:
case T___builtin_va_arg:
static statement_t *parse_compound_statement(bool inside_expression_statement)
{
statement_t *statement = allocate_statement_zero(STATEMENT_COMPOUND);
- statement->base.source_position = token.source_position;
PUSH_PARENT(statement);
eat('{');
add_anchor_token('}');
- int top = environment_top();
- int top_local = local_label_top();
- scope_t *last_scope = scope;
- set_scope(&statement->compound.scope);
+ size_t const top = environment_top();
+ size_t const top_local = local_label_top();
+ scope_push(&statement->compound.scope);
statement_t **anchor = &statement->compound.statements;
bool only_decls_so_far = true;
- while (token.type != '}' && token.type != T_EOF) {
+ while (token.type != '}') {
+ if (token.type == T_EOF) {
+ errorf(&statement->base.source_position,
+ "EOF while parsing compound statement");
+ break;
+ }
statement_t *sub_statement = intern_parse_statement();
if (is_invalid_statement(sub_statement)) {
/* an error occurred. if we are at an anchor, return */
anchor = &sub_statement->base.next;
}
-
- if (token.type == '}') {
- next_token();
- } else {
- errorf(&statement->base.source_position,
- "end of file while looking for closing '}'");
- }
+ next_token();
/* look over all statements again to produce no effect warnings */
if (warning.unused_value) {
end_error:
rem_anchor_token('}');
assert(scope == &statement->compound.scope);
- set_scope(last_scope);
+ scope_pop();
environment_pop_to(top);
local_label_pop_to(top_local);
type_wchar_t_ptr = make_pointer_type(type_wchar_t, TYPE_QUALIFIER_NONE);
/* const version of wchar_t */
- type_const_wchar_t = allocate_type_zero(TYPE_TYPEDEF, &builtin_source_position);
+ type_const_wchar_t = allocate_type_zero(TYPE_TYPEDEF);
type_const_wchar_t->typedeft.declaration = type_wchar_t->typedeft.declaration;
type_const_wchar_t->base.qualifiers |= TYPE_QUALIFIER_CONST;
if (!warning.unused_function && !warning.unused_variable)
return;
- for (const declaration_t *decl = global_scope->declarations; decl != NULL; decl = decl->next) {
+ for (const declaration_t *decl = file_scope->declarations; decl != NULL; decl = decl->next) {
if (decl->used ||
decl->modifiers & DM_UNUSED ||
decl->modifiers & DM_USED ||
static void parse_global_asm(void)
{
+ statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
+
eat(T_asm);
expect('(');
- statement_t *statement = allocate_statement_zero(STATEMENT_ASM);
- statement->base.source_position = token.source_position;
- statement->asms.asm_text = parse_string_literals();
- statement->base.next = unit->global_asm;
- unit->global_asm = statement;
+ statement->asms.asm_text = parse_string_literals();
+ statement->base.next = unit->global_asm;
+ unit->global_asm = statement;
expect(')');
expect(';');
*/
static void parse_translation_unit(void)
{
+ add_anchor_token(T_EOF);
+
+#ifndef NDEBUG
+ unsigned char token_anchor_copy[T_LAST_TOKEN];
+ memcpy(token_anchor_copy, token_anchor_set, sizeof(token_anchor_copy));
+#endif
for (;;) {
#ifndef NDEBUG
bool anchor_leak = false;
- for (token_type_t i = 0; i != T_LAST_TOKEN; ++i) {
- unsigned char count = token_anchor_set[i];
+ for (int i = 0; i != T_LAST_TOKEN; ++i) {
+ unsigned char count = token_anchor_set[i] - token_anchor_copy[i];
if (count != 0) {
errorf(HERE, "Leaked anchor token %k %d times", i, count);
anchor_leak = true;
}
}
+ if (in_gcc_extension) {
+ errorf(HERE, "Leaked __extension__");
+ anchor_leak = true;
+ }
+
if (anchor_leak)
abort();
#endif
break;
case T_EOF:
+ rem_anchor_token(T_EOF);
return;
case ';':
- /* TODO error in strict mode */
- warningf(HERE, "stray ';' outside of function");
- next_token();
- break;
+ if (!strict_mode) {
+ if (warning.other)
+ warningf(HERE, "stray ';' outside of function");
+ next_token();
+ break;
+ }
+ /* FALLTHROUGH */
default:
errorf(HERE, "stray %K outside of function", &token);
assert(unit == NULL);
unit = allocate_ast_zero(sizeof(unit[0]));
- assert(global_scope == NULL);
- global_scope = &unit->scope;
+ assert(file_scope == NULL);
+ file_scope = &unit->scope;
assert(scope == NULL);
- set_scope(&unit->scope);
+ scope_push(&unit->scope);
initialize_builtin_types();
}
translation_unit_t *finish_parsing(void)
{
+ /* do NOT use scope_pop() here, this will crash, will it by hand */
assert(scope == &unit->scope);
- scope = NULL;
+ scope = NULL;
last_declaration = NULL;
- assert(global_scope == &unit->scope);
+ assert(file_scope == &unit->scope);
check_unused_globals();
- global_scope = NULL;
+ file_scope = NULL;
DEL_ARR_F(environment_stack);
DEL_ARR_F(label_stack);