+2018-01-09 Cherry Zhang <cherryyz@google.com>
+
+ * go-gcc.cc (local_variable): Add decl_var parameter.
+
2018-01-09 Cherry Zhang <cherryyz@google.com>
* lang.opt (fgo-debug-escape-hash): New option.
global_variable_set_init(Bvariable*, Bexpression*);
Bvariable*
- local_variable(Bfunction*, const std::string&, Btype*, bool,
+ local_variable(Bfunction*, const std::string&, Btype*, Bvariable*, bool,
Location);
Bvariable*
Bvariable*
Gcc_backend::local_variable(Bfunction* function, const std::string& name,
- Btype* btype, bool is_address_taken,
- Location location)
+ Btype* btype, Bvariable* decl_var,
+ bool is_address_taken, Location location)
{
tree type_tree = btype->get_tree();
if (type_tree == error_mark_node)
TREE_USED(decl) = 1;
if (is_address_taken)
TREE_ADDRESSABLE(decl) = 1;
+ if (decl_var != NULL)
+ {
+ DECL_HAS_VALUE_EXPR_P(decl) = 1;
+ SET_DECL_VALUE_EXPR(decl, decl_var->get_decl());
+ }
go_preserve_from_gc(decl);
return new Bvariable(decl);
}
-0445dc01fd75325ff99f839cfaab29cb9f2a1f97
+29e821cf865aa6ee06cee9dae9823295202b1a61
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
// Create a local variable. The frontend will create the local
// variables first, and then create the block which contains them.
// FUNCTION is the function in which the variable is defined. NAME
- // is the name of the variable. TYPE is the type. IS_ADDRESS_TAKEN
- // is true if the address of this variable is taken (this implies
- // that the address does not escape the function, as otherwise the
- // variable would be on the heap). LOCATION is where the variable
- // is defined. For each local variable the frontend will call
- // init_statement to set the initial value.
+ // is the name of the variable. TYPE is the type. DECL_VAR, if not
+ // null, gives the location at which the value of this variable may
+ // be found, typically used to create an inner-scope reference to an
+ // outer-scope variable, to extend the lifetime of the variable beyond
+ // the inner scope. IS_ADDRESS_TAKEN is true if the address of this
+ // variable is taken (this implies that the address does not escape
+ // the function, as otherwise the variable would be on the heap).
+ // LOCATION is where the variable is defined. For each local variable
+ // the frontend will call init_statement to set the initial value.
virtual Bvariable*
local_variable(Bfunction* function, const std::string& name, Btype* type,
- bool is_address_taken, Location location) = 0;
+ Bvariable* decl_var, bool is_address_taken, Location location) = 0;
// Create a function parameter. This is an incoming parameter, not
// a result parameter (result parameters are treated as local
return TRAVERSE_CONTINUE;
}
+ if (!no->var_value()->is_parameter()
+ && !no->var_value()->is_receiver()
+ && !no->var_value()->is_closure()
+ && no->var_value()->is_non_escaping_address_taken()
+ && !no->var_value()->is_in_heap()
+ && no->var_value()->toplevel_decl() == NULL)
+ {
+ // Local variable that has address taken but not escape.
+ // It needs to be live beyond its lexical scope. So we
+ // create a top-level declaration for it.
+ // No need to do it if it is already in the top level.
+ Block* top_block = function_->func_value()->block();
+ if (top_block->bindings()->lookup_local(no->name()) != no)
+ {
+ Variable* var = no->var_value();
+ Temporary_statement* ts =
+ Statement::make_temporary(var->type(), NULL, var->location());
+ ts->set_is_address_taken();
+ top_block->add_statement_at_front(ts);
+ var->set_toplevel_decl(ts);
+ }
+ }
+
go_assert(!no->var_value()->has_pre_init());
return TRAVERSE_SKIP_COMPONENTS;
type_from_init_tuple_(false), type_from_range_index_(false),
type_from_range_value_(false), type_from_chan_element_(false),
is_type_switch_var_(false), determined_type_(false),
- in_unique_section_(false), escapes_(true)
+ in_unique_section_(false), escapes_(true),
+ toplevel_decl_(NULL)
{
go_assert(type != NULL || init != NULL);
go_assert(!is_parameter || init == NULL);
is_address_taken,
this->location_);
else
- bvar = backend->local_variable(bfunction, n, btype,
- is_address_taken,
- this->location_);
+ {
+ Bvariable* bvar_decl = NULL;
+ if (this->toplevel_decl_ != NULL)
+ {
+ Translate_context context(gogo, NULL, NULL, NULL);
+ bvar_decl = this->toplevel_decl_->temporary_statement()
+ ->get_backend_variable(&context);
+ }
+ bvar = backend->local_variable(bfunction, n, btype,
+ bvar_decl,
+ is_address_taken,
+ this->location_);
+ }
}
this->backend_ = bvar;
}
bool is_address_taken = (this->is_non_escaping_address_taken_
&& !this->is_in_heap());
this->backend_ = backend->local_variable(bfunction, n, btype,
- is_address_taken,
+ NULL, is_address_taken,
this->location_);
}
}
this->in_unique_section_ = true;
}
+ // Return the top-level declaration for this variable.
+ Statement*
+ toplevel_decl()
+ { return this->toplevel_decl_; }
+
+ // Set the top-level declaration for this variable. Only used for local
+ // variables
+ void
+ set_toplevel_decl(Statement* s)
+ {
+ go_assert(!this->is_global_ && !this->is_parameter_ && !this->is_receiver_);
+ this->toplevel_decl_ = s;
+ }
+
// Traverse the initializer expression.
int
traverse_expression(Traverse*, unsigned int traverse_mask);
// Whether this variable escapes the function it is created in. This is
// true until shown otherwise.
bool escapes_ : 1;
+ // The top-level declaration for this variable. Only used for local
+ // variables. Must be a Temporary_statement if not NULL.
+ Statement* toplevel_decl_;
};
// A variable which is really the name for a function return value, or