From 7f195a2270910a6ed08bd76e3a16b0a6503f9faf Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 14 Jun 2022 11:33:42 -0700 Subject: libgo: permit loff_t and off_t to be macros MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit They are macros in musl libc, rather than typedefs, and -fgo-dump-spec doesn't handle that case. Based on patch by Sören Tempel. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/412075 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 0cda305..4b75dd3 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -8db6b78110f84e22c409f334aeaefb80a8b39917 +a409e049737ec9a358a19233e017d957db3d6d2a The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From 7905a9ac26707ed6ac49e40e35a9c8755c6574e3 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 18 Jun 2022 18:19:28 -0700 Subject: libgo: #include when checking for loff_t PR go/106033 Fixes golang/go#53469 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/413214 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 4b75dd3..737bc48 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -a409e049737ec9a358a19233e017d957db3d6d2a +77821de1a149c2e6ef9c154ae384c16292173039 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From 038a7150ec07770174907b93bc93caaa1e019f92 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 22 Jun 2022 16:40:24 -0700 Subject: compiler: unalias types for hash/equality functions Test case is https://go.dev/cl/413694. Fixes golang/go#52846 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/413660 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/gogo.cc | 2 +- gcc/go/gofrontend/types.cc | 17 ++++++++++++----- 3 files changed, 14 insertions(+), 7 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 737bc48..629bc66 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -77821de1a149c2e6ef9c154ae384c16292173039 +6c3752315dc9b82d0f3f3ac646a1e7376818f84a 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/gogo.cc b/gcc/go/gofrontend/gogo.cc index d35c6ba..e13df0d 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -2811,7 +2811,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); } diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index eb3afd9..39aea76 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) @@ -6700,7 +6706,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); @@ -7553,8 +7560,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 +8448,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), -- cgit v1.1 From 5ee8e1d1b0c0d9f6310d27a37a6162e0be80e413 Mon Sep 17 00:00:00 2001 From: zhangjian Date: Tue, 21 Jun 2022 16:08:47 +0000 Subject: compiler: in Sort_bindings return false if comparing value to itself Some versions of std::sort may pass elements at the same iterator location. Fixes golang/go#53483 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/413434 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/export.cc | 3 +++ 2 files changed, 4 insertions(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 629bc66..f882812 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -6c3752315dc9b82d0f3f3ac646a1e7376818f84a +6b314f7947b4b31a86c09d166fe6664cd9968824 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) -- cgit v1.1 From bb403de36aa29e5398119e78a2c96794bdd6bad8 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 23 Jun 2022 17:11:05 -0700 Subject: compiler: use bool for comma-ok if not already boolean If a comma-ok variable already has a type, and that type is not a boolean type, then set the type of the temporary variable to bool. Otherwise we may try to convert an unnamed bool type to an interface type, which will fail. But we don't want to always use bool, because the type of the comma-ok variable may be a named bool type, in which case the assignment would fail (or need an explicit conversion). The test case is https://go.dev/cl/404496. Fixes golang/go#52535 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/413894 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/statements.cc | 18 +++++++++++------- 2 files changed, 12 insertions(+), 8 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index f882812..e20212e 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -6b314f7947b4b31a86c09d166fe6664cd9968824 +6a7ba754e5d98efe0875f1f41f40098e976e7958 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/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); } -- cgit v1.1 From 722750a44a93ce7d23e09df240d8ab700a2d30e6 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 24 Jun 2022 17:18:15 -0700 Subject: compiler: always initialize mpfr in integer import Test case is https://go.dev/cl/413980. Fixes golang/go#52862 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/413981 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 2 +- 2 files changed, 2 insertions(+), 2 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index e20212e..f84347e 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -6a7ba754e5d98efe0875f1f41f40098e976e7958 +6edae0ef6521569e8f949aaaafa9dc1139825051 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/expressions.cc b/gcc/go/gofrontend/expressions.cc index 734ecb9..135dae02 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -2715,7 +2715,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); -- cgit v1.1 From 5f6b6494035fb984d745efa28d334f7893e7272b Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 26 Jun 2022 21:52:35 -0700 Subject: compiler: don't use sink as parameter in method expression thunk Also fix a couple of cases where the error led to a later compiler crash. Test case is https://go.dev/cl/414336. Fixes golang/go#52871 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/414354 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 9 +++++++-- gcc/go/gofrontend/types.cc | 7 +++++-- 3 files changed, 13 insertions(+), 5 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index f84347e..16d274c 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -6edae0ef6521569e8f949aaaafa9dc1139825051 +927528cdc112fc51e0d07ee79e7a1254b586eabe 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/expressions.cc b/gcc/go/gofrontend/expressions.cc index 135dae02..f59f61d 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); @@ -15235,7 +15240,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/types.cc b/gcc/go/gofrontend/types.cc index 39aea76..e82be68 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -4654,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*) -- cgit v1.1 From ed06274eacc17a224b87f23111d7ca874ea53b7c Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 27 Jun 2022 22:17:51 -0700 Subject: compiler: permit expressions of abstract bool to remain abstract Test case is https://go.dev/cl/414755. Fixes golang/go#51475 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/414735 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 9 +++++---- 2 files changed, 6 insertions(+), 5 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 16d274c..a0e386a 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -927528cdc112fc51e0d07ee79e7a1254b586eabe +28fe9fad4acb4e02083faf5503b06e3e6e8eecaf 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/expressions.cc b/gcc/go/gofrontend/expressions.cc index f59f61d..aadca97 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -6829,11 +6829,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; -- cgit v1.1 From 53c4ef1e3cc103ce5bdf1d9923144e93b523102a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 27 Jun 2022 17:22:53 -0700 Subject: libgo: make runtime.Version return a meaningful string Fixes golang/go#51850 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/414734 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index a0e386a..551ea65 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -28fe9fad4acb4e02083faf5503b06e3e6e8eecaf +d5b4abed2f206e492890acc20738e89617ea542c The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From 74956337e8276e5bc9524104b01c147374dd94e7 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sat, 25 Jun 2022 22:09:16 -0700 Subject: compiler: use package path with embedded builtin type The test case is https://go.dev/cl/414235. Fixes golang/go#52856 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/414294 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/names.cc | 29 +++++++++++++++++++++-------- 2 files changed, 22 insertions(+), 9 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 551ea65..13cb6ea 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -d5b4abed2f206e492890acc20738e89617ea542c +c7238f58a26131b7611eff6f555cab02af8a623c 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/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()) { -- cgit v1.1 From 3183acc8e0452fbc0ad429a909811ca0308c86c9 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Tue, 28 Jun 2022 17:03:28 -0700 Subject: compiler: check repeated const expressions in new scope Test case is const8.go in https://go.dev/cl/414795. Fixes golang/go#53585 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/414914 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 110 +++++++-------------------------------- gcc/go/gofrontend/expressions.h | 105 +++++++++++++++++++++++++++++++++++++ gcc/go/gofrontend/parse.cc | 89 +++++++++++++++++++++++++++++++ gcc/go/gofrontend/parse.h | 1 + 5 files changed, 215 insertions(+), 92 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 13cb6ea..4fde25a 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -c7238f58a26131b7611eff6f555cab02af8a623c +63782f8a318e9eebfdc983f171a920c7a937c759 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/expressions.cc b/gcc/go/gofrontend/expressions.cc index aadca97..00d35a9 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -3352,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. @@ -3454,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. @@ -3708,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 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 Const_expression* + const_expression() const + { + return this->convert(); + } + // 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/parse.cc b/gcc/go/gofrontend/parse.cc index cc197e5..e388261 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -1468,6 +1468,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 +1514,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 . void 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(); -- cgit v1.1 From 762fd5e5547e464e25b4bee435db6df4eda0de90 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Wed, 29 Jun 2022 15:32:04 -0700 Subject: libgo: handle stat st_atim32 field and SYS_SECCOMP MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit Patches for musl support, from Sören Tempel. Fixes PR go/105225 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/415294 --- gcc/go/gofrontend/MERGE | 2 +- 1 file changed, 1 insertion(+), 1 deletion(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 4fde25a..0d49e9e 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -63782f8a318e9eebfdc983f171a920c7a937c759 +548720bca6bff21ebc9aba22249d9ce45bbd90c7 The first line of this file holds the git revision number of the last merge done from the gofrontend repository. -- cgit v1.1 From 1f76941c09f6f62f4cbf7a9f531ec95268dd2c0a Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Fri, 1 Jul 2022 10:56:37 -0700 Subject: compiler: rename "requires" to "needs" As of C++20 "requires" is a C++ keyword. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/415754 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/gogo.cc | 12 ++++++------ gcc/go/gofrontend/types.cc | 20 ++++++++++---------- 3 files changed, 17 insertions(+), 17 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 0d49e9e..65f64e0f 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -548720bca6bff21ebc9aba22249d9ce45bbd90c7 +ac438edc5335f69c95df9342f43712ad2f61ad66 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/gogo.cc b/gcc/go/gofrontend/gogo.cc index e13df0d..67b91fa 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -5302,16 +5302,16 @@ Gogo::write_c_header() Named_object* no = types.front(); types.pop_front(); - std::vector requires; + std::vector needs; std::vector 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_iterator pr - = requires.begin(); - pr != requires.end() && ok; + = needs.begin(); + pr != needs.end() && ok; ++pr) { for (std::list::const_iterator pt = types.begin(); @@ -5342,10 +5342,10 @@ Gogo::write_c_header() if (*pd == no) continue; - std::vector drequires; + std::vector dneeds; std::vector 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; diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index e82be68..4995283 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -6967,7 +6967,7 @@ Struct_type::do_import(Import* imp) bool Struct_type::can_write_to_c_header( - std::vector* requires, + std::vector* needs, std::vector* declare) const { const Struct_field_list* fields = this->fields_; @@ -6978,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++; @@ -6993,7 +6993,7 @@ Struct_type::can_write_to_c_header( bool Struct_type::can_write_type_to_c_header( const Type* t, - std::vector* requires, + std::vector* needs, std::vector* declare) const { t = t->forwarded(); @@ -7027,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: { @@ -7049,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: @@ -7150,9 +7150,9 @@ Struct_type::write_field_to_c_header(std::ostream& os, const std::string& name, case TYPE_POINTER: { - std::vector requires; + std::vector needs; std::vector 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 -- cgit v1.1 From fbd7665360d259434f378f68cb2680b17d6cab57 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Thu, 30 Jun 2022 17:40:00 -0700 Subject: compiler: use correct init order for multi-value initialization Use the correct initialization order for var a = c var b, c = x.(bool) The global c is initialized by the preinit of b, but were missing a dependency of c on b, so a would be initialized to the zero value of c rather than the correct value. Simply adding the dependency of c on b didn't work because the preinit of b refers to c, so that appeared circular. So this patch changes the init order to skip dependencies that only appear on the left hand side of assignments in preinit blocks. Doing that didn't work because the write barrier pass can transform "a = b" into code like "gcWriteBarrier(&a, b)" that is not obviously a simple assigment. So this patch moves the collection of dependencies to just after lowering, before the write barriers are inserted. Making those changes permit relaxing the requirement that we don't warn about self-dependency in preinit blocks, so now we correctly warn for var a, b any = b.(bool) The test case is https://go.dev/cl/415238. Fixes golang/go#53619 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/415594 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/go.cc | 3 + gcc/go/gofrontend/gogo.cc | 202 +++++++++++++++++++++++++-------------------- gcc/go/gofrontend/gogo.h | 23 +++++- gcc/go/gofrontend/parse.cc | 18 +++- 5 files changed, 150 insertions(+), 98 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 65f64e0f..7b1d301 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -ac438edc5335f69c95df9342f43712ad2f61ad66 +6479d5976c5d848ec6f5843041275723a00006b0 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/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 67b91fa..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* - 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* 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; - 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_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* refs = pvar->refs(); + const std::vector* refs = + pvar->var()->var_value()->init_refs(); if (refs == NULL) continue; for (std::vector::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* deprefs = dep_init->refs(); + const std::vector* deprefs = + dep_init->var()->var_value()->init_refs(); if (deprefs == NULL) continue; for (std::vector::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) @@ -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. @@ -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; + 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* + 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* init_refs_; // Any associated go:embed comments. std::vector* 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/parse.cc b/gcc/go/gofrontend/parse.cc index e388261..a3c6f63 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -1977,7 +1977,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()) { @@ -2044,7 +2048,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()) { @@ -2110,7 +2118,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()) { -- cgit v1.1 From ccc39d9e97ce24623aefae2097bff791e01619d9 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Mon, 4 Jul 2022 12:20:36 -0700 Subject: compiler: better error message for unknown package name Fixes golang/go#51237 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/415994 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/parse.cc | 6 +++++- 2 files changed, 6 insertions(+), 2 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 7b1d301..461e2fd 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -6479d5976c5d848ec6f5843041275723a00006b0 +a209dca9ec918535977dcab99fd9bb60986ffacd 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/parse.cc b/gcc/go/gofrontend/parse.cc index a3c6f63..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(); -- cgit v1.1 From c70a48a8f8f6a43b35f783b5672c9a3c0a363c31 Mon Sep 17 00:00:00 2001 From: Ian Lance Taylor Date: Sun, 3 Jul 2022 14:37:23 -0700 Subject: compiler: propagate array length error marker farther Fixes golang/go#53639 Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/415936 --- gcc/go/gofrontend/MERGE | 2 +- gcc/go/gofrontend/expressions.cc | 6 ++++++ gcc/go/gofrontend/types.cc | 5 ++++- 3 files changed, 11 insertions(+), 2 deletions(-) (limited to 'gcc/go') diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 461e2fd..7c5c456 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -a209dca9ec918535977dcab99fd9bb60986ffacd +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/expressions.cc b/gcc/go/gofrontend/expressions.cc index 00d35a9..2492d9f 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -8486,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); @@ -13391,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; } diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 4995283..9f34801 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -7429,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()); -- cgit v1.1