#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"
((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;
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);
* 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;
}
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();
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;
/* 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;
}
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 == '{') {
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;
}
#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;
}
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(')');
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;
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();
}
if (type_specifiers & SPECIFIER_COMPLEX) {
- type = allocate_type_zero(TYPE_COMPLEX, &builtin_source_position);
+ type = allocate_type_zero(TYPE_COMPLEX);
type->complex.akind = atomic_type;
} else if (type_specifiers & SPECIFIER_IMAGINARY) {
- type = allocate_type_zero(TYPE_IMAGINARY, &builtin_source_position);
+ 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;
{
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 *last;
if (declaration != NULL) {
declaration->scope.declarations = parameters;
declaration->scope.last_declaration = last;
- declaration->scope.is_parameter = true;
}
construct_function_type_t *construct_function_type =
} else if (is_type_array(skipped_return_type)) {
errorf(HERE, "function returning array is not allowed");
} else {
- if (skipped_return_type->base.qualifiers != 0) {
+ if (skipped_return_type->base.qualifiers != 0 && warning.other) {
warningf(HERE,
"type qualifiers in return type of function type are meaningless");
}
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) {
assert(declaration != previous_declaration);
if (previous_declaration != NULL &&
- previous_declaration->parent_scope->is_parameter &&
+ 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)",
{
eat(';');
- if (specifiers->declared_storage_class != STORAGE_CLASS_NONE) {
- warningf(&specifiers->source_position,
- "useless storage class in empty declaration");
- }
+ if (warning.other) {
+ if (specifiers->declared_storage_class != STORAGE_CLASS_NONE) {
+ warningf(&specifiers->source_position,
+ "useless storage class in empty declaration");
+ }
- 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");
+ 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(&specifiers->source_position, "empty declaration");
- break;
+ default:
+ warningf(&specifiers->source_position, "empty declaration");
+ break;
+ }
}
#ifdef RECORD_EMPTY_DECLARATIONS
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);
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)
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)) {
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;
-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;
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;
is_type_valid(orig_type) && !is_type_function(orig_type)) {
/* access of a variable from an outer function */
declaration->address_taken = true;
- ref->is_outer_ref = true;
current_function->need_closure = true;
}
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;
}
}
-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);
tp_expression->base.type = type_size_t;
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;
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);
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 {
if (is_type_valid(other_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__);
bool old_gcc_extension = in_gcc_extension;
in_gcc_extension = true;
- expression_t *expression = parse_sub_expression(precedence);
+ 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;
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;
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(')');
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");
}
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 {
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(')');
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);
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(')');
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(';');
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");
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 (!is_type_pointer(type) && !is_type_integer(type)) {
errorf(&expression->base.source_position,
"cannot convert to a pointer type");
- } else if (type != type_void_ptr) {
+ } else if (warning.other && type != type_void_ptr) {
warningf(&expression->base.source_position,
"type of computed goto expression should be 'void*' not '%T'", type);
}
next_token();
statement->gotos.label = get_label(symbol);
-
- if (statement->gotos.label->parent_scope->depth < current_function->scope.depth) {
- statement->gotos.outer_fkt_jmp = true;
- }
}
/* remember the goto's in a list for later checking */
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;
expression_t *const expr = parse_expression();
statement->expression.expression = expr;
+ mark_decls_read(expr, DECL_ANY);
expect(';');
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);
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;
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;
case ';':
if (!strict_mode) {
- warningf(HERE, "stray ';' outside of function");
+ if (warning.other)
+ warningf(HERE, "stray ';' outside of function");
next_token();
break;
}