aboutsummaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorMartin Liska <mliska@suse.cz>2022-07-10 16:45:06 +0200
committerMartin Liska <mliska@suse.cz>2022-07-10 16:45:06 +0200
commitc9de7a601878148247a44c4b04f550daa27cd556 (patch)
tree26b101e7703b42390ee048daf0b14bd8cf5b59db /gcc/go
parent3af708eb4547ffc02b446585dde47f71984cf385 (diff)
parent4ebbf3906895bcb40d7ff2729cf46deae66bc268 (diff)
downloadgcc-c9de7a601878148247a44c4b04f550daa27cd556.zip
gcc-c9de7a601878148247a44c4b04f550daa27cd556.tar.gz
gcc-c9de7a601878148247a44c4b04f550daa27cd556.tar.bz2
Merge branch 'master' into devel/sphinx
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/gofrontend/MERGE2
-rw-r--r--gcc/go/gofrontend/export.cc3
-rw-r--r--gcc/go/gofrontend/expressions.cc136
-rw-r--r--gcc/go/gofrontend/expressions.h105
-rw-r--r--gcc/go/gofrontend/go.cc3
-rw-r--r--gcc/go/gofrontend/gogo.cc216
-rw-r--r--gcc/go/gofrontend/gogo.h23
-rw-r--r--gcc/go/gofrontend/names.cc29
-rw-r--r--gcc/go/gofrontend/parse.cc113
-rw-r--r--gcc/go/gofrontend/parse.h1
-rw-r--r--gcc/go/gofrontend/statements.cc18
-rw-r--r--gcc/go/gofrontend/types.cc49
12 files changed, 461 insertions, 237 deletions
diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 0cda305..7c5c456 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@
-8db6b78110f84e22c409f334aeaefb80a8b39917
+d295a0a2c96c0f7c3abd94fea3aa4e2303bf2af2
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/export.cc b/gcc/go/gofrontend/export.cc
index a30b11a..7373dee 100644
--- a/gcc/go/gofrontend/export.cc
+++ b/gcc/go/gofrontend/export.cc
@@ -530,6 +530,9 @@ struct Sort_bindings
bool
operator()(const Named_object* n1, const Named_object* n2) const
{
+ if (n1 == n2)
+ return false;
+
if (n1->package() != n2->package())
{
if (n1->package() == NULL)
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 734ecb9..2492d9f 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -1426,7 +1426,12 @@ Sink_expression::do_get_backend(Translate_context* context)
Gogo* gogo = context->gogo();
if (this->bvar_ == NULL)
{
- go_assert(this->type_ != NULL && !this->type_->is_sink_type());
+ if (this->type_ == NULL || this->type_->is_sink_type())
+ {
+ go_assert(saw_errors());
+ return gogo->backend()->error_expression();
+ }
+
Named_object* fn = context->function();
go_assert(fn != NULL);
Bfunction* fn_ctx = fn->func_value()->get_or_make_decl(gogo, fn);
@@ -2715,7 +2720,7 @@ Integer_expression::do_import(Import_expression* imp, Location loc)
return Expression::make_error(loc);
}
if (pos == std::string::npos)
- mpfr_set_ui(real, 0, MPFR_RNDN);
+ mpfr_init_set_ui(real, 0, MPFR_RNDN);
else
{
std::string real_str = num.substr(0, pos);
@@ -3347,97 +3352,7 @@ class Find_named_object : public Traverse
bool found_;
};
-// A reference to a const in an expression.
-
-class Const_expression : public Expression
-{
- public:
- Const_expression(Named_object* constant, Location location)
- : Expression(EXPRESSION_CONST_REFERENCE, location),
- constant_(constant), type_(NULL), seen_(false)
- { }
-
- Named_object*
- named_object()
- { return this->constant_; }
-
- const Named_object*
- named_object() const
- { return this->constant_; }
-
- // Check that the initializer does not refer to the constant itself.
- void
- check_for_init_loop();
-
- protected:
- int
- do_traverse(Traverse*);
-
- Expression*
- do_lower(Gogo*, Named_object*, Statement_inserter*, int);
-
- bool
- do_is_constant() const
- { return true; }
-
- bool
- do_is_zero_value() const
- { return this->constant_->const_value()->expr()->is_zero_value(); }
-
- bool
- do_is_static_initializer() const
- { return true; }
-
- bool
- do_numeric_constant_value(Numeric_constant* nc) const;
-
- bool
- do_string_constant_value(std::string* val) const;
-
- bool
- do_boolean_constant_value(bool* val) const;
-
- Type*
- do_type();
-
- // The type of a const is set by the declaration, not the use.
- void
- do_determine_type(const Type_context*);
-
- void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- { return this; }
-
- Bexpression*
- do_get_backend(Translate_context* context);
-
- int
- do_inlining_cost() const
- { return 1; }
-
- // When exporting a reference to a const as part of a const
- // expression, we export the value. We ignore the fact that it has
- // a name.
- void
- do_export(Export_function_body* efb) const
- { this->constant_->const_value()->expr()->export_expression(efb); }
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- private:
- // The constant.
- Named_object* constant_;
- // The type of this reference. This is used if the constant has an
- // abstract type.
- Type* type_;
- // Used to prevent infinite recursion when a constant incorrectly
- // refers to itself.
- mutable bool seen_;
-};
+// Class Const_expression.
// Traversal.
@@ -3449,6 +3364,14 @@ Const_expression::do_traverse(Traverse* traverse)
return TRAVERSE_CONTINUE;
}
+// Whether this is the zero value.
+
+bool
+Const_expression::do_is_zero_value() const
+{
+ return this->constant_->const_value()->expr()->is_zero_value();
+}
+
// Lower a constant expression. This is where we convert the
// predeclared constant iota into an integer value.
@@ -3703,6 +3626,16 @@ Const_expression::do_get_backend(Translate_context* context)
return expr->get_backend(context);
}
+// When exporting a reference to a const as part of a const
+// expression, we export the value. We ignore the fact that it has
+// a name.
+
+void
+Const_expression::do_export(Export_function_body* efb) const
+{
+ this->constant_->const_value()->expr()->export_expression(efb);
+}
+
// Dump ast representation for constant expression.
void
@@ -6824,11 +6757,12 @@ Binary_expression::do_determine_type(const Type_context* context)
{
if ((tleft->integer_type() != NULL && tright->integer_type() != NULL)
|| (tleft->float_type() != NULL && tright->float_type() != NULL)
- || (tleft->complex_type() != NULL && tright->complex_type() != NULL))
+ || (tleft->complex_type() != NULL && tright->complex_type() != NULL)
+ || (tleft->is_boolean_type() && tright->is_boolean_type()))
{
- // Both sides have an abstract integer, abstract float, or
- // abstract complex type. Just let CONTEXT determine
- // whether they may remain abstract or not.
+ // Both sides have an abstract integer, abstract float,
+ // abstract complex, or abstract boolean type. Just let
+ // CONTEXT determine whether they may remain abstract or not.
}
else if (tleft->complex_type() != NULL)
subcontext.type = tleft;
@@ -8552,6 +8486,11 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function,
pa != this->args()->end();
++pa)
{
+ if ((*pa)->is_error_expression())
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(loc);
+ }
if ((*pa)->is_nil_expression())
{
Expression* nil = Expression::make_nil(loc);
@@ -13457,6 +13396,7 @@ Array_index_expression::do_check_types(Gogo*)
if (array_type == NULL)
{
go_assert(this->array_->type()->is_error());
+ this->set_is_error();
return;
}
@@ -15235,7 +15175,7 @@ Selector_expression::lower_method_expression(Gogo* gogo)
p != method_parameters->end();
++p, ++i)
{
- if (!p->name().empty())
+ if (!p->name().empty() && !Gogo::is_sink_name(p->name()))
parameters->push_back(*p);
else
{
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 707c193..a1e3733 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -28,6 +28,7 @@ class Map_type;
class Struct_type;
class Struct_field;
class Expression_list;
+class Const_expression;
class Var_expression;
class Enclosed_var_expression;
class Temporary_reference_expression;
@@ -626,6 +627,20 @@ class Expression
is_type_expression() const
{ return this->classification_ == EXPRESSION_TYPE; }
+ // If this is a const reference, return the Const_expression
+ // structure. Otherwise, return NULL. This is a controlled dynamic
+ // cast.
+ Const_expression*
+ const_expression()
+ { return this->convert<Const_expression, EXPRESSION_CONST_REFERENCE>(); }
+
+ const Const_expression*
+ const_expression() const
+ {
+ return this->convert<const Const_expression,
+ EXPRESSION_CONST_REFERENCE>();
+ }
+
// If this is a variable reference, return the Var_expression
// structure. Otherwise, return NULL. This is a controlled dynamic
// cast.
@@ -1453,6 +1468,96 @@ class Parser_expression : public Expression
{ go_unreachable(); }
};
+// A reference to a const in an expression.
+
+class Const_expression : public Expression
+{
+ public:
+ Const_expression(Named_object* constant, Location location)
+ : Expression(EXPRESSION_CONST_REFERENCE, location),
+ constant_(constant), type_(NULL), seen_(false)
+ { }
+
+ Named_object*
+ named_object()
+ { return this->constant_; }
+
+ const Named_object*
+ named_object() const
+ { return this->constant_; }
+
+ // Check that the initializer does not refer to the constant itself.
+ void
+ check_for_init_loop();
+
+ protected:
+ int
+ do_traverse(Traverse*);
+
+ Expression*
+ do_lower(Gogo*, Named_object*, Statement_inserter*, int);
+
+ bool
+ do_is_constant() const
+ { return true; }
+
+ bool
+ do_is_zero_value() const;
+
+ bool
+ do_is_static_initializer() const
+ { return true; }
+
+ bool
+ do_numeric_constant_value(Numeric_constant* nc) const;
+
+ bool
+ do_string_constant_value(std::string* val) const;
+
+ bool
+ do_boolean_constant_value(bool* val) const;
+
+ Type*
+ do_type();
+
+ // The type of a const is set by the declaration, not the use.
+ void
+ do_determine_type(const Type_context*);
+
+ void
+ do_check_types(Gogo*);
+
+ Expression*
+ do_copy()
+ { return this; }
+
+ Bexpression*
+ do_get_backend(Translate_context* context);
+
+ int
+ do_inlining_cost() const
+ { return 1; }
+
+ // When exporting a reference to a const as part of a const
+ // expression, we export the value. We ignore the fact that it has
+ // a name.
+ void
+ do_export(Export_function_body* efb) const;
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
+ private:
+ // The constant.
+ Named_object* constant_;
+ // The type of this reference. This is used if the constant has an
+ // abstract type.
+ Type* type_;
+ // Used to prevent infinite recursion when a constant incorrectly
+ // refers to itself.
+ mutable bool seen_;
+};
+
// An expression which is simply a variable.
class Var_expression : public Expression
diff --git a/gcc/go/gofrontend/go.cc b/gcc/go/gofrontend/go.cc
index 404cb12..1512770 100644
--- a/gcc/go/gofrontend/go.cc
+++ b/gcc/go/gofrontend/go.cc
@@ -146,6 +146,9 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
if (only_check_syntax)
return;
+ // Record global variable initializer dependencies.
+ ::gogo->record_global_init_refs();
+
// Do simple deadcode elimination.
::gogo->remove_deadcode();
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index d35c6ba..9197eef 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -1086,8 +1086,8 @@ class Find_vars : public Traverse
public:
Find_vars()
- : Traverse(traverse_expressions),
- vars_(), seen_objects_()
+ : Traverse(traverse_expressions | traverse_statements),
+ vars_(), seen_objects_(), lhs_is_ref_(false)
{ }
// An iterator through the variables found, after the traversal.
@@ -1104,11 +1104,16 @@ class Find_vars : public Traverse
int
expression(Expression**);
+ int
+ statement(Block*, size_t* index, Statement*);
+
private:
// Accumulated variables.
Vars vars_;
// Objects we have already seen.
Seen_objects seen_objects_;
+ // Whether an assignment to a variable counts as a reference.
+ bool lhs_is_ref_;
};
// Collect global variables referenced by EXPR. Look through function
@@ -1164,7 +1169,11 @@ Find_vars::expression(Expression** pexpr)
if (ins.second)
{
// This is the first time we have seen this name.
- if (f->func_value()->block()->traverse(this) == TRAVERSE_EXIT)
+ bool hold = this->lhs_is_ref_;
+ this->lhs_is_ref_ = true;
+ int r = f->func_value()->block()->traverse(this);
+ this->lhs_is_ref_ = hold;
+ if (r == TRAVERSE_EXIT)
return TRAVERSE_EXIT;
}
}
@@ -1192,6 +1201,29 @@ Find_vars::expression(Expression** pexpr)
return TRAVERSE_CONTINUE;
}
+// Check a statement while searching for variables. This is where we
+// skip variables on the left hand side of assigments if appropriate.
+
+int
+Find_vars::statement(Block*, size_t*, Statement* s)
+{
+ if (this->lhs_is_ref_)
+ return TRAVERSE_CONTINUE;
+ Assignment_statement* as = s->assignment_statement();
+ if (as == NULL)
+ return TRAVERSE_CONTINUE;
+
+ // Only traverse subexpressions of the LHS.
+ if (as->lhs()->traverse_subexpressions(this) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+
+ Expression* rhs = as->rhs();
+ if (Expression::traverse(&rhs, this) == TRAVERSE_EXIT)
+ return TRAVERSE_EXIT;
+
+ return TRAVERSE_SKIP_COMPONENTS;
+}
+
// Return true if EXPR, PREINIT, or DEP refers to VAR.
static bool
@@ -1230,11 +1262,11 @@ class Var_init
{
public:
Var_init()
- : var_(NULL), init_(NULL), refs_(NULL), dep_count_(0)
+ : var_(NULL), init_(NULL), dep_count_(0)
{ }
Var_init(Named_object* var, Bstatement* init)
- : var_(var), init_(init), refs_(NULL), dep_count_(0)
+ : var_(var), init_(init), dep_count_(0)
{ }
// Return the variable.
@@ -1247,19 +1279,6 @@ class Var_init
init() const
{ return this->init_; }
- // Add a reference.
- void
- add_ref(Named_object* var);
-
- // The variables which this variable's initializers refer to.
- const std::vector<Named_object*>*
- refs()
- { return this->refs_; }
-
- // Clear the references, if any.
- void
- clear_refs();
-
// Return the number of remaining dependencies.
size_t
dep_count() const
@@ -1280,36 +1299,12 @@ class Var_init
Named_object* var_;
// The backend initialization statement.
Bstatement* init_;
- // Variables this refers to.
- std::vector<Named_object*>* refs_;
// The number of initializations this is dependent on. A variable
// initialization should not be emitted if any of its dependencies
// have not yet been resolved.
size_t dep_count_;
};
-// Add a reference.
-
-void
-Var_init::add_ref(Named_object* var)
-{
- if (this->refs_ == NULL)
- this->refs_ = new std::vector<Named_object*>;
- this->refs_->push_back(var);
-}
-
-// Clear the references, if any.
-
-void
-Var_init::clear_refs()
-{
- if (this->refs_ != NULL)
- {
- delete this->refs_;
- this->refs_ = NULL;
- }
-}
-
// For comparing Var_init keys in a map.
inline bool
@@ -1324,7 +1319,7 @@ typedef std::list<Var_init> Var_inits;
// variable V2 then we initialize V1 after V2.
static void
-sort_var_inits(Gogo* gogo, Var_inits* var_inits)
+sort_var_inits(Var_inits* var_inits)
{
if (var_inits->empty())
return;
@@ -1337,33 +1332,13 @@ sort_var_inits(Gogo* gogo, Var_inits* var_inits)
Init_deps init_deps;
bool init_loop = false;
- // Compute all variable references.
+ // Map from variable to Var_init.
for (Var_inits::iterator pvar = var_inits->begin();
pvar != var_inits->end();
++pvar)
{
Named_object* var = pvar->var();
var_to_init[var] = &*pvar;
-
- Find_vars find_vars;
- Expression* init = var->var_value()->init();
- if (init != NULL)
- Expression::traverse(&init, &find_vars);
- if (var->var_value()->has_pre_init())
- var->var_value()->preinit()->traverse(&find_vars);
- Named_object* dep = gogo->var_depends_on(var->var_value());
- if (dep != NULL)
- {
- Expression* dinit = dep->var_value()->init();
- if (dinit != NULL)
- Expression::traverse(&dinit, &find_vars);
- if (dep->var_value()->has_pre_init())
- dep->var_value()->preinit()->traverse(&find_vars);
- }
- for (Find_vars::const_iterator p = find_vars.begin();
- p != find_vars.end();
- ++p)
- pvar->add_ref(*p);
}
// Add dependencies to init_deps, and check for cycles.
@@ -1373,7 +1348,8 @@ sort_var_inits(Gogo* gogo, Var_inits* var_inits)
{
Named_object* var = pvar->var();
- const std::vector<Named_object*>* refs = pvar->refs();
+ const std::vector<Named_object*>* refs =
+ pvar->var()->var_value()->init_refs();
if (refs == NULL)
continue;
for (std::vector<Named_object*>::const_iterator pdep = refs->begin();
@@ -1383,19 +1359,11 @@ sort_var_inits(Gogo* gogo, Var_inits* var_inits)
Named_object* dep = *pdep;
if (var == dep)
{
- // This is a reference from a variable to itself, which
- // may indicate a loop. We only report an error if
- // there is an initializer and there is no dependency.
- // When there is no initializer, it means that the
- // preinitializer sets the variable, which will appear
- // to be a loop here.
- if (var->var_value()->init() != NULL
- && gogo->var_depends_on(var->var_value()) == NULL)
- go_error_at(var->location(),
- ("initialization expression for %qs "
- "depends upon itself"),
- var->message_name().c_str());
-
+ // This is a reference from a variable to itself.
+ go_error_at(var->location(),
+ ("initialization expression for %qs "
+ "depends upon itself"),
+ var->message_name().c_str());
continue;
}
@@ -1412,7 +1380,8 @@ sort_var_inits(Gogo* gogo, Var_inits* var_inits)
pvar->add_dependency();
// Check for cycles.
- const std::vector<Named_object*>* deprefs = dep_init->refs();
+ const std::vector<Named_object*>* deprefs =
+ dep_init->var()->var_value()->init_refs();
if (deprefs == NULL)
continue;
for (std::vector<Named_object*>::const_iterator pdepdep =
@@ -1437,10 +1406,6 @@ sort_var_inits(Gogo* gogo, Var_inits* var_inits)
}
var_to_init.clear();
- for (Var_inits::iterator pvar = var_inits->begin();
- pvar != var_inits->end();
- ++pvar)
- pvar->clear_refs();
// If there are no dependencies then the declaration order is sorted.
if (!init_deps.empty() && !init_loop)
@@ -1748,7 +1713,7 @@ Gogo::write_globals()
// workable order.
if (!var_inits.empty())
{
- sort_var_inits(this, &var_inits);
+ sort_var_inits(&var_inits);
for (Var_inits::const_iterator p = var_inits.begin();
p != var_inits.end();
++p)
@@ -2811,7 +2776,7 @@ Specific_type_functions::type(Type* t)
case Type::TYPE_MAP:
{
- Type* key_type = t->map_type()->key_type();
+ Type* key_type = t->map_type()->key_type()->unalias();
if (key_type->needs_specific_type_functions(this->gogo_))
key_type->hash_function(this->gogo_, NULL);
}
@@ -3840,6 +3805,51 @@ Gogo::check_types_in_block(Block* block)
block->traverse(&traverse);
}
+// For each global variable defined in the current package, record the
+// set of variables that its initializer depends on. We do this after
+// lowering so that all unknown names are resolved to their final
+// locations. We do this before write barrier insertion because that
+// makes it harder to distinguish references from assignments in
+// preinit blocks.
+
+void
+Gogo::record_global_init_refs()
+{
+ Bindings* bindings = this->package_->bindings();
+ for (Bindings::const_definitions_iterator pb = bindings->begin_definitions();
+ pb != bindings->end_definitions();
+ pb++)
+ {
+ Named_object* no = *pb;
+ if (!no->is_variable())
+ continue;
+
+ Variable* var = no->var_value();
+ go_assert(var->is_global());
+
+ Find_vars find_vars;
+ Expression* init = var->init();
+ if (init != NULL)
+ Expression::traverse(&init, &find_vars);
+ if (var->has_pre_init())
+ var->preinit()->traverse(&find_vars);
+ Named_object* dep = this->var_depends_on(var);
+ if (dep != NULL)
+ {
+ Expression* dinit = dep->var_value()->init();
+ if (dinit != NULL)
+ Expression::traverse(&dinit, &find_vars);
+ if (dep->var_value()->has_pre_init())
+ dep->var_value()->preinit()->traverse(&find_vars);
+ }
+
+ for (Find_vars::const_iterator pv = find_vars.begin();
+ pv != find_vars.end();
+ ++pv)
+ var->add_init_ref(*pv);
+ }
+}
+
// A traversal class which finds all the expressions which must be
// evaluated in order within a statement or larger expression. This
// is used to implement the rules about order of evaluation.
@@ -5302,16 +5312,16 @@ Gogo::write_c_header()
Named_object* no = types.front();
types.pop_front();
- std::vector<const Named_object*> requires;
+ std::vector<const Named_object*> needs;
std::vector<const Named_object*> declare;
- if (!no->type_value()->struct_type()->can_write_to_c_header(&requires,
+ if (!no->type_value()->struct_type()->can_write_to_c_header(&needs,
&declare))
continue;
bool ok = true;
for (std::vector<const Named_object*>::const_iterator pr
- = requires.begin();
- pr != requires.end() && ok;
+ = needs.begin();
+ pr != needs.end() && ok;
++pr)
{
for (std::list<Named_object*>::const_iterator pt = types.begin();
@@ -5342,10 +5352,10 @@ Gogo::write_c_header()
if (*pd == no)
continue;
- std::vector<const Named_object*> drequires;
+ std::vector<const Named_object*> dneeds;
std::vector<const Named_object*> ddeclare;
if (!(*pd)->type_value()->struct_type()->
- can_write_to_c_header(&drequires, &ddeclare))
+ can_write_to_c_header(&dneeds, &ddeclare))
continue;
bool done = false;
@@ -7422,16 +7432,16 @@ Variable::Variable(Type* type, Expression* init, bool is_global,
bool is_parameter, bool is_receiver,
Location location)
: type_(type), init_(init), preinit_(NULL), location_(location),
- embeds_(NULL), backend_(NULL), is_global_(is_global),
- is_parameter_(is_parameter), is_closure_(false), is_receiver_(is_receiver),
- is_varargs_parameter_(false), is_global_sink_(false), is_used_(false),
- is_address_taken_(false), is_non_escaping_address_taken_(false),
- seen_(false), init_is_lowered_(false), init_is_flattened_(false),
+ toplevel_decl_(NULL), init_refs_(NULL), embeds_(NULL), backend_(NULL),
+ is_global_(is_global), is_parameter_(is_parameter), is_closure_(false),
+ is_receiver_(is_receiver), is_varargs_parameter_(false),
+ is_global_sink_(false), is_used_(false), is_address_taken_(false),
+ is_non_escaping_address_taken_(false), seen_(false),
+ init_is_lowered_(false), init_is_flattened_(false),
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), is_referenced_by_inline_(false),
- toplevel_decl_(NULL)
+ in_unique_section_(false), is_referenced_by_inline_(false)
{
go_assert(type != NULL || init != NULL);
go_assert(!is_parameter || init == NULL);
@@ -7921,6 +7931,16 @@ Variable::get_init_block(Gogo* gogo, Named_object* function,
return block_stmt;
}
+// Add an initializer reference.
+
+void
+Variable::add_init_ref(Named_object* var)
+{
+ if (this->init_refs_ == NULL)
+ this->init_refs_ = new std::vector<Named_object*>;
+ this->init_refs_->push_back(var);
+}
+
// Export the variable
void
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index 2ee0fda..433fdae 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -842,6 +842,11 @@ class Gogo
void
check_return_statements();
+ // Gather references from global variables initializers to other
+ // variables.
+ void
+ record_global_init_refs();
+
// Remove deadcode.
void
remove_deadcode();
@@ -2333,6 +2338,15 @@ class Variable
this->toplevel_decl_ = s;
}
+ // Note that the initializer of this global variable refers to VAR.
+ void
+ add_init_ref(Named_object* var);
+
+ // The variables that this variable's initializers refer to.
+ const std::vector<Named_object*>*
+ init_refs() const
+ { return this->init_refs_; }
+
// Traverse the initializer expression.
int
traverse_expression(Traverse*, unsigned int traverse_mask);
@@ -2389,6 +2403,12 @@ class Variable
Block* preinit_;
// Location of variable definition.
Location location_;
+ // The top-level declaration for this variable. Only used for local
+ // variables. Must be a Temporary_statement if not NULL.
+ Statement* toplevel_decl_;
+ // Variables that the initializer of a global variable refers to.
+ // Used for initializer ordering.
+ std::vector<Named_object*>* init_refs_;
// Any associated go:embed comments.
std::vector<std::string>* embeds_;
// Backend representation.
@@ -2439,9 +2459,6 @@ class Variable
// True if this variable is referenced from an inlined body that
// will be put into the export data.
bool is_referenced_by_inline_ : 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
diff --git a/gcc/go/gofrontend/names.cc b/gcc/go/gofrontend/names.cc
index f85d84c..dac7f20 100644
--- a/gcc/go/gofrontend/names.cc
+++ b/gcc/go/gofrontend/names.cc
@@ -831,15 +831,28 @@ Struct_type::do_mangled_name(Gogo* gogo, std::string* ret,
ret->push_back(' ');
}
- // For an anonymous field with an alias type, the field name
- // is the alias name.
- if (p->is_anonymous()
- && p->type()->named_type() != NULL
- && p->type()->named_type()->is_alias())
- p->type()->named_type()->append_symbol_type_name(gogo, true, ret,
- is_non_identifier);
+ const Type* ft = p->type();
+ const Named_type* nt = ft->named_type();
+
+ if (p->is_anonymous() && nt != NULL && nt->is_builtin())
+ {
+ // For an embedded field with a builtin type, we must
+ // include a package path. Otherwise embedding builtin
+ // types in different packages will produce identical
+ // types, which shouldn't happen because the builtin
+ // types are not exported.
+ ret->append(gogo->pkgpath());
+ ret->push_back('.');
+ nt->append_symbol_type_name(gogo, true, ret, is_non_identifier);
+ }
+ else if (p->is_anonymous() && nt != NULL && nt->is_alias())
+ {
+ // For an anonymous field with an alias type, the field name
+ // is the alias name.
+ nt->append_symbol_type_name(gogo, true, ret, is_non_identifier);
+ }
else
- this->append_mangled_name(p->type(), gogo, ret, is_non_identifier);
+ this->append_mangled_name(ft, gogo, ret, is_non_identifier);
if (p->has_tag())
{
diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc
index cc197e5..c93d82b 100644
--- a/gcc/go/gofrontend/parse.cc
+++ b/gcc/go/gofrontend/parse.cc
@@ -191,7 +191,11 @@ Parse::qualified_ident(std::string* pname, Named_object** ppackage)
Named_object* package = this->gogo_->lookup(name, NULL);
if (package == NULL || !package->is_package())
{
- go_error_at(this->location(), "expected package");
+ if (package == NULL)
+ go_error_at(this->location(), "reference to undefined name %qs",
+ Gogo::message_name(name).c_str());
+ else
+ go_error_at(this->location(), "expected package");
// We expect . IDENTIFIER; skip both.
if (this->advance_token()->is_identifier())
this->advance_token();
@@ -1468,6 +1472,7 @@ Parse::const_spec(int iota, Type** last_type, Expression_list** last_expr_list)
{
Expression* copy = (*p)->copy();
copy->set_location(loc);
+ this->update_references(&copy);
expr_list->push_back(copy);
}
}
@@ -1513,6 +1518,94 @@ Parse::const_spec(int iota, Type** last_type, Expression_list** last_expr_list)
return;
}
+// Update any references to names to refer to the current names,
+// for weird cases like
+//
+// const X = 1
+// func F() {
+// const (
+// X = X + X
+// Y
+// )
+// }
+//
+// where the X + X for the first X is the outer X, but the X + X
+// copied for Y is the inner X.
+
+class Update_references : public Traverse
+{
+ public:
+ Update_references(Gogo* gogo)
+ : Traverse(traverse_expressions),
+ gogo_(gogo)
+ { }
+
+ int
+ expression(Expression**);
+
+ private:
+ Gogo* gogo_;
+};
+
+int
+Update_references::expression(Expression** pexpr)
+{
+ Named_object* old_no;
+ switch ((*pexpr)->classification())
+ {
+ case Expression::EXPRESSION_CONST_REFERENCE:
+ old_no = (*pexpr)->const_expression()->named_object();
+ break;
+ case Expression::EXPRESSION_VAR_REFERENCE:
+ old_no = (*pexpr)->var_expression()->named_object();
+ break;
+ case Expression::EXPRESSION_ENCLOSED_VAR_REFERENCE:
+ old_no = (*pexpr)->enclosed_var_expression()->variable();
+ break;
+ case Expression::EXPRESSION_FUNC_REFERENCE:
+ old_no = (*pexpr)->func_expression()->named_object();
+ break;
+ case Expression::EXPRESSION_UNKNOWN_REFERENCE:
+ old_no = (*pexpr)->unknown_expression()->named_object();
+ break;
+ default:
+ return TRAVERSE_CONTINUE;
+ }
+
+ if (old_no->package() != NULL)
+ {
+ // This is a qualified reference, so it can't have changed in
+ // scope. FIXME: This probably doesn't handle dot imports
+ // correctly.
+ return TRAVERSE_CONTINUE;
+ }
+
+ Named_object* in_function;
+ Named_object* new_no = this->gogo_->lookup(old_no->name(), &in_function);
+ if (new_no == old_no)
+ return TRAVERSE_CONTINUE;
+
+ // The new name must be a constant, since that is all we have
+ // introduced into scope.
+ if (!new_no->is_const())
+ {
+ go_assert(saw_errors());
+ return TRAVERSE_CONTINUE;
+ }
+
+ *pexpr = Expression::make_const_reference(new_no, (*pexpr)->location());
+
+ return TRAVERSE_CONTINUE;
+}
+
+void
+Parse::update_references(Expression** pexpr)
+{
+ Update_references ur(this->gogo_);
+ ur.expression(pexpr);
+ (*pexpr)->traverse_subexpressions(&ur);
+}
+
// TypeDecl = "type" Decl<TypeSpec> .
void
@@ -1888,7 +1981,11 @@ Parse::init_vars_from_map(const Typed_identifier_list* vars, Type* type,
else if (!val_no->is_sink())
{
if (val_no->is_variable())
- val_no->var_value()->add_preinit_statement(this->gogo_, s);
+ {
+ val_no->var_value()->add_preinit_statement(this->gogo_, s);
+ if (no->is_variable())
+ this->gogo_->record_var_depends_on(no->var_value(), val_no);
+ }
}
else if (!no->is_sink())
{
@@ -1955,7 +2052,11 @@ Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type,
else if (!val_no->is_sink())
{
if (val_no->is_variable())
- val_no->var_value()->add_preinit_statement(this->gogo_, s);
+ {
+ val_no->var_value()->add_preinit_statement(this->gogo_, s);
+ if (no->is_variable())
+ this->gogo_->record_var_depends_on(no->var_value(), val_no);
+ }
}
else if (!no->is_sink())
{
@@ -2021,7 +2122,11 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
else if (!val_no->is_sink())
{
if (val_no->is_variable())
- val_no->var_value()->add_preinit_statement(this->gogo_, s);
+ {
+ val_no->var_value()->add_preinit_statement(this->gogo_, s);
+ if (no->is_variable())
+ this->gogo_->record_var_depends_on(no->var_value(), val_no);
+ }
}
else if (!no->is_sink())
{
diff --git a/gcc/go/gofrontend/parse.h b/gcc/go/gofrontend/parse.h
index 6e300ef..cda0bee 100644
--- a/gcc/go/gofrontend/parse.h
+++ b/gcc/go/gofrontend/parse.h
@@ -185,6 +185,7 @@ class Parse
void list(void (Parse::*)(), bool);
void const_decl();
void const_spec(int, Type**, Expression_list**);
+ void update_references(Expression**);
void type_decl();
void type_spec();
void var_decl();
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index b3db843..b442830 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -1594,9 +1594,9 @@ Tuple_map_assignment_statement::do_lower(Gogo* gogo, Named_object*,
// var present_temp bool
Temporary_statement* present_temp =
- Statement::make_temporary((this->present_->type()->is_sink_type())
- ? Type::make_boolean_type()
- : this->present_->type(),
+ Statement::make_temporary((this->present_->type()->is_boolean_type()
+ ? this->present_->type()
+ : Type::lookup_bool_type()),
NULL, loc);
b->add_statement(present_temp);
@@ -1789,9 +1789,9 @@ Tuple_receive_assignment_statement::do_lower(Gogo*, Named_object*,
// var closed_temp bool
Temporary_statement* closed_temp =
- Statement::make_temporary((this->closed_->type()->is_sink_type())
- ? Type::make_boolean_type()
- : this->closed_->type(),
+ Statement::make_temporary((this->closed_->type()->is_boolean_type()
+ ? this->closed_->type()
+ : Type::lookup_bool_type()),
NULL, loc);
b->add_statement(closed_temp);
@@ -1965,6 +1965,8 @@ Tuple_type_guard_assignment_statement::do_lower(Gogo*, Named_object*,
b->add_statement(s);
res = Expression::make_call_result(call, 1);
+ if (!this->ok_->type()->is_boolean_type())
+ res = Expression::make_cast(Type::lookup_bool_type(), res, loc);
s = Statement::make_assignment(this->ok_, res, loc);
b->add_statement(s);
}
@@ -2001,7 +2003,9 @@ Tuple_type_guard_assignment_statement::lower_to_object_type(
Temporary_statement* ok_temp = NULL;
if (!this->ok_->is_sink_expression())
{
- ok_temp = Statement::make_temporary(this->ok_->type(),
+ ok_temp = Statement::make_temporary((this->ok_->type()->is_boolean_type()
+ ? this->ok_->type()
+ : Type::lookup_bool_type()),
NULL, loc);
b->add_statement(ok_temp);
}
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index eb3afd9..9f34801 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -1764,6 +1764,9 @@ Type::needs_specific_type_functions(Gogo* gogo)
Named_object*
Type::hash_function(Gogo* gogo, Function_type* hash_fntype)
{
+ if (this->named_type() != NULL)
+ go_assert(!this->named_type()->is_alias());
+
if (!this->is_comparable())
return NULL;
@@ -2067,6 +2070,9 @@ Type::write_identity_hash(Gogo* gogo, int64_t size)
Named_object*
Type::equal_function(Gogo* gogo, Named_type* name, Function_type* equal_fntype)
{
+ if (this->named_type() != NULL)
+ go_assert(!this->named_type()->is_alias());
+
// If the unaliased type is not a named type, then the type does not
// have a name after all.
if (name != NULL)
@@ -4648,8 +4654,11 @@ class Sink_type : public Type
{ return false; }
Btype*
- do_get_backend(Gogo*)
- { go_unreachable(); }
+ do_get_backend(Gogo* gogo)
+ {
+ go_assert(saw_errors());
+ return gogo->backend()->error_type();
+ }
Expression*
do_type_descriptor(Gogo*, Named_type*)
@@ -6700,7 +6709,8 @@ Struct_type::write_hash_function(Gogo* gogo, Function_type* hash_fntype)
subkey = Expression::make_cast(key_arg_type, subkey, bloc);
// Get the hash function to use for the type of this field.
- Named_object* hash_fn = pf->type()->hash_function(gogo, hash_fntype);
+ Named_object* hash_fn =
+ pf->type()->unalias()->hash_function(gogo, hash_fntype);
// Call the hash function for the field, passing retval as the seed.
ref = Expression::make_temporary_reference(retval, bloc);
@@ -6957,7 +6967,7 @@ Struct_type::do_import(Import* imp)
bool
Struct_type::can_write_to_c_header(
- std::vector<const Named_object*>* requires,
+ std::vector<const Named_object*>* needs,
std::vector<const Named_object*>* declare) const
{
const Struct_field_list* fields = this->fields_;
@@ -6968,7 +6978,7 @@ Struct_type::can_write_to_c_header(
p != fields->end();
++p)
{
- if (!this->can_write_type_to_c_header(p->type(), requires, declare))
+ if (!this->can_write_type_to_c_header(p->type(), needs, declare))
return false;
if (Gogo::message_name(p->field_name()) == "_")
sinks++;
@@ -6983,7 +6993,7 @@ Struct_type::can_write_to_c_header(
bool
Struct_type::can_write_type_to_c_header(
const Type* t,
- std::vector<const Named_object*>* requires,
+ std::vector<const Named_object*>* needs,
std::vector<const Named_object*>* declare) const
{
t = t->forwarded();
@@ -7017,13 +7027,13 @@ Struct_type::can_write_type_to_c_header(
return true;
case TYPE_STRUCT:
- return t->struct_type()->can_write_to_c_header(requires, declare);
+ return t->struct_type()->can_write_to_c_header(needs, declare);
case TYPE_ARRAY:
if (t->is_slice_type())
return true;
return this->can_write_type_to_c_header(t->array_type()->element_type(),
- requires, declare);
+ needs, declare);
case TYPE_NAMED:
{
@@ -7039,10 +7049,10 @@ Struct_type::can_write_type_to_c_header(
// We will accept empty struct fields, but not print them.
if (t->struct_type()->total_field_count() == 0)
return true;
- requires->push_back(no);
- return t->struct_type()->can_write_to_c_header(requires, declare);
+ needs->push_back(no);
+ return t->struct_type()->can_write_to_c_header(needs, declare);
}
- return this->can_write_type_to_c_header(t->base(), requires, declare);
+ return this->can_write_type_to_c_header(t->base(), needs, declare);
}
case TYPE_CALL_MULTIPLE_RESULT:
@@ -7140,9 +7150,9 @@ Struct_type::write_field_to_c_header(std::ostream& os, const std::string& name,
case TYPE_POINTER:
{
- std::vector<const Named_object*> requires;
+ std::vector<const Named_object*> needs;
std::vector<const Named_object*> declare;
- if (!this->can_write_type_to_c_header(t->points_to(), &requires,
+ if (!this->can_write_type_to_c_header(t->points_to(), &needs,
&declare))
os << "void*";
else
@@ -7419,7 +7429,10 @@ bool
Array_type::do_verify()
{
if (this->element_type()->is_error_type())
- return false;
+ {
+ this->set_is_error();
+ return false;
+ }
if (!this->verify_length())
{
this->length_ = Expression::make_error(this->length_->location());
@@ -7553,8 +7566,8 @@ Array_type::write_hash_function(Gogo* gogo, Function_type* hash_fntype)
gogo->start_block(bloc);
// Get the hash function for the element type.
- Named_object* hash_fn = this->element_type_->hash_function(gogo,
- hash_fntype);
+ Named_object* hash_fn =
+ this->element_type_->unalias()->hash_function(gogo, hash_fntype);
// Get a pointer to this element in the loop.
Expression* subkey = Expression::make_temporary_reference(key, bloc);
@@ -8441,8 +8454,8 @@ Map_type::do_type_descriptor(Gogo* gogo, Named_type* name)
++p;
go_assert(p->is_field_name("hasher"));
Function_type* hasher_fntype = p->type()->function_type();
- Named_object* hasher_fn = this->key_type_->hash_function(gogo,
- hasher_fntype);
+ Named_object* hasher_fn =
+ this->key_type_->unalias()->hash_function(gogo, hasher_fntype);
if (hasher_fn == NULL)
vals->push_back(Expression::make_cast(hasher_fntype,
Expression::make_nil(bloc),