diff options
author | Martin Liska <mliska@suse.cz> | 2022-07-10 16:45:06 +0200 |
---|---|---|
committer | Martin Liska <mliska@suse.cz> | 2022-07-10 16:45:06 +0200 |
commit | c9de7a601878148247a44c4b04f550daa27cd556 (patch) | |
tree | 26b101e7703b42390ee048daf0b14bd8cf5b59db /gcc/go | |
parent | 3af708eb4547ffc02b446585dde47f71984cf385 (diff) | |
parent | 4ebbf3906895bcb40d7ff2729cf46deae66bc268 (diff) | |
download | gcc-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/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/export.cc | 3 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 136 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 105 | ||||
-rw-r--r-- | gcc/go/gofrontend/go.cc | 3 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 216 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 23 | ||||
-rw-r--r-- | gcc/go/gofrontend/names.cc | 29 | ||||
-rw-r--r-- | gcc/go/gofrontend/parse.cc | 113 | ||||
-rw-r--r-- | gcc/go/gofrontend/parse.h | 1 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 18 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 49 |
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(©); 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), |