static int lookahead_bufpos;
static stack_entry_t *environment_stack = NULL;
static stack_entry_t *label_stack = NULL;
-static context_t *global_context = NULL;
-static context_t *context = NULL;
+static scope_t *global_scope = NULL;
+static scope_t *scope = NULL;
static declaration_t *last_declaration = NULL;
static declaration_t *current_function = NULL;
static switch_statement_t *current_switch = NULL;
static statement_t *current_loop = NULL;
static goto_statement_t *goto_first = NULL;
static goto_statement_t *goto_last = NULL;
+static label_statement_t *label_first = NULL;
+static label_statement_t *label_last = NULL;
static struct obstack temp_obst;
/** The current source position. */
[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),
} \
next_token();
-static void set_context(context_t *new_context)
+static void set_scope(scope_t *new_scope)
{
- context = new_context;
+ scope = new_scope;
- last_declaration = new_context->declarations;
+ last_declaration = new_scope->declarations;
if(last_declaration != NULL) {
while(last_declaration->next != NULL) {
last_declaration = last_declaration->next;
static void environment_push(declaration_t *declaration)
{
assert(declaration->source_position.input_name != NULL);
- assert(declaration->parent_context != NULL);
+ assert(declaration->parent_scope != NULL);
stack_push(&environment_stack, declaration);
}
static void label_push(declaration_t *declaration)
{
- declaration->parent_context = ¤t_function->context;
+ declaration->parent_scope = ¤t_function->scope;
stack_push(&label_stack, declaration);
}
}
static initializer_t *parse_sub_initializer(type_t *type,
- expression_t *expression,
- type_t *expression_type);
+ expression_t *expression);
static initializer_t *parse_sub_initializer_elem(type_t *type)
{
if(token.type == '{') {
- return parse_sub_initializer(type, NULL, NULL);
+ return parse_sub_initializer(type, NULL);
}
- expression_t *expression = parse_assignment_expression();
- type_t *expression_type = skip_typeref(expression->base.datatype);
-
- return parse_sub_initializer(type, expression, expression_type);
+ expression_t *expression = parse_assignment_expression();
+ return parse_sub_initializer(type, expression);
}
static bool had_initializer_brace_warning;
}
static initializer_t *parse_sub_initializer(type_t *type,
- expression_t *expression,
- type_t *expression_type)
+ expression_t *expression)
{
if(is_type_scalar(type)) {
/* there might be extra {} hierarchies */
warningf(HERE, "braces around scalar initializer");
had_initializer_brace_warning = true;
}
- initializer_t *result = parse_sub_initializer(type, NULL, NULL);
+ initializer_t *result = parse_sub_initializer(type, NULL);
if(token.type == ',') {
next_token();
/* TODO: warn about excessive elements */
if(expression == NULL) {
sub = parse_sub_initializer_elem(element_type);
} else {
- sub = parse_sub_initializer(element_type, expression,
- expression_type);
+ sub = parse_sub_initializer(element_type, expression);
}
/* didn't match the subtypes -> try the parent type */
}
} else {
assert(is_type_compound(type));
- context_t *const context = &type->compound.declaration->context;
+ scope_t *const scope = &type->compound.declaration->scope;
if(token.type == '[') {
errorf(HERE,
skip_designator();
}
- declaration_t *first = context->declarations;
+ declaration_t *first = scope->declarations;
if(first == NULL)
return NULL;
type_t *first_type = first->type;
if(expression == NULL) {
sub = parse_sub_initializer_elem(first_type);
} else {
- sub = parse_sub_initializer(first_type, expression,expression_type);
+ sub = parse_sub_initializer(first_type, expression);
}
/* didn't match the subtypes -> try our parent type */
expect('}');
return result;
} else {
- result = parse_sub_initializer(type, NULL, NULL);
+ result = parse_sub_initializer(type, NULL);
}
return result;
(is_struct ? NAMESPACE_STRUCT : NAMESPACE_UNION);
declaration->source_position = token.source_position;
declaration->symbol = symbol;
- declaration->parent_context = context;
+ declaration->parent_scope = scope;
if (symbol != NULL) {
environment_push(declaration);
}
assert(symbol != NULL);
errorf(HERE, "multiple definition of '%s %Y'",
is_struct ? "struct" : "union", symbol);
- declaration->context.declarations = NULL;
+ declaration->scope.declarations = NULL;
}
declaration->init.is_defined = true;
- int top = environment_top();
- context_t *last_context = context;
- set_context(&declaration->context);
+ int top = environment_top();
+ scope_t *last_scope = scope;
+ set_scope(&declaration->scope);
parse_compound_type_entries();
parse_attributes();
- assert(context == &declaration->context);
- set_context(last_context);
+ assert(scope == &declaration->scope);
+ set_scope(last_scope);
environment_pop_to(top);
}
declaration->namespc = NAMESPACE_ENUM;
declaration->source_position = token.source_position;
declaration->symbol = symbol;
- declaration->parent_context = context;
+ declaration->parent_scope = scope;
}
type_t *const type = allocate_type_zero(TYPE_ENUM);
declaration_t *parameters = parse_parameters(&type->function);
if(declaration != NULL) {
- declaration->context.declarations = parameters;
+ declaration->scope.declarations = parameters;
}
construct_function_type_t *construct_function_type =
if (last_declaration != NULL) {
last_declaration->next = declaration;
} else {
- context->declarations = declaration;
+ scope->declarations = declaration;
}
last_declaration = declaration;
return declaration;
}
+/**
+ * Check if the declaration of main is suspicious. main should be a
+ * function with external linkage, returning int, taking either zero
+ * arguments, two, or three arguments of appropriate types, ie.
+ *
+ * int main([ int argc, char **argv [, char **env ] ]).
+ *
+ * @param decl the declaration to check
+ * @param type the function type of the declaration
+ */
+static void check_type_of_main(const declaration_t *const decl, const function_type_t *const func_type)
+{
+ if (decl->storage_class == STORAGE_CLASS_STATIC) {
+ warningf(decl->source_position, "'main' is normally a non-static function");
+ }
+ if (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);
+ }
+ const function_parameter_t *parm = func_type->parameters;
+ if (parm != NULL) {
+ type_t *const first_type = parm->type;
+ if (!types_compatible(skip_typeref(first_type), type_int)) {
+ warningf(decl->source_position, "first argument of 'main' should be 'int', but is '%T'", first_type);
+ }
+ parm = parm->next;
+ if (parm != NULL) {
+ type_t *const second_type = parm->type;
+ if (!types_compatible(skip_typeref(second_type), type_char_ptr_ptr)) {
+ warningf(decl->source_position, "second argument of 'main' should be 'char**', but is '%T'", second_type);
+ }
+ parm = parm->next;
+ if (parm != NULL) {
+ type_t *const third_type = parm->type;
+ if (!types_compatible(skip_typeref(third_type), type_char_ptr_ptr)) {
+ warningf(decl->source_position, "third argument of 'main' should be 'char**', but is '%T'", third_type);
+ }
+ parm = parm->next;
+ if (parm != NULL) {
+ warningf(decl->source_position, "'main' takes only zero, two or three arguments");
+ }
+ }
+ } else {
+ warningf(decl->source_position, "'main' takes only zero, two or three arguments");
+ }
+ }
+}
+
+/**
+ * Check if a symbol is the equal to "main".
+ */
+static bool is_sym_main(const symbol_t *const sym)
+{
+ return strcmp(sym->string, "main") == 0;
+}
+
static declaration_t *internal_record_declaration(
declaration_t *const declaration,
const bool is_function_definition)
const symbol_t *const symbol = declaration->symbol;
const namespace_t namespc = (namespace_t)declaration->namespc;
- const type_t *const type = skip_typeref(declaration->type);
+ type_t *const orig_type = declaration->type;
+ const type_t *const type = skip_typeref(orig_type);
if (is_type_function(type) &&
type->function.unspecified_parameters &&
warning.strict_prototypes) {
warningf(declaration->source_position,
"function declaration '%#T' is not a prototype",
- type, declaration->symbol);
+ orig_type, declaration->symbol);
+ }
+
+ if (is_function_definition && warning.main && is_sym_main(symbol)) {
+ check_type_of_main(declaration, &type->function);
}
declaration_t *const previous_declaration = get_declaration(symbol, namespc);
assert(declaration != previous_declaration);
if (previous_declaration != NULL) {
- if (previous_declaration->parent_context == context) {
+ if (previous_declaration->parent_scope == scope) {
/* can happen for K&R style declarations */
if(previous_declaration->type == NULL) {
previous_declaration->type = declaration->type;
if (!types_compatible(type, prev_type)) {
errorf(declaration->source_position,
"declaration '%#T' is incompatible with previous declaration '%#T'",
- type, symbol, previous_declaration->type, symbol);
+ orig_type, symbol, previous_declaration->type, symbol);
errorf(previous_declaration->source_position, "previous declaration of '%Y' was here", symbol);
} else {
unsigned old_storage_class = previous_declaration->storage_class;
case STORAGE_CLASS_EXTERN:
if (is_function_definition) {
if (warning.missing_prototypes &&
- prev_type->function.unspecified_parameters) {
- warningf(declaration->source_position, "no previous prototype for '%#T'", type, symbol);
+ prev_type->function.unspecified_parameters &&
+ !is_sym_main(symbol)) {
+ warningf(declaration->source_position, "no previous prototype for '%#T'", orig_type, symbol);
}
} else if (new_storage_class == STORAGE_CLASS_NONE) {
new_storage_class = STORAGE_CLASS_EXTERN;
}
return previous_declaration;
}
- } else if (is_function_definition &&
- declaration->storage_class != STORAGE_CLASS_STATIC) {
- if (warning.missing_prototypes) {
- warningf(declaration->source_position, "no previous prototype for '%#T'", type, symbol);
- } else if (warning.missing_declarations) {
- warningf(declaration->source_position, "no previous declaration for '%#T'", type, symbol);
+ } else if (is_function_definition) {
+ if (declaration->storage_class != STORAGE_CLASS_STATIC) {
+ if (warning.missing_prototypes && !is_sym_main(symbol)) {
+ warningf(declaration->source_position, "no previous prototype for '%#T'", orig_type, symbol);
+ } else if (warning.missing_declarations && !is_sym_main(symbol)) {
+ warningf(declaration->source_position, "no previous declaration for '%#T'", orig_type, symbol);
+ }
}
+ } else if (warning.missing_declarations &&
+ scope == global_scope &&
+ !is_type_function(type) && (
+ declaration->storage_class == STORAGE_CLASS_NONE ||
+ declaration->storage_class == STORAGE_CLASS_THREAD
+ )) {
+ warningf(declaration->source_position, "no previous declaration for '%#T'", orig_type, symbol);
}
- assert(declaration->parent_context == NULL);
+ assert(declaration->parent_scope == NULL);
assert(declaration->symbol != NULL);
- assert(context != NULL);
+ assert(scope != NULL);
- declaration->parent_context = context;
+ declaration->parent_scope = scope;
environment_push(declaration);
return append_declaration(declaration);
declaration_t *previous_declaration = get_declaration(symbol, namespc);
if(previous_declaration == NULL ||
- previous_declaration->parent_context != context) {
+ previous_declaration->parent_scope != scope) {
errorf(HERE, "expected declaration of a function parameter, found '%Y'",
symbol);
return declaration;
if(previous_declaration->type == NULL) {
previous_declaration->type = declaration->type;
previous_declaration->storage_class = declaration->storage_class;
- previous_declaration->parent_context = context;
+ previous_declaration->parent_scope = scope;
return previous_declaration;
} else {
return record_declaration(declaration);
return;
/* push function parameters */
- int top = environment_top();
- context_t *last_context = context;
- set_context(&declaration->context);
+ int top = environment_top();
+ scope_t *last_scope = scope;
+ set_scope(&declaration->scope);
- declaration_t *parameter = declaration->context.declarations;
+ declaration_t *parameter = declaration->scope.declarations;
for( ; parameter != NULL; parameter = parameter->next) {
- assert(parameter->parent_context == NULL);
- parameter->parent_context = context;
+ assert(parameter->parent_scope == NULL);
+ parameter->parent_scope = scope;
environment_push(parameter);
}
}
/* pop function parameters */
- assert(context == &declaration->context);
- set_context(last_context);
+ assert(scope == &declaration->scope);
+ set_scope(last_scope);
environment_pop_to(top);
/* update function type */
function_parameter_t *parameters = NULL;
function_parameter_t *last_parameter = NULL;
- declaration_t *parameter_declaration = declaration->context.declarations;
+ declaration_t *parameter_declaration = declaration->scope.declarations;
for( ; parameter_declaration != NULL;
parameter_declaration = parameter_declaration->next) {
type_t *parameter_type = parameter_declaration->type;
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_for_missing_labels(void)
+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) {
- const declaration_t *label = goto_statement->label;
-
- 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);
- }
- errorf(goto_statement->statement.source_position,
- "label '%Y' used but not defined", label->symbol);
+ goto_statement != NULL;
+ goto_statement = goto_statement->next) {
+ declaration_t *label = goto_statement->label;
+
+ label->used = true;
+ if (label->source_position.input_name == NULL) {
+ print_in_function();
+ errorf(goto_statement->statement.source_position,
+ "label '%Y' used but not defined", label->symbol);
}
}
goto_first = goto_last = NULL;
+
+ if (warning.unused_label) {
+ for (const label_statement_t *label_statement = label_first;
+ label_statement != NULL;
+ label_statement = label_statement->next) {
+ const declaration_t *label = label_statement->label;
+
+ if (! label->used) {
+ 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)
declaration_t *const declaration = record_function_definition(ndeclaration);
if(ndeclaration != declaration) {
- declaration->context = ndeclaration->context;
+ declaration->scope = ndeclaration->scope;
}
type = skip_typeref(declaration->type);
- /* push function parameters and switch context */
- int top = environment_top();
- context_t *last_context = context;
- set_context(&declaration->context);
+ /* push function parameters and switch scope */
+ int top = environment_top();
+ scope_t *last_scope = scope;
+ set_scope(&declaration->scope);
- declaration_t *parameter = declaration->context.declarations;
+ declaration_t *parameter = declaration->scope.declarations;
for( ; parameter != NULL; parameter = parameter->next) {
- if(parameter->parent_context == &ndeclaration->context) {
- parameter->parent_context = context;
+ if(parameter->parent_scope == &ndeclaration->scope) {
+ parameter->parent_scope = scope;
}
- assert(parameter->parent_context == NULL
- || parameter->parent_context == context);
- parameter->parent_context = context;
+ assert(parameter->parent_scope == NULL
+ || parameter->parent_scope == scope);
+ parameter->parent_scope = scope;
environment_push(parameter);
}
current_function = declaration;
declaration->init.statement = parse_compound_statement();
- check_for_missing_labels();
+ first_err = true;
+ check_labels();
+ check_declarations();
assert(current_function == declaration);
current_function = old_current_function;
}
end_of_parse_external_declaration:
- assert(context == &declaration->context);
- set_context(last_context);
+ assert(scope == &declaration->scope);
+ set_scope(last_scope);
environment_pop_to(top);
}
declaration->type = type;
declaration->symbol = symbol;
declaration->source_position = source_position;
- declaration->parent_context = global_context;
+ declaration->parent_scope = global_scope;
- context_t *old_context = context;
- set_context(global_context);
+ scope_t *old_scope = scope;
+ set_scope(global_scope);
environment_push(declaration);
- /* prepend the declaration to the global declarations list */
- declaration->next = context->declarations;
- context->declarations = declaration;
+ /* prepends the declaration to the global declarations list */
+ declaration->next = scope->declarations;
+ scope->declarations = declaration;
- assert(context == global_context);
- set_context(old_context);
+ assert(scope == global_scope);
+ set_scope(old_scope);
return declaration;
}
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->parent_context == ¤t_function->context &&
+ if (decl == NULL)
+ return create_invalid_expression();
+ if (decl->parent_scope == ¤t_function->scope &&
decl->next == NULL) {
expression->va_starte.parameter = decl;
expect(')');
panic("invalid compare builtin found");
break;
}
+ expression->base.source_position = HERE;
next_token();
expect('(');
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",
- token.source_position, orig_type_left, orig_type_right);
+ expression->base.source_position, orig_type_left, orig_type_right);
}
} else {
semantic_comparison(&expression->binary);
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,
return create_invalid_expression();
}
- declaration_t *iter = declaration->context.declarations;
+ declaration_t *iter = declaration->scope.declarations;
for( ; iter != NULL; iter = iter->next) {
if(iter->symbol == symbol) {
break;
for( ; parameter != NULL && argument != NULL;
parameter = parameter->next, argument = argument->next) {
type_t *expected_type = parameter->type;
- /* TODO report context in error messages */
+ /* TODO report scope in error messages */
expression_t *const arg_expr = argument->expression;
type_t *const res_type = semantic_assign(expected_type, arg_expr, "function call");
if (res_type == NULL) {
{
type_t *const orig_type = expression->value->base.datatype;
type_t *const type = skip_typeref(orig_type);
+ /* TODO !is_type_real && !is_type_pointer */
if(!is_type_arithmetic(type) && type->kind != TYPE_POINTER) {
if (is_type_valid(type)) {
/* TODO: improve error message */
}
}
+/**
+ * Check the semantics of comparison expressions.
+ *
+ * @param expression The expression to check.
+ */
static void semantic_comparison(binary_expression_t *expression)
{
expression_t *left = expression->left;
/* 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);
expression->expression.datatype = arithmetic_type;
+ if (warning.float_equal &&
+ (expression->expression.kind == EXPR_BINARY_EQUAL ||
+ expression->expression.kind == EXPR_BINARY_NOTEQUAL) &&
+ is_type_float(arithmetic_type)) {
+ warningf(expression->expression.source_position,
+ "comparing floating point with == or != is unsafe");
+ }
} else if (is_type_pointer(type_left) && is_type_pointer(type_right)) {
/* TODO check compatibility */
} else if (is_type_pointer(type_left)) {
expression->left = create_implicit_cast(left, type_right);
} else if (is_type_valid(type_left) && is_type_valid(type_right)) {
type_error_incompatible("invalid operands in comparison",
- token.source_position, type_left, type_right);
+ expression->expression.source_position,
+ type_left, type_right);
}
expression->expression.datatype = type_int;
}
*/
static bool has_const_fields(const compound_type_t *type)
{
- const context_t *context = &type->declaration->context;
- const declaration_t *declaration = context->declarations;
+ const scope_t *scope = &type->declaration->scope;
+ const declaration_t *declaration = scope->declarations;
for (; declaration != NULL; declaration = declaration->next) {
if (declaration->namespc != NAMESPACE_NORMAL)
case EXPR_BINARY_BITWISE_AND: return false;
case EXPR_BINARY_BITWISE_OR: return false;
case EXPR_BINARY_BITWISE_XOR: return false;
- case EXPR_BINARY_LOGICAL_AND: return false;
- case EXPR_BINARY_LOGICAL_OR: return false;
case EXPR_BINARY_SHIFTLEFT: return false;
case EXPR_BINARY_SHIFTRIGHT: return false;
case EXPR_BINARY_ASSIGN: return true;
case EXPR_BINARY_BITWISE_AND_ASSIGN: return true;
case EXPR_BINARY_BITWISE_XOR_ASSIGN: return true;
case EXPR_BINARY_BITWISE_OR_ASSIGN: return true;
+ case EXPR_BINARY_LOGICAL_AND:
+ case EXPR_BINARY_LOGICAL_OR:
case EXPR_BINARY_COMMA:
return expression_has_effect(expr->binary.right);
expression_t *left) \
{ \
eat(token_type); \
+ source_position_t pos = HERE; \
\
expression_t *right = parse_sub_expression(precedence + lr); \
\
expression_t *binexpr = allocate_expression_zero(binexpression_type); \
+ binexpr->base.source_position = pos; \
binexpr->binary.left = left; \
binexpr->binary.right = right; \
sfunc(&binexpr->binary); \
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);
/* if we found a label in the same function, then we already created the
* declaration */
if(candidate != NULL
- && candidate->parent_context == ¤t_function->context) {
+ && candidate->parent_scope == ¤t_function->scope) {
return candidate;
}
errorf(HERE, "label at end of compound statement");
return (statement_t*) label_statement;
} else {
- label_statement->label_statement = parse_statement();
+ if (token.type == ';') {
+ /* eat an empty statement here, to avoid the warning about an empty
+ * after a label. label:; is commonly used to have a label before
+ * a }. */
+ next_token();
+ } else {
+ label_statement->label_statement = parse_statement();
+ }
+ }
+
+ /* remember the labels's in a list for later checking */
+ if (label_last == NULL) {
+ label_first = label_statement;
+ } else {
+ label_last->next = label_statement;
}
+ label_last = label_statement;
return (statement_t*) label_statement;
}
expect('(');
- int top = environment_top();
- context_t *last_context = context;
- set_context(&statement->context);
+ int top = environment_top();
+ scope_t *last_scope = scope;
+ set_scope(&statement->scope);
if(token.type != ';') {
if(is_declaration_specifier(&token, false)) {
expect(')');
statement->body = parse_loop_body((statement_t*)statement);
- assert(context == &statement->context);
- set_context(last_context);
+ assert(scope == &statement->scope);
+ set_scope(last_scope);
environment_pop_to(top);
return (statement_t*) 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.
*/
parse_declaration(record_declaration);
if(before == NULL) {
- statement->declaration.declarations_begin = context->declarations;
+ statement->declaration.declarations_begin = scope->declarations;
} else {
statement->declaration.declarations_begin = before->next;
}
break;
case ';':
+ if (warning.empty_statement) {
+ warningf(HERE, "statement is empty");
+ }
next_token();
statement = NULL;
break;
eat('{');
- int top = environment_top();
- context_t *last_context = context;
- set_context(&compound_statement->context);
+ int top = environment_top();
+ scope_t *last_scope = scope;
+ set_scope(&compound_statement->scope);
statement_t *last_statement = NULL;
errorf(compound_statement->statement.source_position, "end of file while looking for closing '}'");
}
- assert(context == &compound_statement->context);
- set_context(last_context);
+ assert(scope == &compound_statement->scope);
+ set_scope(last_scope);
environment_pop_to(top);
return (statement_t*) compound_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.
*/
{
translation_unit_t *unit = allocate_ast_zero(sizeof(unit[0]));
- assert(global_context == NULL);
- global_context = &unit->context;
+ assert(global_scope == NULL);
+ global_scope = &unit->scope;
- assert(context == NULL);
- set_context(&unit->context);
+ assert(scope == NULL);
+ set_scope(&unit->scope);
initialize_builtin_types();
}
}
- assert(context == &unit->context);
- context = NULL;
+ assert(scope == &unit->scope);
+ scope = NULL;
last_declaration = NULL;
- assert(global_context == &unit->context);
- global_context = NULL;
+ assert(global_scope == &unit->scope);
+ check_unused_globals();
+ global_scope = NULL;
return unit;
}