static ir_node *current_switch_cond;
static bool saw_default_label;
static declaration_t **all_labels;
+static declaration_t **inner_functions;
+static int inner_function_idx;
static ir_node *ijmp_list;
static bool constant_folding;
DECLARATION_KIND_ENUM_ENTRY,
DECLARATION_KIND_COMPOUND_TYPE_INCOMPLETE,
DECLARATION_KIND_COMPOUND_TYPE_COMPLETE,
- DECLARATION_KIND_TYPE
+ DECLARATION_KIND_TYPE,
+ DECLARATION_KIND_INNER_FUNCTION
} declaration_kind_t;
static ir_type *get_ir_type(type_t *type);
static ir_type *get_ir_type_incomplete(type_t *type);
static int count_decls_in_stmts(const statement_t *stmt);
+static void enqueue_inner_function(declaration_t *declaration) {
+ if (inner_functions == NULL) {
+ inner_functions = NEW_ARR_F(declaration_t *, 16);
+ inner_functions[0] = declaration;
+ inner_function_idx = 1;
+ } else {
+ int size = ARR_LEN(inner_functions);
+ if (inner_function_idx >= size) {
+ ARR_RESIZE(declaration_t *, inner_functions, size + 16);
+ }
+ inner_functions[inner_function_idx++] = declaration;
+ }
+}
+
+static declaration_t *next_inner_function(void) {
+ if (inner_function_idx == 0)
+ return 0;
+ return inner_functions[--inner_function_idx];
+}
+
ir_node *uninitialized_local_var(ir_graph *irg, ir_mode *mode, int pos)
{
const declaration_t *declaration = get_irg_loc_description(irg, pos);
*/
static ir_entity *get_function_entity(declaration_t *declaration)
{
- if (declaration->declaration_kind == DECLARATION_KIND_FUNCTION)
+ if (declaration->declaration_kind == DECLARATION_KIND_FUNCTION ||
+ declaration->declaration_kind == DECLARATION_KIND_INNER_FUNCTION)
return declaration->v.entity;
assert(declaration->declaration_kind == DECLARATION_KIND_UNKNOWN);
case DECLARATION_KIND_ENUM_ENTRY: {
ir_mode *const mode = get_ir_mode(type);
- return new_Const(mode, declaration->v.enum_val);
+ if (ref->is_outer_ref) {
+ /* reference to an outer variable */
+ panic("Outer variable reference not implemented");
+ } else {
+ return new_Const(mode, declaration->v.enum_val);
+ }
}
case DECLARATION_KIND_LOCAL_VARIABLE: {
ir_mode *const mode = get_ir_mode(type);
return create_symconst(dbgi, mode, declaration->v.entity);
}
+ case DECLARATION_KIND_INNER_FUNCTION: {
+ ir_mode *const mode = get_ir_mode(type);
+ if (! declaration->goto_to_outer && !declaration->need_closure) {
+ /* inner function not using the closure */
+ return create_symconst(dbgi, mode, declaration->v.entity);
+ } else {
+ /* TODO: need trampoline here */
+ panic("Trampoline code not implemented");
+ return create_symconst(dbgi, mode, declaration->v.entity);
+ }
+ }
case DECLARATION_KIND_GLOBAL_VARIABLE: {
ir_node *const addr = get_global_var_address(dbgi, declaration);
return deref_address(dbgi, declaration->type, addr);
case STORAGE_CLASS_REGISTER:
if (is_type_function(type)) {
if (declaration->init.statement != NULL) {
- panic("nested functions not supported yet");
+ get_function_entity(declaration);
+ declaration->declaration_kind = DECLARATION_KIND_INNER_FUNCTION;
+ enqueue_inner_function(declaration);
} else {
get_function_entity(declaration);
}
case DECLARATION_KIND_FUNCTION:
case DECLARATION_KIND_TYPE:
case DECLARATION_KIND_ENUM_ENTRY:
+ case DECLARATION_KIND_INNER_FUNCTION:
return;
case DECLARATION_KIND_UNKNOWN:
- panic("can't initialize unknwon declaration");
+ panic("can't initialize unknown declaration");
}
panic("invalid declaration kind");
}
set_irn_link(ijmp, ijmp_list);
ijmp_list = ijmp;
} else {
- ir_node *block = get_label_block(statement->label);
- ir_node *jmp = new_Jmp();
- add_immBlock_pred(block, jmp);
+ if (statement->outer_fkt_jmp) {
+ /* TODO: this is a outer function jmp */
+ panic("outer function jump not implemented");
+ } else {
+ ir_node *block = get_label_block(statement->label);
+ ir_node *jmp = new_Jmp();
+ add_immBlock_pred(block, jmp);
+ }
}
set_cur_block(NULL);
}
type_t *type = declaration->type;
if (type->kind == TYPE_FUNCTION) {
create_function(declaration);
+ declaration_t *inner;
+ for (inner = next_inner_function(); inner != NULL;
+ inner = next_inner_function())
+ create_function(inner);
} else {
assert(declaration->declaration_kind
== DECLARATION_KIND_GLOBAL_VARIABLE);
struct reference_expression_t {
expression_base_t base;
declaration_t *declaration;
+ bool is_outer_ref; /**< Set, if this referenced a variable
+ outside of an inner function */
};
struct call_argument_t {
unsigned int is_inline : 1;
unsigned int used : 1; /**< Set if the declaration is used. */
unsigned int implicit : 1; /**< Set for implicit (not found in source code) declarations. */
+ unsigned int need_closure : 1; /**< Inner function needs closure. */
+ unsigned int goto_to_outer : 1; /**< Inner function has goto to outer function. */
type_t *type;
il_size_t offset; /**< The offset of this member inside a compound. */
symbol_t *symbol;
struct goto_statement_t {
statement_base_t base;
- declaration_t *label; /**< The destination label. */
- expression_t *expression; /**< The expression for an assigned goto. */
- goto_statement_t *next; /**< links all goto statements of a function */
+ declaration_t *label; /**< The destination label. */
+ expression_t *expression; /**< The expression for an assigned goto. */
+ goto_statement_t *next; /**< links all goto statements of a function */
+ bool outer_fkt_jmp; /**< Set if this goto jump to an outer function. */
};
struct case_label_statement_t {
}
}
- type_t *type = declaration->type;
+ type_t *orig_type = declaration->type;
/* we always do the auto-type conversions; the & and sizeof parser contains
* code to revert this! */
- type = automatic_type_conversion(type);
+ type_t *type = automatic_type_conversion(orig_type);
ref->declaration = declaration;
ref->base.type = type;
declaration->used = true;
if (declaration->parent_scope != global_scope &&
- declaration->parent_scope->depth < current_function->scope.depth) {
+ declaration->parent_scope->depth < current_function->scope.depth &&
+ is_type_valid(orig_type) && !is_type_function(orig_type)) {
/* access of a variable from an outer function */
- declaration->address_taken = true;
+ declaration->address_taken = true;
+ ref->is_outer_ref = true;
+ current_function->need_closure = true;
}
/* check for deprecated functions */
candidate = get_declaration(symbol, NAMESPACE_LOCAL_LABEL);
/* if we found a local label, we already created the declaration */
if (candidate != NULL) {
- assert(candidate->parent_scope == scope);
+ if (candidate->parent_scope != scope) {
+ assert(candidate->parent_scope->depth < scope->depth);
+ current_function->goto_to_outer = true;
+ }
return candidate;
}
statement = allocate_statement_zero(STATEMENT_GOTO);
statement->base.source_position = source_position;
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 */