[EXPR_CONDITIONAL] = sizeof(conditional_expression_t),
[EXPR_SELECT] = sizeof(select_expression_t),
[EXPR_ARRAY_ACCESS] = sizeof(array_access_expression_t),
- [EXPR_SIZEOF] = sizeof(sizeof_expression_t),
+ [EXPR_SIZEOF] = sizeof(typeprop_expression_t),
+ [EXPR_ALIGNOF] = sizeof(typeprop_expression_t),
[EXPR_CLASSIFY_TYPE] = sizeof(classify_type_expression_t),
[EXPR_FUNCTION] = sizeof(string_literal_expression_t),
[EXPR_PRETTY_FUNCTION] = sizeof(string_literal_expression_t),
declaration->type = type;
}
+static bool first_err = true;
+
+/**
+ * When called with first_err set, prints the name of the current function,
+ * else does noting.
+ */
+static void print_in_function(void) {
+ if (first_err) {
+ first_err = false;
+ diagnosticf("%s: In function '%Y':\n",
+ current_function->source_position.input_name,
+ current_function->symbol);
+ }
+}
+
/**
* Check if all labels are defined in the current function.
* Check if all labels are used in the current function.
*/
static void check_labels(void)
{
- bool first_err = true;
for (const goto_statement_t *goto_statement = goto_first;
goto_statement != NULL;
goto_statement = goto_statement->next) {
label->used = true;
if (label->source_position.input_name == NULL) {
- if (first_err) {
- first_err = false;
- diagnosticf("%s: In function '%Y':\n",
- current_function->source_position.input_name,
- current_function->symbol);
- }
+ print_in_function();
errorf(goto_statement->statement.source_position,
"label '%Y' used but not defined", label->symbol);
}
const declaration_t *label = label_statement->label;
if (! label->used) {
- if (first_err) {
- first_err = false;
- diagnosticf("%s: In function '%Y':\n",
- current_function->source_position.input_name,
- current_function->symbol);
- }
+ print_in_function();
warningf(label_statement->statement.source_position,
"label '%Y' defined but not used", label->symbol);
}
label_first = label_last = NULL;
}
+/**
+ * Check declarations of current_function for unused entities.
+ */
+static void check_declarations(void)
+{
+ if (warning.unused_parameter) {
+ const scope_t *scope = ¤t_function->scope;
+
+ const declaration_t *parameter = scope->declarations;
+ for (; parameter != NULL; parameter = parameter->next) {
+ if (! parameter->used) {
+ print_in_function();
+ warningf(parameter->source_position,
+ "unused parameter '%Y'", parameter->symbol);
+ }
+ }
+ }
+ if (warning.unused_variable) {
+ }
+}
+
static void parse_external_declaration(void)
{
/* function-definitions and declarations both start with declaration
current_function = declaration;
declaration->init.statement = parse_compound_statement();
+ first_err = true;
check_labels();
+ check_declarations();
assert(current_function == declaration);
current_function = old_current_function;
ref->declaration = declaration;
ref->expression.datatype = type;
+ /* this declaration is used */
+ declaration->used = true;
+
return expression;
}
expression_t *const expr = parse_assignment_expression();
if (expr->kind == EXPR_REFERENCE) {
declaration_t *const decl = expr->reference.declaration;
+ if (decl == NULL)
+ return create_invalid_expression();
if (decl->parent_scope == ¤t_function->scope &&
decl->next == NULL) {
expression->va_starte.parameter = decl;
type_t *const type_left = skip_typeref(orig_type_left);
type_t *const type_right = skip_typeref(orig_type_right);
- if(!is_type_floating(type_left) && !is_type_floating(type_right)) {
+ if(!is_type_float(type_left) && !is_type_float(type_right)) {
if (is_type_valid(type_left) && is_type_valid(type_right)) {
type_error_incompatible("invalid operands in comparison",
expression->base.source_position, orig_type_left, orig_type_right);
return expression;
}
-static expression_t *parse_alignof(void) {
- eat(T___alignof__);
-
- expression_t *expression
- = allocate_expression_zero(EXPR_ALIGNOF);
-
- expect('(');
- expression->alignofe.type = parse_typename();
- expect(')');
-
- expression->base.datatype = type_size_t;
- return expression;
-}
-
static expression_t *parse_primary_expression(void)
{
switch(token.type) {
return parse_builtin_constant();
case T___builtin_prefetch:
return parse_builtin_prefetch();
- case T___alignof__:
- return parse_alignof();
case T_assume:
return parse_assume();
return (expression_t*) array_access;
}
-static expression_t *parse_sizeof(unsigned precedence)
+static expression_t *parse_typeprop(expression_kind_t kind, unsigned precedence)
{
- eat(T_sizeof);
-
- sizeof_expression_t *sizeof_expression
- = allocate_ast_zero(sizeof(sizeof_expression[0]));
- sizeof_expression->expression.kind = EXPR_SIZEOF;
- sizeof_expression->expression.datatype = type_size_t;
+ expression_t *tp_expression
+ = allocate_expression_zero(kind);
+ tp_expression->base.datatype = type_size_t;
if(token.type == '(' && is_declaration_specifier(look_ahead(1), true)) {
next_token();
- sizeof_expression->type = parse_typename();
+ tp_expression->typeprop.type = parse_typename();
expect(')');
} else {
expression_t *expression = parse_sub_expression(precedence);
expression->base.datatype = revert_automatic_type_conversion(expression);
- sizeof_expression->type = expression->base.datatype;
- sizeof_expression->size_expression = expression;
+ tp_expression->typeprop.type = expression->base.datatype;
+ tp_expression->typeprop.tp_expression = expression;
}
- return (expression_t*) sizeof_expression;
+ return tp_expression;
+}
+
+static expression_t *parse_sizeof(unsigned precedence)
+{
+ eat(T_sizeof);
+ return parse_typeprop(EXPR_SIZEOF, precedence);
+}
+
+static expression_t *parse_alignof(unsigned precedence)
+{
+ eat(T___alignof__);
+ return parse_typeprop(EXPR_SIZEOF, precedence);
}
static expression_t *parse_select_expression(unsigned precedence,
/* TODO non-arithmetic types */
if(is_type_arithmetic(type_left) && is_type_arithmetic(type_right)) {
+ if (warning.sign_compare &&
+ (expression->expression.kind != EXPR_BINARY_EQUAL &&
+ expression->expression.kind != EXPR_BINARY_NOTEQUAL) &&
+ (is_type_signed(type_left) != is_type_signed(type_right))) {
+ warningf(expression->expression.source_position,
+ "comparison between signed and unsigned");
+ }
type_t *arithmetic_type = semantic_arithmetic(type_left, type_right);
expression->left = create_implicit_cast(left, arithmetic_type);
expression->right = create_implicit_cast(right, arithmetic_type);
if (warning.float_equal &&
(expression->expression.kind == EXPR_BINARY_EQUAL ||
expression->expression.kind == EXPR_BINARY_NOTEQUAL) &&
- is_type_floating(arithmetic_type)) {
+ is_type_float(arithmetic_type)) {
warningf(expression->expression.source_position,
"comparing floating point with == or != is unsafe");
}
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_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);
/* remember the labels's in a list for later checking */
if (label_last == NULL) {
- label_first = label_last = label_statement;
+ label_first = label_statement;
} else {
label_last->next = label_statement;
}
+ label_last = label_statement;
return (statement_t*) label_statement;
}
/* remember the goto's in a list for later checking */
if (goto_last == NULL) {
- goto_first = goto_last = statement;
+ goto_first = statement;
} else {
goto_last->next = statement;
}
+ goto_last = statement;
expect(';');
}
}
+/**
+ * Check if a given declaration represents a variable.
+ */
+static bool is_var_declaration(const declaration_t *declaration) {
+ switch ((storage_class_tag_t) declaration->storage_class) {
+ case STORAGE_CLASS_NONE:
+ case STORAGE_CLASS_EXTERN:
+ case STORAGE_CLASS_STATIC:
+ case STORAGE_CLASS_AUTO:
+ case STORAGE_CLASS_REGISTER:
+ case STORAGE_CLASS_THREAD:
+ case STORAGE_CLASS_THREAD_EXTERN:
+ case STORAGE_CLASS_THREAD_STATIC: {
+ const type_t *type = skip_typeref(declaration->type);
+ if(is_type_function(type)) {
+ return false;
+ } else {
+ return true;
+ }
+ }
+ default:
+ return false;
+ }
+}
+
/**
* Check if a given expression represents a local variable.
*/
return is_local_var_declaration(declaration);
}
+/**
+ * Check if a given expression represents a local variable and
+ * return its declaration then, else return NULL.
+ */
+declaration_t *expr_is_variable(const expression_t *expression)
+{
+ if (expression->base.kind != EXPR_REFERENCE) {
+ return NULL;
+ }
+ declaration_t *declaration = expression->reference.declaration;
+ if (is_var_declaration(declaration))
+ return declaration;
+ return NULL;
+}
+
/**
* Parse a return statement.
*/
type_wchar_t_ptr = make_pointer_type(type_wchar_t, TYPE_QUALIFIER_NONE);
}
+/**
+ * Check for unused global static functions and variables
+ */
+static void check_unused_globals(void)
+{
+ if (!warning.unused_function && !warning.unused_variable)
+ return;
+
+ for (const declaration_t *decl = global_scope->declarations; decl != NULL; decl = decl->next) {
+ if (decl->used || decl->storage_class != STORAGE_CLASS_STATIC)
+ continue;
+
+ type_t *const type = decl->type;
+ const char *s;
+ if (is_type_function(skip_typeref(type))) {
+ if (!warning.unused_function || decl->is_inline)
+ continue;
+
+ s = (decl->init.statement != NULL ? "defined" : "declared");
+ } else {
+ if (!warning.unused_variable)
+ continue;
+
+ s = "defined";
+ }
+
+ warningf(decl->source_position, "'%#T' %s but not used",
+ type, decl->symbol, s);
+ }
+}
+
/**
* Parse a translation unit.
*/
last_declaration = NULL;
assert(global_scope == &unit->scope);
+ check_unused_globals();
global_scope = NULL;
return unit;