diff options
author | Thomas Koenig <tkoenig@gcc.gnu.org> | 2021-01-03 21:40:04 +0100 |
---|---|---|
committer | Thomas Koenig <tkoenig@gcc.gnu.org> | 2021-01-03 21:40:04 +0100 |
commit | afae4a55ccaa0de95ea11e5f634084db6ab2f444 (patch) | |
tree | d632cc867d10410ba9fb750523be790b86846ac4 /gcc/go | |
parent | 9d9a82ec8478ff52c7a9d61f58cd2a7b6295b5f9 (diff) | |
parent | d2eb616a0f7bea78164912aa438c29fe1ef5774a (diff) | |
download | gcc-afae4a55ccaa0de95ea11e5f634084db6ab2f444.zip gcc-afae4a55ccaa0de95ea11e5f634084db6ab2f444.tar.gz gcc-afae4a55ccaa0de95ea11e5f634084db6ab2f444.tar.bz2 |
Merge branch 'master' into devel/coarray_native
Diffstat (limited to 'gcc/go')
-rw-r--r-- | gcc/go/ChangeLog | 34 | ||||
-rw-r--r-- | gcc/go/Make-lang.in | 5 | ||||
-rw-r--r-- | gcc/go/go-gcc.cc | 4 | ||||
-rw-r--r-- | gcc/go/go-lang.c | 16 | ||||
-rw-r--r-- | gcc/go/gofrontend/MERGE | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/ast-dump.cc | 6 | ||||
-rw-r--r-- | gcc/go/gofrontend/escape.cc | 2 | ||||
-rw-r--r-- | gcc/go/gofrontend/export.cc | 11 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 344 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 21 | ||||
-rw-r--r-- | gcc/go/gofrontend/go-encode-id.cc | 289 | ||||
-rw-r--r-- | gcc/go/gofrontend/go-encode-id.h | 13 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 279 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 205 | ||||
-rw-r--r-- | gcc/go/gofrontend/import.cc | 18 | ||||
-rw-r--r-- | gcc/go/gofrontend/lex.cc | 11 | ||||
-rw-r--r-- | gcc/go/gofrontend/names.cc | 885 | ||||
-rw-r--r-- | gcc/go/gofrontend/parse.cc | 39 | ||||
-rw-r--r-- | gcc/go/gofrontend/runtime.def | 57 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 165 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.h | 48 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 252 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.h | 88 | ||||
-rw-r--r-- | gcc/go/gofrontend/wb.cc | 5 |
24 files changed, 1796 insertions, 1003 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index b25aa0c..4d611a1 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,37 @@ +2020-12-22 Ian Lance Taylor <iant@golang.org> + + PR go/98402 + * go-lang.c (go_langhook_init): Force MPFR exponent range to be + large enough to support Go constants. + +2020-11-20 Jakub Jelinek <jakub@redhat.com> + + PR other/97911 + * Make-lang.in (go.serial): Change from goal to a variable. + (.PHONY): Drop go.serial and go.prev. + (go1$(exeext)): Depend on $(go.serial) rather than go.serial. + +2020-11-18 Jakub Jelinek <jakub@redhat.com> + + * Make-lang.in (go.serial): New goal. + (.PHONY): Add go.serial go.prev. + (go1$(exeext)): Depend on go.prev. Call LINK_PROGRESS. + +2020-11-11 Alan Modra <amodra@gmail.com> + + * go-gcc.cc (Gcc_backend::global_variable_set_init): Cast NULL to + avoid ambiguous overloaded call. + +2020-11-06 Nathan Sidwell <nathan@acm.org> + + * go-gcc.cc (Gcc_backend::call_expression): Rename + DECL_IS_BUILTIN->DECL_IS_UNDECLARED_BUILTIN. + +2020-11-04 Ian Lance Taylor <iant@golang.org> + + * go-lang.c (go_langhook_post_options): Disable + -fipa-icf-functions if it was not explicitly enabled. + 2020-09-14 Jakub Jelinek <jakub@redhat.com> * go-gcc.cc (Gcc_backend::function): Adjust diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in index ce711b2..a987127 100644 --- a/gcc/go/Make-lang.in +++ b/gcc/go/Make-lang.in @@ -27,6 +27,7 @@ GCCGO_TARGET_INSTALL_NAME := $(target_noncanonical)-$(shell echo gccgo|sed '$(pr # The name for selecting go in LANGUAGES. go: go1$(exeext) +go.serial = go1$(exeext) .PHONY: go @@ -78,9 +79,11 @@ GO_OBJS = \ go_OBJS = $(GO_OBJS) go/gospec.o -go1$(exeext): $(GO_OBJS) attribs.o $(BACKEND) $(LIBDEPS) +go1$(exeext): $(GO_OBJS) attribs.o $(BACKEND) $(LIBDEPS) $(go.prev) + @$(call LINK_PROGRESS,$(INDEX.go),start) +$(LLINKER) $(ALL_LINKERFLAGS) $(LDFLAGS) -o $@ \ $(GO_OBJS) attribs.o $(BACKEND) $(LIBS) $(BACKENDLIBS) + @$(call LINK_PROGRESS,$(INDEX.go),end) # Documentation. diff --git a/gcc/go/go-gcc.cc b/gcc/go/go-gcc.cc index 505fb15..d8d9c3f 100644 --- a/gcc/go/go-gcc.cc +++ b/gcc/go/go-gcc.cc @@ -2110,7 +2110,7 @@ Gcc_backend::call_expression(Bfunction*, // containing fcn for call if (optimize && TREE_CODE(fndecl) == FUNCTION_DECL && fndecl_built_in_p (fndecl, BUILT_IN_NORMAL) - && DECL_IS_BUILTIN (fndecl) + && DECL_IS_UNDECLARED_BUILTIN (fndecl) && nargs > 0 && ((SCALAR_FLOAT_TYPE_P(rettype) && SCALAR_FLOAT_TYPE_P(TREE_TYPE(args[0]))) @@ -2756,7 +2756,7 @@ Gcc_backend::global_variable_set_init(Bvariable* var, Bexpression* expr) if (symtab_node::get(var_decl) && symtab_node::get(var_decl)->implicit_section) { - set_decl_section_name (var_decl, NULL); + set_decl_section_name (var_decl, (const char *) NULL); resolve_unique_section (var_decl, compute_reloc_for_constant (expr_tree), 1); diff --git a/gcc/go/go-lang.c b/gcc/go/go-lang.c index 2cfb410..9c0e7af 100644 --- a/gcc/go/go-lang.c +++ b/gcc/go/go-lang.c @@ -131,6 +131,16 @@ go_langhook_init (void) eventually be controllable by a command line option. */ mpfr_set_default_prec (256); + /* If necessary, override GCC's choice of minimum and maximum + exponents. This should only affect GCC middle-end + compilation-time, not correctness. */ + mpfr_exp_t exp = mpfr_get_emax (); + if (exp < (1 << 16) - 1) + mpfr_set_emax ((1 << 16) - 1); + exp = mpfr_get_emin (); + if (exp > - ((1 << 16) - 1)) + mpfr_set_emin (- ((1 << 16) - 1)); + /* Go uses exceptions. */ using_eh_for_cleanups (); @@ -306,6 +316,12 @@ go_langhook_post_options (const char **pfilename ATTRIBUTE_UNUSED) SET_OPTION_IF_UNSET (&global_options, &global_options_set, flag_partial_inlining, 0); + /* Go programs expect runtime.Callers to give the right answers, + which means that we can't combine functions even if they look the + same. */ + SET_OPTION_IF_UNSET (&global_options, &global_options_set, + flag_ipa_icf_functions, 0); + /* If the debug info level is still 1, as set in init_options, make sure that some debugging type is selected. */ if (global_options.x_debug_info_level == DINFO_LEVEL_TERSE diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 3ad6c96..fc5ef44 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -28f3df468666787f83f94220312383a7c267a8ce +47bdc8bb36f16f9d1dec72df5dd6b45d7b0b0725 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/ast-dump.cc b/gcc/go/gofrontend/ast-dump.cc index a3cbda9..eca0bf1 100644 --- a/gcc/go/gofrontend/ast-dump.cc +++ b/gcc/go/gofrontend/ast-dump.cc @@ -226,7 +226,11 @@ Ast_dump_context::dump_type(const Type* t) // FIXME: write a type pretty printer instead of // using mangled names. if (this->gogo_ != NULL) - this->ostream() << "(" << t->mangled_name(this->gogo_) << ")"; + { + Backend_name bname; + t->backend_name(this->gogo_, &bname); + this->ostream() << "(" << bname.name() << ")"; + } } // Dump a textual representation of a block to the diff --git a/gcc/go/gofrontend/escape.cc b/gcc/go/gofrontend/escape.cc index 8962f3f..cf68874 100644 --- a/gcc/go/gofrontend/escape.cc +++ b/gcc/go/gofrontend/escape.cc @@ -363,8 +363,6 @@ Node::op_format() const op << "append"; break; - case Runtime::SLICECOPY: - case Runtime::SLICESTRINGCOPY: case Runtime::TYPEDSLICECOPY: op << "copy"; break; diff --git a/gcc/go/gofrontend/export.cc b/gcc/go/gofrontend/export.cc index 277aa74..e99c680 100644 --- a/gcc/go/gofrontend/export.cc +++ b/gcc/go/gofrontend/export.cc @@ -461,7 +461,7 @@ should_export(Named_object* no) return false; // We don't export various special functions. - if (Gogo::is_special_name(no->name())) + if (Gogo::special_name_pos(no->name()) != std::string::npos) return false; // Methods are exported with the type, not here. @@ -524,7 +524,11 @@ struct Sort_types if (t1->classification() != t2->classification()) return t1->classification() < t2->classification(); Gogo* gogo = go_get_gogo(); - return gogo->type_descriptor_name(t1, NULL).compare(gogo->type_descriptor_name(t2, NULL)) < 0; + Backend_name b1; + gogo->type_descriptor_backend_name(t1, NULL, &b1); + Backend_name b2; + gogo->type_descriptor_backend_name(t2, NULL, &b2); + return b1.name() < b2.name(); } }; @@ -1211,6 +1215,9 @@ Export::write_type_definition(const Type* type, int index) this->write_string(nt->named_object()->name()); this->write_c_string("\" "); + if (!nt->in_heap()) + this->write_c_string("notinheap "); + if (nt->is_alias()) this->write_c_string("= "); } diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index e76bc69..17b4cfd 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -59,6 +59,67 @@ Expression::traverse_subexpressions(Traverse* traverse) return this->do_traverse(traverse); } +// A traversal used to set the location of subexpressions. + +class Set_location : public Traverse +{ + public: + Set_location(Location loc) + : Traverse(traverse_expressions), + loc_(loc) + { } + + int + expression(Expression** pexpr); + + private: + Location loc_; +}; + +// Set the location of an expression. + +int +Set_location::expression(Expression** pexpr) +{ + // Some expressions are shared or don't have an independent + // location, so we shouldn't change their location. This is the set + // of expressions for which do_copy is just "return this" or + // otherwise does not pass down the location. + switch ((*pexpr)->classification()) + { + case Expression::EXPRESSION_ERROR: + case Expression::EXPRESSION_VAR_REFERENCE: + case Expression::EXPRESSION_ENCLOSED_VAR_REFERENCE: + case Expression::EXPRESSION_STRING: + case Expression::EXPRESSION_FUNC_DESCRIPTOR: + case Expression::EXPRESSION_TYPE: + case Expression::EXPRESSION_BOOLEAN: + case Expression::EXPRESSION_CONST_REFERENCE: + case Expression::EXPRESSION_NIL: + case Expression::EXPRESSION_TYPE_DESCRIPTOR: + case Expression::EXPRESSION_GC_SYMBOL: + case Expression::EXPRESSION_PTRMASK_SYMBOL: + case Expression::EXPRESSION_TYPE_INFO: + case Expression::EXPRESSION_STRUCT_FIELD_OFFSET: + return TRAVERSE_CONTINUE; + default: + break; + } + + (*pexpr)->location_ = this->loc_; + return TRAVERSE_CONTINUE; +} + +// Set the location of an expression and its subexpressions. + +void +Expression::set_location(Location loc) +{ + this->location_ = loc; + Set_location sl(loc); + this->traverse_subexpressions(&sl); +} + // Default implementation for do_traverse for child classes. int @@ -113,7 +174,13 @@ Expression::export_name(Export_function_body* efb, const Named_object* no) void Expression::unused_value_error() { - this->report_error(_("value computed is not used")); + if (this->type()->is_error()) + { + go_assert(saw_errors()); + this->set_is_error(); + } + else + this->report_error(_("value computed is not used")); } // Note that this expression is an error. This is called by children @@ -827,8 +894,7 @@ Type_expression : public Expression { } void - do_check_types(Gogo*) - { this->report_error(_("invalid use of type")); } + do_check_types(Gogo*); Expression* do_copy() @@ -846,6 +912,18 @@ Type_expression : public Expression }; void +Type_expression::do_check_types(Gogo*) +{ + if (this->type_->is_error()) + { + go_assert(saw_errors()); + this->set_is_error(); + } + else + this->report_error(_("invalid use of type")); +} + +void Type_expression::do_dump_expression(Ast_dump_context* ast_dump_context) const { ast_dump_context->dump_type(this->type_); @@ -1596,7 +1674,8 @@ Func_descriptor_expression::do_get_backend(Translate_context* context) return context->backend()->var_expression(this->dvar_, loc); Gogo* gogo = context->gogo(); - std::string var_name(gogo->function_descriptor_name(no)); + Backend_name bname; + gogo->function_descriptor_backend_name(no, &bname); bool is_descriptor = false; if (no->is_function_declaration() && !no->func_declaration_value()->asm_name().empty() @@ -1616,10 +1695,11 @@ Func_descriptor_expression::do_get_backend(Translate_context* context) Btype* btype = this->type()->get_backend(gogo); Bvariable* bvar; - std::string asm_name(go_selectively_encode_id(var_name)); if (no->package() != NULL || is_descriptor) - bvar = context->backend()->immutable_struct_reference(var_name, asm_name, - btype, loc); + bvar = + context->backend()->immutable_struct_reference(bname.name(), + bname.optional_asm_name(), + btype, loc); else { Location bloc = Linemap::predeclared_location(); @@ -1644,7 +1724,8 @@ Func_descriptor_expression::do_get_backend(Translate_context* context) if (no->is_function() && no->func_value()->is_referenced_by_inline()) is_hidden = false; - bvar = context->backend()->immutable_struct(var_name, asm_name, + bvar = context->backend()->immutable_struct(bname.name(), + bname.optional_asm_name(), is_hidden, false, btype, bloc); Expression_list* vals = new Expression_list(); @@ -1654,8 +1735,9 @@ Func_descriptor_expression::do_get_backend(Translate_context* context) Translate_context bcontext(gogo, NULL, NULL, NULL); bcontext.set_is_const(); Bexpression* binit = init->get_backend(&bcontext); - context->backend()->immutable_struct_set_init(bvar, var_name, is_hidden, - false, btype, bloc, binit); + context->backend()->immutable_struct_set_init(bvar, bname.name(), + is_hidden, false, btype, + bloc, binit); } this->dvar_ = bvar; @@ -4020,8 +4102,16 @@ Type_conversion_expression::do_string_constant_value(std::string* val) const unsigned long ival; if (nc.to_unsigned_long(&ival) == Numeric_constant::NC_UL_VALID) { + unsigned int cval = static_cast<unsigned int>(ival); + if (static_cast<unsigned long>(cval) != ival) + { + go_warning_at(this->location(), 0, + "unicode code point 0x%lx out of range", + ival); + cval = 0xfffd; // Unicode "replacement character." + } val->clear(); - Lex::append_char(ival, true, val, this->location()); + Lex::append_char(cval, true, val, this->location()); return true; } } @@ -5190,11 +5280,9 @@ Unary_expression::do_get_backend(Translate_context* context) copy_to_heap = (context->function() != NULL || context->is_const()); } - std::string asm_name(go_selectively_encode_id(var_name)); Bvariable* implicit = - gogo->backend()->implicit_variable(var_name, asm_name, - btype, true, copy_to_heap, - false, 0); + gogo->backend()->implicit_variable(var_name, "", btype, true, + copy_to_heap, false, 0); gogo->backend()->implicit_variable_set_init(implicit, var_name, btype, true, copy_to_heap, false, bexpr); @@ -5219,10 +5307,9 @@ Unary_expression::do_get_backend(Translate_context* context) && this->expr_->is_static_initializer()) { std::string var_name(gogo->initializer_name()); - std::string asm_name(go_selectively_encode_id(var_name)); Bvariable* decl = - gogo->backend()->immutable_struct(var_name, asm_name, - true, false, btype, loc); + gogo->backend()->immutable_struct(var_name, "", true, false, + btype, loc); gogo->backend()->immutable_struct_set_init(decl, var_name, true, false, btype, loc, bexpr); bexpr = gogo->backend()->var_expression(decl, loc); @@ -5230,9 +5317,8 @@ Unary_expression::do_get_backend(Translate_context* context) else if (this->expr_->is_constant()) { std::string var_name(gogo->initializer_name()); - std::string asm_name(go_selectively_encode_id(var_name)); Bvariable* decl = - gogo->backend()->implicit_variable(var_name, asm_name, btype, + gogo->backend()->implicit_variable(var_name, "", btype, true, true, false, 0); gogo->backend()->implicit_variable_set_init(decl, var_name, btype, true, true, false, @@ -5248,7 +5334,6 @@ Unary_expression::do_get_backend(Translate_context* context) { go_assert(this->expr_->type()->points_to() != NULL); - bool known_valid = false; Type* ptype = this->expr_->type()->points_to(); Btype* pbtype = ptype->get_backend(gogo); switch (this->requires_nil_check(gogo)) @@ -5289,14 +5374,12 @@ Unary_expression::do_get_backend(Translate_context* context) compare, bcrash, ubexpr, loc); - known_valid = true; break; } case NIL_CHECK_DEFAULT: go_unreachable(); } - ret = gogo->backend()->indirect_expression(pbtype, bexpr, - known_valid, loc); + ret = gogo->backend()->indirect_expression(pbtype, bexpr, false, loc); } break; @@ -6279,8 +6362,21 @@ Binary_expression::lower_array_comparison(Gogo* gogo, args->push_back(this->operand_address(inserter, this->left_)); args->push_back(this->operand_address(inserter, this->right_)); - Expression* ret = Expression::make_call(func, args, false, loc); - + Call_expression* ce = Expression::make_call(func, args, false, loc); + + // Record that this is a call to a generated equality function. We + // need to do this because a comparison returns an abstract boolean + // type, but the function necessarily returns "bool". The + // difference shows up in code like + // type mybool bool + // var b mybool = [10]string{} == [10]string{} + // The comparison function returns "bool", but since a comparison + // has an abstract boolean type we need an implicit conversion to + // "mybool". The implicit conversion is inserted in + // Call_expression::do_flatten. + ce->set_is_equal_function(); + + Expression* ret = ce; if (this->op_ == OPERATOR_NOTEQ) ret = Expression::make_unary(OPERATOR_NOT, ret, loc); @@ -6971,27 +7067,6 @@ Binary_expression::do_get_backend(Translate_context* context) // been converted to a String_concat_expression in do_lower. go_assert(!left_type->is_string_type()); - // For complex division Go might want slightly different results than the - // backend implementation provides, so we have our own runtime routine. - if (this->op_ == OPERATOR_DIV && this->left_->type()->complex_type() != NULL) - { - Runtime::Function complex_code; - switch (this->left_->type()->complex_type()->bits()) - { - case 64: - complex_code = Runtime::COMPLEX64_DIV; - break; - case 128: - complex_code = Runtime::COMPLEX128_DIV; - break; - default: - go_unreachable(); - } - Expression* complex_div = - Runtime::make_call(complex_code, loc, 2, this->left_, this->right_); - return complex_div->get_backend(context); - } - Bexpression* left = this->left_->get_backend(context); Bexpression* right = this->right_->get_backend(context); @@ -8885,8 +8960,8 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, // We will optimize this to directly zeroing the tail, // instead of allocating a new slice then copy. - // Retrieve the length. Cannot reference s2 as we will remove - // the makeslice call. + // Retrieve the length and capacity. Cannot reference s2 as + // we will remove the makeslice call. Expression* len_arg = makecall->args()->at(1); len_arg = Expression::make_cast(int_type, len_arg, loc); l2tmp = Statement::make_temporary(int_type, len_arg, loc); @@ -8899,28 +8974,19 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function, inserter->insert(c2tmp); // Check bad len/cap here. - // if len2 < 0 { panicmakeslicelen(); } + // checkmakeslice(type, len, cap) + // (Note that if len and cap are constants, we won't see a + // makeslice call here, as it will be rewritten to a stack + // allocated array by Mark_address_taken::expression.) + Expression* elem = Expression::make_type_descriptor(element_type, + loc); len2 = Expression::make_temporary_reference(l2tmp, loc); - Expression* zero = Expression::make_integer_ul(0, int_type, loc); - Expression* cond = Expression::make_binary(OPERATOR_LT, len2, - zero, loc); - Expression* call = Runtime::make_call(Runtime::PANIC_MAKE_SLICE_LEN, - loc, 0); - cond = Expression::make_conditional(cond, call, zero->copy(), loc); - gogo->lower_expression(function, inserter, &cond); - gogo->flatten_expression(function, inserter, &cond); - Statement* s = Statement::make_statement(cond, false); - inserter->insert(s); - - // if cap2 < 0 { panicmakeslicecap(); } Expression* cap2 = Expression::make_temporary_reference(c2tmp, loc); - cond = Expression::make_binary(OPERATOR_LT, cap2, - zero->copy(), loc); - call = Runtime::make_call(Runtime::PANIC_MAKE_SLICE_CAP, loc, 0); - cond = Expression::make_conditional(cond, call, zero->copy(), loc); - gogo->lower_expression(function, inserter, &cond); - gogo->flatten_expression(function, inserter, &cond); - s = Statement::make_statement(cond, false); + Expression* check = Runtime::make_call(Runtime::CHECK_MAKE_SLICE, + loc, 3, elem, len2, cap2); + gogo->lower_expression(function, inserter, &check); + gogo->flatten_expression(function, inserter, &check); + Statement* s = Statement::make_statement(check, false); inserter->insert(s); // Remove the original makeslice call. @@ -9398,6 +9464,8 @@ Builtin_call_expression::do_is_constant() const if (arg == NULL) return false; Type* arg_type = arg->type(); + if (arg_type->is_error()) + return true; if (arg_type->points_to() != NULL && arg_type->points_to()->array_type() != NULL @@ -9469,6 +9537,8 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const if (arg == NULL) return false; Type* arg_type = arg->type(); + if (arg_type->is_error()) + return false; if (this->code_ == BUILTIN_LEN && arg_type->is_string_type()) { @@ -9491,17 +9561,25 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const { if (this->seen_) return false; - Expression* e = arg_type->array_type()->length(); - this->seen_ = true; - bool r = e->numeric_constant_value(nc); - this->seen_ = false; - if (r) + + // We may be replacing this expression with a constant + // during lowering, so verify the type to report any errors. + // It's OK to verify an array type more than once. + arg_type->verify(); + if (!arg_type->is_error()) { - if (!nc->set_type(Type::lookup_integer_type("int"), false, - this->location())) - r = false; + Expression* e = arg_type->array_type()->length(); + this->seen_ = true; + bool r = e->numeric_constant_value(nc); + this->seen_ = false; + if (r) + { + if (!nc->set_type(Type::lookup_integer_type("int"), false, + this->location())) + r = false; + } + return r; } - return r; } } else if (this->code_ == BUILTIN_SIZEOF @@ -11185,6 +11263,13 @@ Call_expression::do_flatten(Gogo* gogo, Named_object*, return ret; } + // Add an implicit conversion to a boolean type, if needed. See the + // comment in Binary_expression::lower_array_comparison. + if (this->is_equal_function_ + && this->type_ != NULL + && this->type_ != Type::lookup_bool_type()) + return Expression::make_cast(this->type_, this, this->location()); + return this; } @@ -11960,7 +12045,7 @@ Call_expression::do_type() // parameter types to set the types of the arguments. void -Call_expression::do_determine_type(const Type_context*) +Call_expression::do_determine_type(const Type_context* context) { if (!this->determining_types()) return; @@ -12007,6 +12092,22 @@ Call_expression::do_determine_type(const Type_context*) (*pa)->determine_type_no_context(); } } + + // If this is a call to a generated equality function, we determine + // the type based on the context. See the comment in + // Binary_expression::lower_array_comparison. + if (this->is_equal_function_ + && !context->may_be_abstract + && context->type != NULL + && context->type->is_boolean_type() + && context->type != Type::lookup_bool_type()) + { + go_assert(this->type_ == NULL + || this->type_ == Type::lookup_bool_type() + || this->type_ == context->type + || this->type_->is_error()); + this->type_ = context->type; + } } // Called when determining types for a Call_expression. Return true @@ -12794,24 +12895,11 @@ Array_index_expression::do_determine_type(const Type_context*) this->array_->determine_type_no_context(); Type_context index_context(Type::lookup_integer_type("int"), false); - if (this->start_->is_constant()) - this->start_->determine_type(&index_context); - else - this->start_->determine_type_no_context(); + this->start_->determine_type(&index_context); if (this->end_ != NULL) - { - if (this->end_->is_constant()) - this->end_->determine_type(&index_context); - else - this->end_->determine_type_no_context(); - } + this->end_->determine_type(&index_context); if (this->cap_ != NULL) - { - if (this->cap_->is_constant()) - this->cap_->determine_type(&index_context); - else - this->cap_->determine_type_no_context(); - } + this->cap_->determine_type(&index_context); } // Check types of an array index. @@ -13248,7 +13336,8 @@ Array_index_expression::do_get_backend(Translate_context* context) Type* ele_type = this->array_->type()->array_type()->element_type(); Btype* ele_btype = ele_type->get_backend(gogo); - ret = gogo->backend()->indirect_expression(ele_btype, ptr, true, loc); + ret = gogo->backend()->indirect_expression(ele_btype, ptr, false, + loc); } return ret; } @@ -13467,7 +13556,7 @@ Type* String_index_expression::do_type() { if (this->end_ == NULL) - return Type::lookup_integer_type("uint8"); + return Type::lookup_integer_type("byte"); else return this->string_->type(); } @@ -13480,17 +13569,9 @@ String_index_expression::do_determine_type(const Type_context*) this->string_->determine_type_no_context(); Type_context index_context(Type::lookup_integer_type("int"), false); - if (this->start_->is_constant()) - this->start_->determine_type(&index_context); - else - this->start_->determine_type_no_context(); + this->start_->determine_type(&index_context); if (this->end_ != NULL) - { - if (this->end_->is_constant()) - this->end_->determine_type(&index_context); - else - this->end_->determine_type_no_context(); - } + this->end_->determine_type(&index_context); } // Check types of a string index. @@ -13596,7 +13677,7 @@ String_index_expression::do_get_backend(Translate_context* context) { ptr = gogo->backend()->pointer_offset_expression(ptr, bstart, loc); Btype* ubtype = Type::lookup_integer_type("uint8")->get_backend(gogo); - return gogo->backend()->indirect_expression(ubtype, ptr, true, loc); + return gogo->backend()->indirect_expression(ubtype, ptr, false, loc); } Expression* end = NULL; @@ -14028,7 +14109,7 @@ Field_reference_expression::do_lower(Gogo* gogo, Named_object* function, Expression* length_expr = Expression::make_integer_ul(s.length(), NULL, loc); - Type* byte_type = gogo->lookup_global("byte")->type_value(); + Type* byte_type = Type::lookup_integer_type("byte"); Array_type* array_type = Type::make_array_type(byte_type, length_expr); array_type->set_is_array_incomparable(); @@ -15295,9 +15376,22 @@ Array_construction_expression::do_is_static_initializer() const void Array_construction_expression::do_determine_type(const Type_context*) { + if (this->is_error_expression()) + { + go_assert(saw_errors()); + return; + } + if (this->vals() == NULL) return; - Type_context subcontext(this->type_->array_type()->element_type(), false); + Array_type* at = this->type_->array_type(); + if (at == NULL || at->is_error() || at->element_type()->is_error()) + { + go_assert(saw_errors()); + this->set_is_error(); + return; + } + Type_context subcontext(at->element_type(), false); for (Expression_list::const_iterator pv = this->vals()->begin(); pv != this->vals()->end(); ++pv) @@ -15312,10 +15406,22 @@ Array_construction_expression::do_determine_type(const Type_context*) void Array_construction_expression::do_check_types(Gogo*) { + if (this->is_error_expression()) + { + go_assert(saw_errors()); + return; + } + if (this->vals() == NULL) return; Array_type* at = this->type_->array_type(); + if (at == NULL || at->is_error() || at->element_type()->is_error()) + { + go_assert(saw_errors()); + this->set_is_error(); + return; + } int i = 0; Type* element_type = at->element_type(); for (Expression_list::const_iterator pv = this->vals()->begin(); @@ -15340,6 +15446,12 @@ Expression* Array_construction_expression::do_flatten(Gogo*, Named_object*, Statement_inserter* inserter) { + if (this->is_error_expression()) + { + go_assert(saw_errors()); + return this; + } + if (this->vals() == NULL) return this; @@ -15376,6 +15488,12 @@ Array_construction_expression::do_flatten(Gogo*, Named_object*, void Array_construction_expression::do_add_conversions() { + if (this->is_error_expression()) + { + go_assert(saw_errors()); + return; + } + if (this->vals() == NULL) return; @@ -18251,9 +18369,8 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) { // The interface conversion table is defined elsewhere. Btype* btype = this->type()->get_backend(gogo); - std::string asm_name(go_selectively_encode_id(mangled_name)); this->bvar_ = - gogo->backend()->immutable_struct_reference(mangled_name, asm_name, + gogo->backend()->immutable_struct_reference(mangled_name, "", btype, loc); return gogo->backend()->var_expression(this->bvar_, this->location()); } @@ -18323,8 +18440,7 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) Bexpression* ctor = gogo->backend()->constructor_expression(btype, ctor_bexprs, loc); - std::string asm_name(go_selectively_encode_id(mangled_name)); - this->bvar_ = gogo->backend()->immutable_struct(mangled_name, asm_name, false, + this->bvar_ = gogo->backend()->immutable_struct(mangled_name, "", false, !is_public, btype, loc); gogo->backend()->immutable_struct_set_init(this->bvar_, mangled_name, false, !is_public, btype, loc, ctor); diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index d297523..712f687 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -549,6 +549,16 @@ class Expression location() const { return this->location_; } + // Set the location of an expression and all its subexpressions. + // This is used for const declarations where the expression is + // copied from an earlier declaration. + void + set_location(Location loc); + + // For set_location. This should really be a local class in + // Expression, but it needs types defined in gogo.h. + friend class Set_location; + // Return whether this is a constant expression. bool is_constant() const @@ -2326,8 +2336,8 @@ class Call_expression : public Expression fn_(fn), args_(args), type_(NULL), call_(NULL), call_temp_(NULL) , expected_result_count_(0), is_varargs_(is_varargs), varargs_are_lowered_(false), types_are_determined_(false), - is_deferred_(false), is_concurrent_(false), issued_error_(false), - is_multi_value_arg_(false), is_flattened_(false) + is_deferred_(false), is_concurrent_(false), is_equal_function_(false), + issued_error_(false), is_multi_value_arg_(false), is_flattened_(false) { } // The function to call. @@ -2408,6 +2418,11 @@ class Call_expression : public Expression set_is_concurrent() { this->is_concurrent_ = true; } + // Note that this is a call to a generated equality function. + void + set_is_equal_function() + { this->is_equal_function_ = true; } + // We have found an error with this call expression; return true if // we should report it. bool @@ -2545,6 +2560,8 @@ class Call_expression : public Expression bool is_deferred_; // True if the call is an argument to a go statement. bool is_concurrent_; + // True if this is a call to a generated equality function. + bool is_equal_function_; // True if we reported an error about a mismatch between call // results and uses. This is to avoid producing multiple errors // when there are multiple Call_result_expressions. diff --git a/gcc/go/gofrontend/go-encode-id.cc b/gcc/go/gofrontend/go-encode-id.cc index 550da97..7ab65f5 100644 --- a/gcc/go/gofrontend/go-encode-id.cc +++ b/gcc/go/gofrontend/go-encode-id.cc @@ -12,8 +12,8 @@ #include "go-encode-id.h" #include "lex.h" -// Return whether the character c is OK to use in the assembler. We -// only permit ASCII alphanumeric characters, underscore, and dot. +// Return whether the character c can appear in a name that we are +// encoding. We only permit ASCII alphanumeric characters. static bool char_needs_encoding(char c) @@ -32,7 +32,6 @@ char_needs_encoding(char c) case 'y': case 'z': case '0': case '1': case '2': case '3': case '4': case '5': case '6': case '7': case '8': case '9': - case '_': case '.': return false; default: return true; @@ -53,6 +52,52 @@ go_id_needs_encoding(const std::string& str) return false; } +// Map from characters to the underscore encoding for them. + +class Special_char_code +{ + public: + Special_char_code(); + + // Return the simple underscore encoding for C, or 0 if none. + char + code_for(unsigned int c) const + { + if (c <= 127) + return this->codes_[c]; + return 0; + } + + private: + // Encodings for characters. + char codes_[128]; +}; + +// Construct the underscore encoding map. + +Special_char_code::Special_char_code() +{ + memset(this->codes_, 0, sizeof this->codes_); + this->codes_['_'] = '_'; + this->codes_['.'] = '0'; + this->codes_['/'] = '1'; + this->codes_['*'] = '2'; + this->codes_[','] = '3'; + this->codes_['{'] = '4'; + this->codes_['}'] = '5'; + this->codes_['['] = '6'; + this->codes_[']'] = '7'; + this->codes_['('] = '8'; + this->codes_[')'] = '9'; + this->codes_['"'] = 'a'; + this->codes_[' '] = 'b'; + this->codes_[';'] = 'c'; +} + +// The singleton Special_char_code. + +static const Special_char_code special_char_code; + // Pull the next UTF-8 character out of P and store it in *PC. Return // the number of bytes read. @@ -82,10 +127,9 @@ fetch_utf8_char(const char* p, unsigned int* pc) return len; } -// Encode an identifier using assembler-friendly characters. The encoding is -// described in detail near the end of the long comment at the start of -// names.cc. Short version: translate all non-ASCII-alphanumeric characters into -// ..uXXXX or ..UXXXXXXXX, translate ASCII non-alphanumerics into ".zXX". +// Encode an identifier using assembler-friendly characters. The +// encoding is described in detail near the end of the long comment at +// the start of names.cc. std::string go_encode_id(const std::string &id) @@ -96,50 +140,57 @@ go_encode_id(const std::string &id) return id; } - // The encoding is only unambiguous if the input string does not - // contain ..z, ..u or ..U. - go_assert(id.find("..z") == std::string::npos); - go_assert(id.find("..u") == std::string::npos); - go_assert(id.find("..U") == std::string::npos); - std::string ret; const char* p = id.c_str(); const char* pend = p + id.length(); - // A leading ".0" is a space introduced before a mangled type name - // that starts with a 'u' or 'U', to avoid confusion with the - // mangling used here. We don't need a leading ".0", and we don't - // want symbols that start with '.', so remove it. - if (p[0] == '.' && p[1] == '0') - p += 2; + // We encode a leading digit, to ensure that no identifier starts + // with a digit. + if (pend > p && p[0] >= '0' && p[0] <= '9') + { + char buf[8]; + snprintf(buf, sizeof buf, "_x%02x", p[0]); + ret.append(buf); + ++p; + } while (p < pend) { unsigned int c; size_t len = fetch_utf8_char(p, &c); - if (len == 1 && !char_needs_encoding(c)) + if (len == 1) { - ret += c; + if (!char_needs_encoding(c)) + ret.push_back(c); + else + { + char code = special_char_code.code_for(c); + if (code != 0) + { + ret.push_back('_'); + ret.push_back(code); + } + else + { + char buf[8]; + snprintf(buf, sizeof buf, "_x%02x", c); + ret.append(buf); + } + } } else { char buf[16]; - if (len == 1) - snprintf(buf, sizeof buf, "..z%02x", c); - else if (c < 0x10000) - snprintf(buf, sizeof buf, "..u%04x", c); + if (c < 0x10000) + snprintf(buf, sizeof buf, "_u%04x", c); else - snprintf(buf, sizeof buf, "..U%08x", c); - - // We don't want a symbol to start with '.', so add a prefix - // if needed. - if (ret.empty()) - ret += '_'; - - ret += buf; + snprintf(buf, sizeof buf, "_U%08x", c); + ret.append(buf); } + p += len; } + return ret; } @@ -170,64 +221,116 @@ go_decode_id(const std::string &encoded) const char* pend = p + encoded.length(); const Location loc = Linemap::predeclared_location(); - // Special case for initial "_", in case it was introduced - // as a way to prevent encoded symbol starting with ".". - if (*p == '_' && (strncmp(p+1, "..u", 3) == 0 || strncmp(p+1, "..U", 3) == 0)) - p++; - while (p < pend) { - if (strncmp(p, "..z", 3) == 0) - { - const char* digits = p+3; - if (strlen(digits) < 2) - return ""; - unsigned rune = hex_digits_to_unicode_codepoint(digits, 2); - Lex::append_char(rune, true, &ret, loc); - p += 5; - } - else if (strncmp(p, "..u", 3) == 0) - { - const char* digits = p+3; - if (strlen(digits) < 4) - return ""; - unsigned rune = hex_digits_to_unicode_codepoint(digits, 4); - Lex::append_char(rune, true, &ret, loc); - p += 7; - } - else if (strncmp(p, "..U", 3) == 0) - { - const char* digits = p+3; - if (strlen(digits) < 8) - return ""; - unsigned rune = hex_digits_to_unicode_codepoint(digits, 8); - Lex::append_char(rune, true, &ret, loc); - p += 11; - } - else - { - ret += *p; - p += 1; - } + if (*p != '_' || p + 1 == pend) + { + ret.push_back(*p); + p++; + continue; + } + + switch (p[1]) + { + case '_': + ret.push_back('_'); + p += 2; + break; + case '0': + ret.push_back('.'); + p += 2; + break; + case '1': + ret.push_back('/'); + p += 2; + break; + case '2': + ret.push_back('*'); + p += 2; + break; + case '3': + ret.push_back(','); + p += 2; + break; + case '4': + ret.push_back('{'); + p += 2; + break; + case '5': + ret.push_back('}'); + p += 2; + break; + case '6': + ret.push_back('['); + p += 2; + break; + case '7': + ret.push_back(']'); + p += 2; + break; + case '8': + ret.push_back('('); + p += 2; + break; + case '9': + ret.push_back(')'); + p += 2; + break; + case 'a': + ret.push_back('"'); + p += 2; + break; + case 'b': + ret.push_back(' '); + p += 2; + break; + case 'c': + ret.push_back(';'); + p += 2; + break; + case 'x': + { + const char* digits = p + 2; + if (strlen(digits) < 2) + return ""; + unsigned int rune = hex_digits_to_unicode_codepoint(digits, 2); + Lex::append_char(rune, true, &ret, loc); + p += 4; + } + break; + case 'u': + { + const char* digits = p + 2; + if (strlen(digits) < 4) + return ""; + unsigned int rune = hex_digits_to_unicode_codepoint(digits, 4); + Lex::append_char(rune, true, &ret, loc); + p += 6; + } + break; + case 'U': + { + const char* digits = p + 2; + if (strlen(digits) < 8) + return ""; + unsigned int rune = hex_digits_to_unicode_codepoint(digits, 8); + Lex::append_char(rune, true, &ret, loc); + p += 10; + } + break; + default: + return ""; + } } return ret; } -std::string -go_selectively_encode_id(const std::string &id) -{ - if (go_id_needs_encoding(id)) - return go_encode_id(id); - return std::string(); -} - // Encode a struct field tag. This is only used when we need to // create a type descriptor for an anonymous struct type with field -// tags. This mangling is applied before go_encode_id. We skip -// alphanumerics and underscore, replace every other single byte -// character with .xNN, and leave larger UTF-8 characters for -// go_encode_id. +// tags. Underscore encoding will be applied to the returned string. +// The tag will appear between curly braces, so that is all we have to +// avoid. std::string go_mangle_struct_tag(const std::string& tag) @@ -241,28 +344,14 @@ go_mangle_struct_tag(const std::string& tag) size_t len = fetch_utf8_char(p, &c); if (len > 1) ret.append(p, len); - else if (!char_needs_encoding(c) && c != '.') - ret += c; + else if (c != '{' && c != '}' && c != '\\') + ret.push_back(c); else { - char buf[16]; - snprintf(buf, sizeof buf, ".x%02x", c); - ret += buf; + ret.push_back('\\'); + ret.push_back(c); } p += len; } return ret; } - -// Encode a package path. - -std::string -go_mangle_pkgpath(const std::string& pkgpath) -{ - std::string s = pkgpath; - for (size_t i = s.find('.'); - i != std::string::npos; - i = s.find('.', i + 1)) - s.replace(i, 1, ".x2e"); // 0x2e is the ASCII encoding for '.' - return s; -} diff --git a/gcc/go/gofrontend/go-encode-id.h b/gcc/go/gofrontend/go-encode-id.h index 2d09b0c..cbafd54 100644 --- a/gcc/go/gofrontend/go-encode-id.h +++ b/gcc/go/gofrontend/go-encode-id.h @@ -25,21 +25,8 @@ go_encode_id(const std::string &id); extern std::string go_decode_id(const std::string &id); -// Returns the empty string if the specified name needs encoding, -// otherwise invokes go_encode_id on the name and returns the result. -extern std::string -go_selectively_encode_id(const std::string &id); - // Encodes a struct tag that appears in a type literal encoding. extern std::string go_mangle_struct_tag(const std::string& tag); -// Encode a package path. A package path can contain any arbitrary -// character, including '.'. go_encode_id expects that any '.' will -// be inserted by name mangling in a controlled manner. So first -// translate any '.' using the same .x encoding as used by -// go_mangle_struct_tag. -extern std::string -go_mangle_pkgpath(const std::string& pkgpath); - #endif // !defined(GO_ENCODE_ID_H) diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index f40f131..fbf8935 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -117,17 +117,11 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int, int pointer_size) // "byte" is an alias for "uint8". uint8_type->integer_type()->set_is_byte(); - Named_object* byte_type = Named_object::make_type("byte", NULL, uint8_type, - loc); - byte_type->type_value()->set_is_alias(); - this->add_named_type(byte_type->type_value()); + this->add_named_type(Type::make_integer_type_alias("byte", uint8_type)); // "rune" is an alias for "int32". int32_type->integer_type()->set_is_rune(); - Named_object* rune_type = Named_object::make_type("rune", NULL, int32_type, - loc); - rune_type->type_value()->set_is_alias(); - this->add_named_type(rune_type->type_value()); + this->add_named_type(Type::make_integer_type_alias("rune", int32_type)); this->add_named_type(Type::make_named_bool_type()); @@ -299,7 +293,7 @@ void Gogo::set_pkgpath(const std::string& arg) { go_assert(!this->pkgpath_set_); - this->pkgpath_ = go_mangle_pkgpath(arg); + this->pkgpath_ = arg; this->pkgpath_set_ = true; this->pkgpath_from_option_ = true; } @@ -324,32 +318,6 @@ Gogo::set_prefix(const std::string& arg) this->prefix_from_option_ = true; } -// Given a name which may or may not have been hidden, append the -// appropriate version of the name to the result string. Take care -// to avoid creating a sequence that will be rejected by go_encode_id -// (avoid ..u, ..U, ..z). -void -Gogo::append_possibly_hidden_name(std::string *result, const std::string& name) -{ - // FIXME: This adds in pkgpath twice for hidden symbols, which is - // less than ideal. - if (!Gogo::is_hidden_name(name)) - (*result) += name; - else - { - std::string n = "."; - std::string pkgpath = Gogo::hidden_name_pkgpath(name); - char lastR = result->at(result->length() - 1); - char firstP = pkgpath.at(0); - if (lastR == '.' && (firstP == 'u' || firstP == 'U' || firstP == 'z')) - n = "_."; - n.append(pkgpath); - n.append(1, '.'); - n.append(Gogo::unpack_hidden_name(name)); - (*result) += n; - } -} - // Munge name for use in an error message. std::string @@ -397,8 +365,7 @@ Gogo::set_package_name(const std::string& package_name, { if (!this->prefix_from_option_) this->prefix_ = "go"; - this->pkgpath_ = (go_mangle_pkgpath(this->prefix_) + '.' - + package_name); + this->pkgpath_ = this->prefix_ + '.' + package_name; this->pkgpath_symbol_ = (Gogo::pkgpath_for_symbol(this->prefix_) + '.' + Gogo::pkgpath_for_symbol(package_name)); } @@ -792,7 +759,7 @@ Gogo::register_gc_vars(const std::vector<Named_object*>& var_gc, Type* pvt = Type::make_pointer_type(Type::make_void_type()); Type* uintptr_type = Type::lookup_integer_type("uintptr"); - Type* byte_type = this->lookup_global("byte")->type_value(); + Type* byte_type = Type::lookup_integer_type("byte"); Type* pointer_byte_type = Type::make_pointer_type(byte_type); Struct_type* root_type = Type::make_builtin_struct_type(4, @@ -997,9 +964,9 @@ Gogo::register_type_descriptors(std::vector<Bstatement*>& init_stmts, it != this->imported_init_fns_.end(); ++it) { - std::string pkgpath = - this->pkgpath_from_init_fn_name((*it)->init_name()); - list_names.push_back(this->type_descriptor_list_symbol(pkgpath)); + std::string pkgpath_symbol = + this->pkgpath_symbol_from_init_fn_name((*it)->init_name()); + list_names.push_back(this->type_descriptor_list_symbol(pkgpath_symbol)); } // Add the main package itself. list_names.push_back(this->type_descriptor_list_symbol("main")); @@ -1591,6 +1558,17 @@ Gogo::write_globals() || (no->is_const() && no->const_value()->is_sink())) continue; + // Skip global sink variables with static initializers. With + // non-static initializers we have to evaluate for side effects, + // and we wind up initializing a dummy variable. That is not + // ideal but it works and it's a rare case. + if (no->is_variable() + && no->var_value()->is_global_sink() + && !no->var_value()->has_pre_init() + && (no->var_value()->init() == NULL + || no->var_value()->init()->is_static_initializer())) + continue; + // There is nothing useful we can output for constants which // have ideal or non-integral type. if (no->is_const()) @@ -2746,8 +2724,7 @@ Gogo::clear_file_scope() // parse tree is lowered. void -Gogo::queue_hash_function(Type* type, int64_t size, - const std::string& hash_name, +Gogo::queue_hash_function(Type* type, int64_t size, Backend_name* bname, Function_type* hash_fntype) { go_assert(!this->specific_type_functions_are_written_); @@ -2755,7 +2732,7 @@ Gogo::queue_hash_function(Type* type, int64_t size, Specific_type_function::Specific_type_function_kind kind = Specific_type_function::SPECIFIC_HASH; Specific_type_function* tsf = new Specific_type_function(type, NULL, size, - kind, hash_name, + kind, bname, hash_fntype); this->specific_type_functions_.push_back(tsf); } @@ -2766,15 +2743,14 @@ Gogo::queue_hash_function(Type* type, int64_t size, void Gogo::queue_equal_function(Type* type, Named_type* name, int64_t size, - const std::string& equal_name, - Function_type* equal_fntype) + Backend_name* bname, Function_type* equal_fntype) { go_assert(!this->specific_type_functions_are_written_); go_assert(!this->in_global_scope()); Specific_type_function::Specific_type_function_kind kind = Specific_type_function::SPECIFIC_EQUAL; Specific_type_function* tsf = new Specific_type_function(type, name, size, - kind, equal_name, + kind, bname, equal_fntype); this->specific_type_functions_.push_back(tsf); } @@ -2872,11 +2848,11 @@ Gogo::write_specific_type_functions() Specific_type_function* tsf = this->specific_type_functions_.back(); this->specific_type_functions_.pop_back(); if (tsf->kind == Specific_type_function::SPECIFIC_HASH) - tsf->type->write_hash_function(this, tsf->size, tsf->fnname, + tsf->type->write_hash_function(this, tsf->size, &tsf->bname, tsf->fntype); else tsf->type->write_equal_function(this, tsf->name, tsf->size, - tsf->fnname, tsf->fntype); + &tsf->bname, tsf->fntype); delete tsf; } this->specific_type_functions_are_written_ = true; @@ -3773,7 +3749,7 @@ Check_types_traverse::variable(Named_object* named_object) && !var->type()->is_error() && (init == NULL || !init->is_error_expression()) && !Lex::is_invalid_identifier(named_object->name())) - go_error_at(var->location(), "%qs declared and not used", + go_error_at(var->location(), "%qs declared but not used", named_object->message_name().c_str()); } return TRAVERSE_CONTINUE; @@ -6218,6 +6194,56 @@ Function::import_func(Import* imp, std::string* pname, return true; } +// Get the backend name. + +void +Function::backend_name(Gogo* gogo, Named_object* no, Backend_name *bname) +{ + if (!this->asm_name_.empty()) + bname->set_asm_name(this->asm_name_); + else if (no->package() == NULL && no->name() == gogo->get_init_fn_name()) + { + // These names appear in the export data and are used + // directly in the assembler code. If we change this here + // we need to change Gogo::init_imports. + bname->set_asm_name(no->name()); + } + else if (this->enclosing_ != NULL) + { + // Rewrite the nested name to use the enclosing function name. + // We don't do this earlier because we just store simple names + // in a Named_object, not Backend_names. + + // The name was set by nested_function_name, which always + // appends ..funcNNN. We want that to be our suffix. + size_t pos = no->name().find("..func"); + go_assert(pos != std::string::npos); + + Named_object* enclosing = this->enclosing_; + while (true) + { + Named_object* parent = enclosing->func_value()->enclosing(); + if (parent == NULL) + break; + enclosing = parent; + } + + Type* rtype = NULL; + if (enclosing->func_value()->type()->is_method()) + rtype = enclosing->func_value()->type()->receiver()->type(); + gogo->function_backend_name(enclosing->name(), enclosing->package(), + rtype, bname); + bname->append_suffix(no->name().substr(pos)); + } + else + { + Type* rtype = NULL; + if (this->type_->is_method()) + rtype = this->type_->receiver()->type(); + gogo->function_backend_name(no->name(), no->package(), rtype, bname); + } +} + // Get the backend representation. Bfunction* @@ -6226,7 +6252,6 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no) if (this->fndecl_ == NULL) { unsigned int flags = 0; - bool is_init_fn = false; if (no->package() != NULL) { // Functions defined in other packages must be visible. @@ -6238,10 +6263,7 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no) && !this->type_->is_method()) ; else if (no->name() == gogo->get_init_fn_name()) - { - flags |= Backend::function_is_visible; - is_init_fn = true; - } + flags |= Backend::function_is_visible; else if (Gogo::unpack_hidden_name(no->name()) == "main" && gogo->is_main_package()) flags |= Backend::function_is_visible; @@ -6255,29 +6277,13 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no) flags |= Backend::function_is_visible; } - Type* rtype = NULL; - if (this->type_->is_method()) - rtype = this->type_->receiver()->type(); - - std::string asm_name; if (!this->asm_name_.empty()) { - asm_name = this->asm_name_; - // If an assembler name is explicitly specified, there must // be some reason to refer to the symbol from a different // object file. flags |= Backend::function_is_visible; } - else if (is_init_fn) - { - // These names appear in the export data and are used - // directly in the assembler code. If we change this here - // we need to change Gogo::init_imports. - asm_name = no->name(); - } - else - asm_name = gogo->function_asm_name(no->name(), no->package(), rtype); // If an inline body refers to this function, then it // needs to be visible in the symbol table. @@ -6337,13 +6343,36 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no) flags |= Backend::function_only_inline; Btype* functype = this->type_->get_backend_fntype(gogo); - this->fndecl_ = - gogo->backend()->function(functype, no->get_id(gogo), asm_name, - flags, this->location()); + + Backend_name bname; + this->backend_name(gogo, no, &bname); + + this->fndecl_ = gogo->backend()->function(functype, + bname.name(), + bname.optional_asm_name(), + flags, + this->location()); } return this->fndecl_; } +// Get the backend name. + +void +Function_declaration::backend_name(Gogo* gogo, Named_object* no, + Backend_name* bname) +{ + if (!this->asm_name_.empty()) + bname->set_asm_name(this->asm_name_); + else + { + Type* rtype = NULL; + if (this->fntype_->is_method()) + rtype = this->fntype_->receiver()->type(); + gogo->function_backend_name(no->name(), no->package(), rtype, bname); + } +} + // Get the backend representation. Bfunction* @@ -6375,21 +6404,16 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no) flags |= Backend::function_does_not_return; } - std::string asm_name; - if (this->asm_name_.empty()) - { - Type* rtype = NULL; - if (this->fntype_->is_method()) - rtype = this->fntype_->receiver()->type(); - asm_name = gogo->function_asm_name(no->name(), no->package(), rtype); - } - else if (go_id_needs_encoding(no->get_id(gogo))) - asm_name = go_encode_id(no->get_id(gogo)); - Btype* functype = this->fntype_->get_backend_fntype(gogo); - this->fndecl_ = - gogo->backend()->function(functype, no->get_id(gogo), asm_name, - flags, this->location()); + + Backend_name bname; + this->backend_name(gogo, no, &bname); + + this->fndecl_ = gogo->backend()->function(functype, + bname.name(), + bname.optional_asm_name(), + flags, + this->location()); } return this->fndecl_; @@ -7434,7 +7458,7 @@ Variable::Variable(Type* type, Expression* init, bool is_global, : type_(type), init_(init), preinit_(NULL), location_(location), backend_(NULL), is_global_(is_global), is_parameter_(is_parameter), is_closure_(false), is_receiver_(is_receiver), - is_varargs_parameter_(false), is_used_(false), + 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), @@ -7993,7 +8017,6 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, type = Type::make_pointer_type(type); } - const std::string n = Gogo::unpack_hidden_name(name); Btype* btype = type->get_backend(gogo); Bvariable* bvar; @@ -8001,19 +8024,14 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, bvar = Map_type::backend_zero_value(gogo); else if (this->is_global_) { - std::string var_name(package != NULL - ? package->package_name() - : gogo->package_name()); - var_name.push_back('.'); - var_name.append(n); - - std::string asm_name(gogo->global_var_asm_name(name, package)); + Backend_name bname; + gogo->global_var_backend_name(name, package, &bname); bool is_hidden = Gogo::is_hidden_name(name); // Hack to export runtime.writeBarrier. FIXME. // This is because go:linkname doesn't work on variables. if (gogo->compiling_runtime() - && var_name == "runtime.writeBarrier") + && bname.name() == "runtime.writeBarrier") is_hidden = false; // If an inline body refers to this variable, then it @@ -8028,8 +8046,12 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, if (package != NULL) is_hidden = false; - bvar = backend->global_variable(var_name, - asm_name, + // For some reason asm_name can't be the empty string + // for global_variable, so we call asm_name rather than + // optional_asm_name here. FIXME. + + bvar = backend->global_variable(bname.name(), + bname.asm_name(), btype, package != NULL, is_hidden, @@ -8043,6 +8065,7 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, } else { + const std::string n = Gogo::unpack_hidden_name(name); Bfunction* bfunction = function->func_value()->get_decl(); bool is_address_taken = (this->is_non_escaping_address_taken_ && !this->is_in_heap()); @@ -8216,7 +8239,13 @@ Named_constant::get_backend(Gogo* gogo, Named_object* const_no) if (type != NULL && type->is_numeric_type()) { Btype* btype = type->get_backend(gogo); - std::string name = const_no->get_id(gogo); + std::string name; + if (const_no->package() == NULL) + name = gogo->pkgpath(); + else + name = const_no->package()->pkgpath(); + name.push_back('.'); + name.append(Gogo::unpack_hidden_name(const_no->name())); const_decl = gogo->backend()->named_constant_expression(btype, name, const_decl, loc); @@ -8637,54 +8666,6 @@ Named_object::get_backend_variable(Gogo* gogo, Named_object* function) go_unreachable(); } -// Return the external identifier for this object. - -std::string -Named_object::get_id(Gogo* gogo) -{ - go_assert(!this->is_variable() - && !this->is_result_variable() - && !this->is_type()); - std::string decl_name; - if (this->is_function_declaration() - && !this->func_declaration_value()->asm_name().empty()) - decl_name = this->func_declaration_value()->asm_name(); - else - { - std::string package_name; - if (this->package_ == NULL) - package_name = gogo->package_name(); - else - package_name = this->package_->package_name(); - - // Note that this will be misleading if this is an unexported - // method generated for an embedded imported type. In that case - // the unexported method should have the package name of the - // package from which it is imported, but we are going to give - // it our package name. Fixing this would require knowing the - // package name, but we only know the package path. It might be - // better to use package paths here anyhow. This doesn't affect - // the assembler code, because we always set that name in - // Function::get_or_make_decl anyhow. FIXME. - - decl_name = package_name + '.' + Gogo::unpack_hidden_name(this->name_); - - Function_type* fntype; - if (this->is_function()) - fntype = this->func_value()->type(); - else if (this->is_function_declaration()) - fntype = this->func_declaration_value()->type(); - else - fntype = NULL; - if (fntype != NULL && fntype->is_method()) - { - decl_name.push_back('.'); - decl_name.append(fntype->receiver()->type()->mangled_name(gogo)); - } - } - return decl_name; -} - void debug_go_named_object(Named_object* no) { diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 45be173..bdb3166 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -57,6 +57,116 @@ class Node; // This file declares the basic classes used to hold the internal // representation of Go which is built by the parser. +// The name of some backend object. Backend objects have a +// user-visible name and an assembler name. The user visible name +// might include arbitrary Unicode characters. The assembler name +// will not. + +class Backend_name +{ + public: + Backend_name() + : prefix_(NULL), components_(), count_(0), suffix_(), + is_asm_name_(false), is_non_identifier_(false) + {} + + // Set the prefix. Prefixes are always constant strings. + void + set_prefix(const char* p) + { + go_assert(this->prefix_ == NULL && !this->is_asm_name_); + this->prefix_ = p; + } + + // Set the suffix. + void + set_suffix(const std::string& s) + { + go_assert(this->suffix_.empty() && !this->is_asm_name_); + this->suffix_ = s; + } + + // Append to the suffix. + void + append_suffix(const std::string& s) + { + if (this->is_asm_name_) + this->components_[0].append(s); + else + this->suffix_.append(s); + } + + // Add a component. + void + add(const std::string& c) + { + go_assert(this->count_ < Backend_name::max_components + && !this->is_asm_name_); + this->components_[this->count_] = c; + ++this->count_; + } + + // Set an assembler name specified by the user. This overrides both + // the user-visible name and the assembler name. No further + // encoding is applied. + void + set_asm_name(const std::string& n) + { + go_assert(this->prefix_ == NULL + && this->count_ == 0 + && this->suffix_.empty() + && !this->is_asm_name_); + this->components_[0] = n; + this->is_asm_name_ = true; + } + + // Whether some component includes some characters that can't appear + // in an identifier. + bool + is_non_identifier() const + { return this->is_non_identifier_; } + + // Record that some component includes some character that can't + // appear in an identifier. + void + set_is_non_identifier() + { this->is_non_identifier_ = true; } + + // Get the user visible name. + std::string + name() const; + + // Get the assembler name. This may be the same as the user visible + // name. + std::string + asm_name() const; + + // Get an optional assembler name: if it would be the same as the + // user visible name, this returns the empty string. + std::string + optional_asm_name() const; + + private: + // The maximum number of components. + static const int max_components = 4; + + // An optional prefix that does not require encoding. + const char *prefix_; + // Up to four components. The name will include these components + // separated by dots. Each component will be underscore-encoded + // (see the long comment near the top of names.cc). + std::string components_[Backend_name::max_components]; + // Number of components. + int count_; + // An optional suffix that does not require encoding. + std::string suffix_; + // True if components_[0] is an assembler name specified by the user. + bool is_asm_name_; + // True if some component includes some character that can't + // normally appear in an identifier. + bool is_non_identifier_; +}; + // An initialization function for an imported package. This is a // magic function which initializes variables and runs the "init" // function. @@ -613,7 +723,7 @@ class Gogo // is used when a type-specific hash function is needed when not at // top level. void - queue_hash_function(Type* type, int64_t size, const std::string& hash_name, + queue_hash_function(Type* type, int64_t size, Backend_name*, Function_type* hash_fntype); // Queue up a type-specific equal function to be written out. This @@ -621,8 +731,7 @@ class Gogo // top level. void queue_equal_function(Type* type, Named_type* name, int64_t size, - const std::string& equal_name, - Function_type* equal_fntype); + Backend_name*, Function_type* equal_fntype); // Write out queued specific type functions. void @@ -869,31 +978,32 @@ class Gogo Expression* allocate_memory(Type *type, Location); - // Return the assembler name to use for an exported function, a - // method, or a function/method declaration. - std::string - function_asm_name(const std::string& go_name, const Package*, - const Type* receiver); + // Get the backend name to use for an exported function, a method, + // or a function/method declaration. + void + function_backend_name(const std::string& go_name, const Package*, + const Type* receiver, Backend_name*); // Return the name to use for a function descriptor. - std::string - function_descriptor_name(Named_object*); + void + function_descriptor_backend_name(Named_object*, Backend_name*); // Return the name to use for a generated stub method. std::string stub_method_name(const Package*, const std::string& method_name); - // Return the name of the hash function for TYPE. - std::string - hash_function_name(const Type*); + // Get the backend name of the hash function for TYPE. + void + hash_function_name(const Type*, Backend_name*); - // Return the name of the equal function for TYPE. - std::string - equal_function_name(const Type*, const Named_type*); + // Get the backend name of the equal function for TYPE. + void + equal_function_name(const Type*, const Named_type*, Backend_name*); - // Return the assembler name to use for a global variable. - std::string - global_var_asm_name(const std::string& go_name, const Package*); + // Get the backend name to use for a global variable. + void + global_var_backend_name(const std::string& go_name, const Package*, + Backend_name*); // Return a name to use for an error case. This should only be used // after reporting an error, and is used to avoid useless knockon @@ -961,13 +1071,14 @@ class Gogo // Return the package path symbol from an init function name, which // can be a real init function or a dummy one. std::string - pkgpath_from_init_fn_name(std::string); + pkgpath_symbol_from_init_fn_name(std::string); - // Return the name for a type descriptor symbol. - std::string - type_descriptor_name(const Type*, Named_type*); + // Get the backend name for a type descriptor symbol. + void + type_descriptor_backend_name(const Type*, Named_type*, Backend_name*); // Return the name of the type descriptor list symbol of a package. + // The argument is an encoded pkgpath, as with pkgpath_symbol. std::string type_descriptor_list_symbol(const std::string&); @@ -987,11 +1098,11 @@ class Gogo std::string interface_method_table_name(Interface_type*, Type*, bool is_pointer); - // Return whether NAME is a special name that can not be passed to - // unpack_hidden_name. This is needed because various special names - // use "..SUFFIX", but unpack_hidden_name just looks for '.'. - static bool - is_special_name(const std::string& name); + // If NAME is a special name used as a Go identifier, return the + // position within the string where the special part of the name + // occurs. + static size_t + special_name_pos(const std::string& name); private: // During parsing, we keep a stack of functions. Each function on @@ -1056,6 +1167,9 @@ class Gogo Named_object* write_barrier_variable(); + static bool + is_digits(const std::string&); + // Type used to map import names to packages. typedef std::map<std::string, Package*> Imports; @@ -1079,15 +1193,15 @@ class Gogo Named_type* name; int64_t size; Specific_type_function_kind kind; - std::string fnname; + Backend_name bname; Function_type* fntype; Specific_type_function(Type* atype, Named_type* aname, int64_t asize, Specific_type_function_kind akind, - const std::string& afnname, + Backend_name* abname, Function_type* afntype) : type(atype), name(aname), size(asize), kind(akind), - fnname(afnname), fntype(afntype) + bname(*abname), fntype(afntype) { } }; @@ -1631,6 +1745,10 @@ class Function Bstatement* return_value(Gogo*, Named_object*, Location) const; + // Get the backend name of this function. + void + backend_name(Gogo*, Named_object*, Backend_name*); + // Get an expression for the variable holding the defer stack. Expression* defer_stack(Location); @@ -1872,6 +1990,10 @@ class Function_declaration void build_backend_descriptor(Gogo*); + // Get the backend name of this function declaration. + void + backend_name(Gogo*, Named_object*, Backend_name*); + // Export a function declaration. void export_func(Export* exp, const Named_object* no) const @@ -1991,6 +2113,20 @@ class Variable is_varargs_parameter() const { return this->is_varargs_parameter_; } + // Return whether this is a global sink variable, created only to + // run an initializer. + bool + is_global_sink() const + { return this->is_global_sink_; } + + // Record that this is a global sink variable. + void + set_is_global_sink() + { + go_assert(this->is_global_); + this->is_global_sink_ = true; + } + // Whether this variable's address is taken. bool is_address_taken() const @@ -2218,6 +2354,9 @@ class Variable bool is_receiver_ : 1; // Whether this is the varargs parameter of a function. bool is_varargs_parameter_ : 1; + // Whether this is a global sink variable created to run an + // initializer. + bool is_global_sink_ : 1; // Whether this variable is ever referenced. bool is_used_ : 1; // Whether something takes the address of this variable. For a @@ -2863,10 +3002,6 @@ class Named_object Bvariable* get_backend_variable(Gogo*, Named_object* function); - // Return the external identifier for this object. - std::string - get_id(Gogo*); - // Get the backend representation of this object. void get_backend(Gogo*, std::vector<Bexpression*>&, std::vector<Btype*>&, diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index c6c1178..f671416 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -1049,6 +1049,13 @@ Import::read_named_type(int index) this->require_c_string(" "); } + bool in_heap = true; + if (this->match_c_string("notinheap")) + { + this->require_c_string("notinheap "); + in_heap = false; + } + bool is_alias = false; if (this->match_c_string("= ")) { @@ -1102,7 +1109,14 @@ Import::read_named_type(int index) // declaration of a type defined in some other file. Type* type; if (this->match_c_string(">") || this->match_c_string("\n")) - type = this->types_[index]; + { + type = this->types_[index]; + if (!in_heap) + go_error_at(this->location_, + ("import error at %d for type index %d: " + "forward declaration marked notinheap"), + this->pos(), index); + } else { if (no->is_type_declaration()) @@ -1117,6 +1131,8 @@ Import::read_named_type(int index) // This type has not yet been imported. ntype->clear_is_visible(); + if (!in_heap) + ntype->set_not_in_heap(); if (is_alias) ntype->set_is_alias(); diff --git a/gcc/go/gofrontend/lex.cc b/gcc/go/gofrontend/lex.cc index 156a90c..0baf4e4 100644 --- a/gcc/go/gofrontend/lex.cc +++ b/gcc/go/gofrontend/lex.cc @@ -743,6 +743,13 @@ Lex::next_token() if (Lex::is_unicode_letter(ci)) return this->gather_identifier(); + if (!issued_error && Lex::is_unicode_digit(ci)) + { + go_error_at(this->location(), + "identifier cannot begin with digit"); + issued_error = true; + } + if (!issued_error) go_error_at(this->location(), "invalid character 0x%x in input file", @@ -1309,9 +1316,13 @@ Lex::gather_number() } } + mpfr_clear_overflow(); mpfr_t val; int r = mpfr_init_set_str(val, num.c_str(), base, MPFR_RNDN); go_assert(r == 0); + if (mpfr_overflow_p()) + go_error_at(this->location(), + "floating-point exponent too large to represent"); bool is_imaginary = *p == 'i'; if (is_imaginary) diff --git a/gcc/go/gofrontend/names.cc b/gcc/go/gofrontend/names.cc index 1f0a545..f85d84c 100644 --- a/gcc/go/gofrontend/names.cc +++ b/gcc/go/gofrontend/names.cc @@ -15,53 +15,68 @@ // assembly code. This is not used for names that appear only in the // debug info. -// Our external names contain only ASCII alphanumeric characters, +// Our external names may contain only ASCII alphanumeric characters, // underscore, and dot. (According to the GCC sources, dot is not // permitted in assembler symbols on VxWorks and MMIX. We will not -// support those systems.) Go names can not contain dot, so we rely -// on using dot to encode Unicode characters, and to separate Go -// symbols by package, and so forth. We assume that none of the -// non-Go symbols in the final link will contain a dot, so we don't -// worry about conflicts. +// support those systems.) Go identifiers cannot contain dot, but Go +// package paths can. Both Go identifiers and package paths can, of +// course, contain all sorts of Unicode characters. +// +// The gc compiler uses names like "pkg.F", and it seems convenient to +// emulate that. Therefore, we will use dot to separate different +// components of names. +// +// Since package paths can contain dot, to avoid ambiguity we must +// encode package paths such that they do not contain any dot. The +// natural way to do this is to encode forbidden characters, including +// dot, using a notation based on underscore. We will, of course, +// have to encode underscore itself. +// +// Since we will be using an underscore encoding for the package path, +// it seems reasonable to use the same encoding for Go identifiers. +// This has the disadvantage that encoded Go identifiers will appear +// to be valid Go identifiers with funny spellings, but it seems like +// the best available approach. +// +// Therefore, in the following discussion we may assume that none of +// the names under discussion contain a dot. All of the names we +// generate for Go identifiers (that don't use //export or +// //go:linkname) will contain at least one dot, as discussed below. +// We assume that none of the non-Go symbols in the final link will +// contain a dot, so we don't worry about conflicts. // // We first describe the basic symbol names, used to represent Go -// functions and variables. These never start with a dot, never end -// with a dot, never contain two consecutive dots, and never contain a -// dot followed by a digit. +// functions and variables. // // The external name for a normal Go symbol NAME, a function or // variable, is simply "PKGPATH.NAME". Note that NAME is not the // packed form used for the "hidden" name internally in the compiler; -// it is the name that appears in the source code. PKGPATH is the -// -fgo-pkgpath option as adjusted by Gogo::pkgpath_for_symbol. Note -// that PKGPATH can not contain a dot and neither can NAME. Also, -// NAME may not begin with a digit. NAME may require further encoding -// for non-ASCII characters as described below, but until that -// encoding these symbols contain exactly one dot, and they do not -// start with a dot. +// it is the name that appears in the source code. Both PKGPATH and +// NAME will be encoded as described below. The encoding process +// ensures that neither encoded string can contain a dot, and neither +// will start with a digit (NAME is a Go identifier that can't contain +// a dot or start with a digit anyhow). The encoding process means +// that these external names contain exactly one dot and do not start +// with a dot. // // The external name for a method NAME for a named type TYPE is -// "PKGPATH.TYPE.NAME". Unlike the gc compiler, the external name -// does not indicate whether this is a pointer method or a value -// method; a named type can not have both a pointer and value method -// with the same name, so there is no ambiguity. PKGPATH is the -// package path of the package in which TYPE is defined. Here none of -// PKGPATH, TYPE, or NAME can be empty or contain a dot, and neither -// TYPE nor NAME may begin with a digit. Before encoding these names -// contain exactly two dots, not consecutive, and they do not start -// with a dot. +// "PKGPATH.TYPE.NAME". Both NAME and TYPE are simple Go identifiers. +// Unlike the gc compiler, the external name does not indicate whether +// this is a pointer method or a value method; a named type can not +// have both a pointer and value method with the same name, so there +// is no ambiguity. PKGPATH is the package path of the package in +// which TYPE is defined. PKGPATH, TYPE, and NAME are encoded, and +// cannot be empty or contain a dot or start with a digit. These +// external names contain exactly two dots, not consecutive, and they +// do not start with a dot. // // It's uncommon, but the use of type literals with embedded fields // can cause us to have methods on unnamed types. The external names -// for these are also PKGPATH.TYPE.NAME, where TYPE is an +// for these are also PKGPATH.TYPELIT.NAME, where TYPELIT is an // approximately readable version of the type literal, described -// below. As the type literal encoding always contains multiple dots, -// these names always contain more than two dots. Although the type -// literal encoding contains dots, neither PKGPATH nor NAME can -// contain a dot, and neither TYPE nor NAME can begin with a digit. -// The effect is that PKGPATH is always the portion of the name before -// the first dot and NAME is always the portion after the last dot. -// There is no ambiguity as long as encoded type literals are +// below. A TYPELIT will always contain characters that cannot appear +// in a Go identifier, so TYPELIT can never be confused with a TYPE +// name. There is no ambiguity as long as encoded type literals are // unambiguous. // // Also uncommon is an external name that must refer to a named type @@ -91,46 +106,51 @@ // the function with an added suffix "..f". // // A thunk for a go or defer statement is treated as a function whose -// name is ".thunkNN" where NN is a sequence of digits (these -// functions are never globally visible). Thus the final name of a -// thunk will be PKGPATH..thunkNN. +// name is ".thunkNN", unencoded, where NN is a sequence of digits +// (these functions are never globally visible). Thus the final name +// of a thunk will be PKGPATH..thunkNN (PKGPATH is encoded). // -// An init function is treated as a function whose name is ".initNN" -// where NN is a sequence of digits (these functions are never -// globally visible). Thus the final name of an init function will be -// PKGPATH..initNN. +// An init function is treated as a function whose name is ".initNN", +// unencoded, where NN is a sequence of digits (these functions are +// never globally visible). Thus the final name of an init function +// will be PKGPATH..initNN (PKGPATH is encoded). // // A nested function is given the name of outermost enclosing function -// or method with an added suffix "..funcNN" where NN is a sequence of -// digits. Note that the function descriptor of a nested function, if -// needed, will end with "..funcNN..f". +// or method with an added suffix "..funcNN", unencoded, where NN is a +// sequence of digits. Note that the function descriptor of a nested +// function, if needed, will end with "..funcNN..f". // // A recover thunk is the same as the name of the function with an // added suffix "..r". // -// The name of a type descriptor for a named type is PKGPATH.TYPE..d. +// The name of a type descriptor for a named type is +// PKGPATH.TYPENAME..d (PKGPATH and TYPENAME are encoded). // -// The name of a type descriptor for an unnamed type is type..TYPE. -// That is, the string "type.." followed by the type literal encoding. +// The name of a type descriptor for a pointer to a named type is +// PKGPATH.TYPENAME..p (PKGPATH and TYPENAME are encoded). +// +// The name of a type descriptor for an unnamed type is type..TYPELIT. +// That is, the string "type.." followed by the encoded type literal. // These names are common symbols, in the linker's sense of the word // common: in the final executable there is only one instance of the -// type descriptor for a given unnamed type. The type literal -// encoding can never start with a digit or with 'u' or 'U'. +// type descriptor for a given unnamed type. // -// The name of the GC symbol for a named type is PKGPATH.TYPE..g. +// The name of the GC symbol for a named type is PKGPATH.TYPE..g +// (PKGPATH and TYPE are encoded). // -// The name of the GC symbol for an unnamed type is typeg..TYPE. +// The name of the GC symbol for an unnamed type is type..TYPELIT..g. // These are common symbols. // // The name of a ptrmask symbol is gcbits..B32 where B32 is an -// encoding of the ptrmask bits using only ASCII letters without 'u' -// or 'U'. These are common symbols. +// encoding of the ptrmask bits using only ASCII letters. These are +// common symbols. // // An interface method table for assigning the non-interface type TYPE // to the interface type ITYPE is named imt..ITYPE..TYPE. If ITYPE or -// TYPE is a named type, they are written as PKGPATH.TYPE. Otherwise -// they are written as a type literal. An interface method table for -// a pointer method set uses pimt instead of imt. +// TYPE is a named type, they are written as PKGPATH.TYPE (where both +// PKGPATH and TYPE are encoded). Otherwise they are written as a +// type literal. An interface method table for a pointer method set +// uses pimt instead of imt. // // The names of composite literal initializers, including the GC root // variable, are not referenced. They must not conflict with any C @@ -147,7 +167,7 @@ // PKGPATH..import. If a package doesn't need an init function, it // will have a dummy one, named ~PKGPATH. // -// In each pacakge there is a list of all the type descriptors defined +// In each package there is a list of all the type descriptors defined // in this package. The name of the list is PKGPATH..types. // // In the main package it gathers all the type descriptor lists in a @@ -161,109 +181,123 @@ // The type literal encoding is not quite valid Go, as some aspects of // compiler generated types can not be represented. For example, // incomparable struct types have an extra field "{x}". Struct tags -// are quoted inside curly braces, rather than introduce an encoding -// for quotes. Struct tags can contain any character, so any single -// byte Unicode character that is not alphanumeric or underscore is -// replaced with .xNN where NN is the hex encoding. +// can contain any character, which will be underscore encoded as +// usual. In the unusual case of a curly brace or a backslash in a +// struct tag, the brace or backslash will be backslash quoted, before +// underscore encoding. +// +// Many of these names will be visible in the debugger. The debugger +// will be given these names before applying any underscore encoding. +// These user names do not have to be unique--they are only used by +// the debugger, not the linker--so this is OK. However, there is an +// exception: if the name would otherwise include characters that +// can't normally appear in an identifier, then the user name will +// also be underscore encoded. This avoids problems with +// communicating the debug info to the assembler and with handling the +// debug info in the debugger. A Go-aware debugger will need to know +// whether to apply underscore decoding to a name before showing it to +// the user. We indicate this by adding a prefix of "g.", and +// assuming that cases of a package path of "g" are unusual. This +// prefix will only appear in the user name, not the assembler name. // -// There is a simple encoding for glue characters in type literals: -// .0 - ' ' -// .1 - '*' -// .2 - ';' -// .3 - ',' -// .4 - '{' -// .5 - '}' -// .6 - '[' -// .7 - ']' -// .8 - '(' -// .9 - ')' -// This is unambiguous as, although the type literal can contain a dot -// as shown above, those dots are always followed by a name and names -// can not begin with a digit. A dot is always followed by a name or -// a digit, and a type literal can neither start nor end with a dot, -// so this never introduces consecutive dots. +// The underscore encoding is, naturally, an underscore followed by +// other characters. As there are various characters that commonly +// appear in type literals and in package paths, we have a set of +// short encodings. Then we have general encodings for other +// characters. // -// Struct tags can contain any character, so they need special -// treatment. Alphanumerics, underscores, and Unicode characters that -// require more than a single byte are left alone (Unicode characters -// will be encoded later, as described below). Other single bytes -// characters are replace with .xNN where NN is the hex encoding. +// __ - '_' +// _0 - '.' +// _1 - '/' +// _2 - '*' +// _3 - ',' +// _4 - '{' +// _5 - '}' +// _6 - '[' +// _7 - ']' +// _8 - '(' +// _9 - ')' +// _a - '"' +// _b - ' ' +// _c - ';' // -// Since Go identifiers can contain Unicode characters, we must encode -// them into ASCII. We do this last, after the name is generated as -// described above and after type literals are encoded. To make the -// encoding unambiguous, we introduce it with two consecutive dots. -// This is followed by the letter u and four hex digits or the letter -// U and eight digits, just as in the language only using ..u and ..U -// instead of \u and \U. The compiler also produces identifiers that -// are qualified by package path, which means that there may also be ASCII -// characters that are not assembler-friendly (ex: '=', '/'). The encoding -// scheme translates such characters into the "..zNN" where NN is the -// hex value for the character. Since before this encoding names can never -// contain consecutive dots followed by 'z', 'u' or 'U', and after this -// encoding "..z", "..u" and "..U" are followed by a known number of -// characters, this is unambiguous. +// Other non-alphanumeric ASCII characters are encoded as _xNN, where +// NN is the hex value for the character. If an encoded name would +// otherwise start with a digit, this encoding is also used for the +// leading digit. +// +// Non-ASCII Unicode characters are encoded as _u and four hex digits +// or _U and eight digits, just as in the language only using _u and +// _U instead of \u and \U. // // Demangling these names is straightforward: -// - replace ..zXX with an ASCII character -// - replace ..uXXXX with a unicode character -// - replace ..UXXXXXXXX with a unicode character -// - replace .D, where D is a digit, with the character from the above +// - replace _xXX with an ASCII character +// - replace _uXXXX with a unicode character +// - replace _UXXXXXXXX with a unicode character +// - replace _C per the table above // That will get you as close as possible to a readable name. -// Return the assembler name to use for an exported function, a -// method, or a function/method declaration. This is not called if -// the function has been given an explicit name via a magic //extern -// or //go:linkname comment. GO_NAME is the name that appears in the -// Go code. PACKAGE is the package where the function is defined, and -// is NULL for the package being compiled. For a method, RTYPE is +// Set BNAME to the name to use for an exported function, a method, or +// a function/method declaration. GO_NAME is the name that appears in +// the Go code. PACKAGE is the package where the function is defined, +// and is NULL for the package being compiled. For a method, RTYPE is // the method's receiver type; for a function, RTYPE is NULL. -std::string -Gogo::function_asm_name(const std::string& go_name, const Package* package, - const Type* rtype) +void +Gogo::function_backend_name(const std::string& go_name, + const Package* package, const Type* rtype, + Backend_name* bname) { - std::string ret; if (rtype != NULL) - ret = rtype->deref()->mangled_name(this); + rtype->deref()->backend_name(this, bname); else if (package == NULL) - ret = this->pkgpath(); + bname->add(this->pkgpath()); else - ret = package->pkgpath(); - ret.push_back('.'); - // Check for special names that will break if we use - // Gogo::unpack_hidden_name. - if (Gogo::is_special_name(go_name)) - ret.append(go_name); + bname->add(package->pkgpath()); + + size_t pos = Gogo::special_name_pos(go_name); + if (pos == std::string::npos) + bname->add(Gogo::unpack_hidden_name(go_name)); else - ret.append(Gogo::unpack_hidden_name(go_name)); - return go_encode_id(ret); + { + if (pos > 0) + bname->add(go_name.substr(0, pos)); + bname->set_suffix(go_name.substr(pos)); + } } -// Return the name to use for a function descriptor. These symbols -// are globally visible. +// Set BNAME to the name to use for a function descriptor. These +// symbols are globally visible. -std::string -Gogo::function_descriptor_name(Named_object* no) +void +Gogo::function_descriptor_backend_name(Named_object* no, + Backend_name* bname) { - if (no->is_function() && !no->func_value()->asm_name().empty()) - return no->func_value()->asm_name() + "..f"; - else if (no->is_function_declaration() - && !no->func_declaration_value()->asm_name().empty()) - return no->func_declaration_value()->asm_name() + "..f"; - std::string ret = this->function_asm_name(no->name(), no->package(), NULL); - ret.append("..f"); - return ret; + if (no->is_function()) + no->func_value()->backend_name(this, no, bname); + else if (no->is_function_declaration()) + no->func_declaration_value()->backend_name(this, no, bname); + else + go_unreachable(); + bname->append_suffix("..f"); } -// Return the name to use for a generated stub method. MNAME is the -// method name. PACKAGE is the package where the type that needs this -// stub method is defined. These functions are globally visible. -// Note that this is the function name that corresponds to the name -// used for the method in Go source code, if this stub method were -// written in Go. The assembler name will be generated by -// Gogo::function_asm_name, and because this is a method that name -// will include the receiver type. +// Return the name to use for a generated stub method. A stub method +// is used as the method table entry for a promoted method of an +// embedded type. MNAME is the method name. PACKAGE is the package +// where the type that needs this stub method is defined. These +// functions are globally visible. +// +// This returns a name that acts like a Go identifier, as though the +// stub method were written in Go as an explicitly defined method that +// simply calls the promoted method. The name we return here will +// eventually be passed to function_backend_name, which will return a +// name that includes the receiver type. +// +// We construct a unique method name and append "..stub". +// function_backend_name will look for the "..stub" and turn that into +// an unencoded suffix. The rest of the name will be encoded as +// usual. std::string Gogo::stub_method_name(const Package* package, const std::string& mname) @@ -279,56 +313,70 @@ Gogo::stub_method_name(const Package* package, const std::string& mname) return Gogo::unpack_hidden_name(mname) + "..stub"; // We are creating a stub method for an unexported method of an - // imported embedded type. We need to disambiguate the method name. - std::string ret = mpkgpath; + // imported embedded type. A single type can have multiple promoted + // methods with the same unexported name, if it embeds types from + // different packages. We need to disambiguate the method name. + // This produces an unambiguous name because even though MPKGPATH + // can be anything, we know that MNAME does not contain a dot. The + // dot we return here, between MPKGPATH and MNAME, will wind up + // being underscore encoded. + std::string ret(mpkgpath); ret.push_back('.'); ret.append(Gogo::unpack_hidden_name(mname)); ret.append("..stub"); return ret; } -// Return the name of the hash function for TYPE. +// Set BNAME to the name of the hash function for TYPE. -std::string -Gogo::hash_function_name(const Type* type) +void +Gogo::hash_function_name(const Type* type, Backend_name* bname) { - std::string tname = type->mangled_name(this); - return tname + "..hash"; + if (type->named_type() != NULL) + type->backend_name(this, bname); + else + { + bname->add(this->pkgpath()); + type->backend_name(this, bname); + } + bname->set_suffix("..hash"); } -// Return the name of the equal function for TYPE. If NAME is not -// NULL it is the name of the type. +// Set BNAME to the name of the equal function for TYPE. If NAME is +// not NULL it is the name of the type. -std::string -Gogo::equal_function_name(const Type* type, const Named_type* name) +void +Gogo::equal_function_name(const Type* type, const Named_type* name, + Backend_name* bname) { - const Type* rtype = type; if (name != NULL) - rtype = name; - std::string tname = rtype->mangled_name(this); - return tname + "..eq"; + name->backend_name(this, bname); + else + { + bname->add(this->pkgpath()); + type->backend_name(this, bname); + } + bname->set_suffix("..eq"); } -// Return the assembler name to use for a global variable. GO_NAME is -// the name that appears in the Go code. PACKAGE is the package where -// the variable is defined, and is NULL for the package being -// compiled. +// Set BNAME to the name to use for a global variable. GO_NAME is the +// name that appears in the Go code. PACKAGE is the package where the +// variable is defined, and is NULL for the package being compiled. -std::string -Gogo::global_var_asm_name(const std::string& go_name, const Package* package) +void +Gogo::global_var_backend_name(const std::string& go_name, + const Package* package, + Backend_name* bname) { - std::string ret; if (package == NULL) - ret = this->pkgpath(); + bname->add(this->pkgpath()); else - ret = package->pkgpath(); - ret.append(1, '.'); - ret.append(Gogo::unpack_hidden_name(go_name)); - return go_encode_id(ret); + bname->add(package->pkgpath()); + bname->add(Gogo::unpack_hidden_name(go_name)); } // Return an erroneous name that indicates that an error has already -// been reported. +// been reported. This name will act like a Go identifier. std::string Gogo::erroneous_name() @@ -349,7 +397,10 @@ Gogo::is_erroneous_name(const std::string& name) return name.compare(0, 10, ".erroneous") == 0; } -// Return a name for a thunk object. +// Return a name for a thunk object. This name will act like a Go +// identifier. The name returned here will eventually be passed to +// function_backend_name, which will pull off the ..thunk as an +// unencoded suffix. std::string Gogo::thunk_name() @@ -358,7 +409,12 @@ Gogo::thunk_name() char thunk_name[50]; snprintf(thunk_name, sizeof thunk_name, "..thunk%d", thunk_count); ++thunk_count; - std::string ret = this->pkgpath(); + // We don't want to return a name that starts with a dot, as that + // will confuse Gogo::is_hidden_name. And we don't want to change + // ..thunk, which fits our general theme and is used by code like + // runtime.Callers. But the prefix doesn't matter, as the actual + // name will include the package path. + std::string ret = "go"; return ret + thunk_name; } @@ -368,13 +424,10 @@ bool Gogo::is_thunk(const Named_object* no) { const std::string& name(no->name()); - size_t i = name.find("..thunk"); + size_t i = name.rfind("..thunk"); if (i == std::string::npos) return false; - for (i += 7; i < name.size(); ++i) - if (name[i] < '0' || name[i] > '9') - return false; - return true; + return Gogo::is_digits(name.substr(i + 7)); } // Return the name to use for an init function. There can be multiple @@ -387,11 +440,12 @@ Gogo::init_function_name() char buf[30]; snprintf(buf, sizeof buf, "..init%d", init_count); ++init_count; - std::string ret = this->pkgpath(); - return ret + buf; + return this->pkgpath() + buf; } -// Return the name to use for a nested function. +// Return the name to use for a nested function. This name acts like +// a Go identifier. This name will be rewritten by +// Function::backend_name. std::string Gogo::nested_function_name(Named_object* enclosing) @@ -420,7 +474,9 @@ Gogo::nested_function_name(Named_object* enclosing) enclosing->func_value()->type()->receiver(); if (rcvr != NULL) { - prefix = rcvr->type()->mangled_name(this); + Backend_name bname; + rcvr->type()->backend_name(this, &bname); + prefix = bname.name(); prefix.push_back('.'); } prefix.append(Gogo::unpack_hidden_name(enclosing->name())); @@ -460,7 +516,8 @@ Gogo::redefined_function_name() } // Return the name to use for a recover thunk for the function NAME. -// If the function is a method, RTYPE is the receiver type. +// If the function is a method, RTYPE is the receiver type. This is a +// name that acts like a Go identifier. std::string Gogo::recover_thunk_name(const std::string& name, const Type* rtype) @@ -468,10 +525,12 @@ Gogo::recover_thunk_name(const std::string& name, const Type* rtype) std::string ret; if (rtype != NULL) { - ret = rtype->mangled_name(this); + Backend_name bname; + rtype->deref()->backend_name(this, &bname); + ret = bname.name(); ret.append(1, '.'); } - if (Gogo::is_special_name(name)) + if (Gogo::special_name_pos(name) != std::string::npos) ret.append(name); else ret.append(Gogo::unpack_hidden_name(name)); @@ -504,8 +563,8 @@ Gogo::initializer_name() return buf; } -// Return the name of the variable used to represent the zero value of -// a map. This is a globally visible common symbol. +// Return the assembler name of the variable used to represent the +// zero value of a map. This is a globally visible common symbol. std::string Gogo::map_zero_value_name() @@ -513,7 +572,9 @@ Gogo::map_zero_value_name() return "go..zerovalue"; } -// Return the name to use for the import control function. +// Return the name to use for the import control function. This name +// is handled specially by Function::backend_name. It is not encoded +// further. const std::string& Gogo::get_init_fn_name() @@ -550,7 +611,7 @@ Gogo::dummy_init_fn_name() // can be a real init function or a dummy one. std::string -Gogo::pkgpath_from_init_fn_name(std::string name) +Gogo::pkgpath_symbol_from_init_fn_name(std::string name) { go_assert(!name.empty()); if (name[0] == '~') @@ -561,85 +622,71 @@ Gogo::pkgpath_from_init_fn_name(std::string name) go_unreachable(); } -// Return a mangled name for a type. These names appear in symbol -// names in the assembler file for things like type descriptors and -// methods. +// Set BNAME to a name for a type to use in a symbol. Return a name +// for a type to use in a symbol. These names appear in symbol names +// in the assembler file for things like type descriptors and methods. -std::string -Type::mangled_name(Gogo* gogo) const +void +Type::backend_name(Gogo* gogo, Backend_name* bname) const { - std::string ret; - - // The do_mangled_name virtual function will set RET to the mangled - // name before glue character mapping. - this->do_mangled_name(gogo, &ret); - - // Type descriptor names and interface method table names use a ".." - // before the mangled name of a type, so to avoid ambiguity the - // mangled name must not start with 'u' or 'U' or a digit. - go_assert((ret[0] < '0' || ret[0] > '9') && ret[0] != ' '); - if (ret[0] == 'u' || ret[0] == 'U') - ret = " " + ret; - - // Map glue characters as described above. - - // The mapping is only unambiguous if there is no .DIGIT in the - // string, so check that. - for (size_t i = ret.find('.'); - i != std::string::npos; - i = ret.find('.', i + 1)) + // Special case top level named types to get nicer name encodings + // for this common case. + const Named_type* nt = this->unalias()->named_type(); + if (nt != NULL && !nt->is_builtin()) { - if (i + 1 < ret.size()) + unsigned int index; + if (nt->in_function(&index) == NULL) { - char c = ret[i + 1]; - go_assert(c < '0' || c > '9'); + const Named_object* no = nt->named_object(); + if (no->package() == NULL) + bname->add(gogo->pkgpath()); + else + bname->add(no->package()->pkgpath()); + bname->add(Gogo::unpack_hidden_name(no->name())); + return; } } - // The order of these characters is the replacement code. - const char * const replace = " *;,{}[]()"; + std::string name; + bool is_non_identifier = false; - const size_t rlen = strlen(replace); - char buf[2]; - buf[0] = '.'; - for (size_t ri = 0; ri < rlen; ++ri) - { - buf[1] = '0' + ri; - while (true) - { - size_t i = ret.find(replace[ri]); - if (i == std::string::npos) - break; - ret.replace(i, 1, buf, 2); - } - } + // The do_symbol_name virtual function will set RET to the mangled + // name before encoding. + this->do_mangled_name(gogo, &name, &is_non_identifier); - return ret; + bname->add(name); + if (is_non_identifier) + bname->set_is_non_identifier(); } // The mangled name is implemented as a method on each instance of // Type. void -Error_type::do_mangled_name(Gogo*, std::string* ret) const +Error_type::do_mangled_name(Gogo*, std::string* ret, + bool* is_non_identifier) const { ret->append("{error}"); + *is_non_identifier = true; } void -Void_type::do_mangled_name(Gogo*, std::string* ret) const +Void_type::do_mangled_name(Gogo*, std::string* ret, + bool* is_non_identifier) const { ret->append("{void}"); + *is_non_identifier = true; } void -Boolean_type::do_mangled_name(Gogo*, std::string* ret) const +Boolean_type::do_mangled_name(Gogo*, std::string* ret, bool*) const { ret->append("bool"); } void -Integer_type::do_mangled_name(Gogo*, std::string* ret) const +Integer_type::do_mangled_name(Gogo*, std::string* ret, + bool* is_non_identifier) const { char buf[100]; snprintf(buf, sizeof buf, "%s%si%d", @@ -647,43 +694,53 @@ Integer_type::do_mangled_name(Gogo*, std::string* ret) const this->is_unsigned_ ? "u" : "", this->bits_); ret->append(buf); + if (this->is_abstract_) + *is_non_identifier = true; } void -Float_type::do_mangled_name(Gogo*, std::string* ret) const +Float_type::do_mangled_name(Gogo*, std::string* ret, + bool* is_non_identifier) const { char buf[100]; snprintf(buf, sizeof buf, "%sfloat%d", this->is_abstract_ ? "{abstract}" : "", this->bits_); ret->append(buf); + if (this->is_abstract_) + *is_non_identifier = true; } void -Complex_type::do_mangled_name(Gogo*, std::string* ret) const +Complex_type::do_mangled_name(Gogo*, std::string* ret, + bool* is_non_identifier) const { char buf[100]; snprintf(buf, sizeof buf, "%sc%d", this->is_abstract_ ? "{abstract}" : "", this->bits_); ret->append(buf); + if (this->is_abstract_) + *is_non_identifier = true; } void -String_type::do_mangled_name(Gogo*, std::string* ret) const +String_type::do_mangled_name(Gogo*, std::string* ret, bool*) const { ret->append("string"); } void -Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const +Function_type::do_mangled_name(Gogo* gogo, std::string* ret, + bool* is_non_identifier) const { ret->append("func"); if (this->receiver_ != NULL) { ret->push_back('('); - this->append_mangled_name(this->receiver_->type(), gogo, ret); + this->append_mangled_name(this->receiver_->type(), gogo, ret, + is_non_identifier); ret->append(")"); } @@ -701,13 +758,9 @@ Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const else ret->push_back(','); if (this->is_varargs_ && p + 1 == params->end()) - { - // We can't use "..." here because the mangled name - // might start with 'u' or 'U', which would be ambiguous - // with the encoding of Unicode characters. - ret->append(",,,"); - } - this->append_mangled_name(p->type(), gogo, ret); + ret->append("..."); + this->append_mangled_name(p->type(), gogo, ret, + is_non_identifier); } } ret->push_back(')'); @@ -725,27 +778,34 @@ Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const first = false; else ret->append(","); - this->append_mangled_name(p->type(), gogo, ret); + this->append_mangled_name(p->type(), gogo, ret, is_non_identifier); } } ret->push_back(')'); + + *is_non_identifier = true; } void -Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret) const +Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret, + bool* is_non_identifier) const { ret->push_back('*'); - this->append_mangled_name(this->to_type_, gogo, ret); + this->append_mangled_name(this->to_type_, gogo, ret, is_non_identifier); + *is_non_identifier = true; } void -Nil_type::do_mangled_name(Gogo*, std::string* ret) const +Nil_type::do_mangled_name(Gogo*, std::string* ret, + bool* is_non_identifier) const { ret->append("{nil}"); + *is_non_identifier = true; } void -Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const +Struct_type::do_mangled_name(Gogo* gogo, std::string* ret, + bool* is_non_identifier) const { ret->append("struct{"); @@ -776,15 +836,16 @@ Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const if (p->is_anonymous() && p->type()->named_type() != NULL && p->type()->named_type()->is_alias()) - p->type()->named_type()->append_mangled_type_name(gogo, true, ret); + p->type()->named_type()->append_symbol_type_name(gogo, true, ret, + is_non_identifier); else - this->append_mangled_name(p->type(), gogo, ret); + this->append_mangled_name(p->type(), gogo, ret, is_non_identifier); if (p->has_tag()) { // Use curly braces around a struct tag, since they are - // unambiguous here and we have no encoding for - // quotation marks. + // unambiguous here and struct tags rarely contain curly + // braces. ret->push_back('{'); ret->append(go_mangle_struct_tag(p->tag())); ret->push_back('}'); @@ -793,10 +854,13 @@ Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const } ret->push_back('}'); + + *is_non_identifier = true; } void -Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const +Array_type::do_mangled_name(Gogo* gogo, std::string* ret, + bool* is_non_identifier) const { ret->push_back('['); if (this->length_ != NULL) @@ -821,32 +885,38 @@ Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const ret->append("x"); } ret->push_back(']'); - this->append_mangled_name(this->element_type_, gogo, ret); + this->append_mangled_name(this->element_type_, gogo, ret, is_non_identifier); + *is_non_identifier = true; } void -Map_type::do_mangled_name(Gogo* gogo, std::string* ret) const +Map_type::do_mangled_name(Gogo* gogo, std::string* ret, + bool* is_non_identifier) const { ret->append("map["); - this->append_mangled_name(this->key_type_, gogo, ret); + this->append_mangled_name(this->key_type_, gogo, ret, is_non_identifier); ret->push_back(']'); - this->append_mangled_name(this->val_type_, gogo, ret); + this->append_mangled_name(this->val_type_, gogo, ret, is_non_identifier); + *is_non_identifier = true; } void -Channel_type::do_mangled_name(Gogo* gogo, std::string* ret) const +Channel_type::do_mangled_name(Gogo* gogo, std::string* ret, + bool* is_non_identifier) const { if (!this->may_send_) - ret->append("{}"); + ret->append("<-"); ret->append("chan"); if (!this->may_receive_) - ret->append("{}"); + ret->append("<-"); ret->push_back(' '); - this->append_mangled_name(this->element_type_, gogo, ret); + this->append_mangled_name(this->element_type_, gogo, ret, is_non_identifier); + *is_non_identifier = true; } void -Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const +Interface_type::do_mangled_name(Gogo* gogo, std::string* ret, + bool* is_non_identifier) const { go_assert(this->methods_are_finalized_); @@ -872,25 +942,29 @@ Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const ret->push_back(' '); } - this->append_mangled_name(p->type(), gogo, ret); + this->append_mangled_name(p->type(), gogo, ret, is_non_identifier); } this->seen_ = false; } ret->push_back('}'); + + *is_non_identifier = true; } void -Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const +Named_type::do_mangled_name(Gogo* gogo, std::string* ret, + bool* is_non_identifier) const { - this->append_mangled_type_name(gogo, false, ret); + this->append_symbol_type_name(gogo, false, ret, is_non_identifier); } void -Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret) const +Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret, + bool *is_non_identifier) const { if (this->is_defined()) - this->append_mangled_name(this->real_type(), gogo, ret); + this->append_mangled_name(this->real_type(), gogo, ret, is_non_identifier); else { const Named_object* no = this->named_object(); @@ -903,13 +977,14 @@ Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret) const } } -// Append the mangled name for a named type to RET. For an alias we +// Append the symbol name for a named type to RET. For an alias we // normally use the real name, but if USE_ALIAS is true we use the // alias name itself. void -Named_type::append_mangled_type_name(Gogo* gogo, bool use_alias, - std::string* ret) const +Named_type::append_symbol_type_name(Gogo* gogo, bool use_alias, + std::string* ret, + bool* is_non_identifier) const { if (this->is_error_) return; @@ -918,7 +993,7 @@ Named_type::append_mangled_type_name(Gogo* gogo, bool use_alias, if (this->seen_alias_) return; this->seen_alias_ = true; - this->append_mangled_name(this->type_, gogo, ret); + this->append_mangled_name(this->type_, gogo, ret, is_non_identifier); this->seen_alias_ = false; return; } @@ -933,7 +1008,13 @@ Named_type::append_mangled_type_name(Gogo* gogo, bool use_alias, const Typed_identifier* rcvr = this->in_function_->func_value()->type()->receiver(); if (rcvr != NULL) - ret->append(rcvr->type()->deref()->mangled_name(gogo)); + { + Backend_name bname; + rcvr->type()->deref()->backend_name(gogo, &bname); + ret->append(bname.name()); + if (bname.is_non_identifier()) + *is_non_identifier = true; + } else if (this->in_function_->package() == NULL) ret->append(gogo->pkgpath()); else @@ -956,23 +1037,46 @@ Named_type::append_mangled_type_name(Gogo* gogo, bool use_alias, if (this->in_function_ != NULL && this->in_function_index_ > 0) { char buf[30]; - snprintf(buf, sizeof buf, "..i%u", this->in_function_index_); + snprintf(buf, sizeof buf, ".i%u", this->in_function_index_); ret->append(buf); } } -// Return the name for the type descriptor symbol for TYPE. This can -// be a global, common, or local symbol, depending. NT is not NULL if -// it is the name to use. +// Given a name which may or may not have been hidden, append the +// appropriate version of the name to the result string. -std::string -Gogo::type_descriptor_name(const Type* type, Named_type* nt) +void +Gogo::append_possibly_hidden_name(std::string *result, const std::string& name) +{ + if (!Gogo::is_hidden_name(name)) + *result += name; + else + *result += name.substr(1); +} + +// Set BNAME to the name for the type descriptor symbol for TYPE. +// This can be a global, common, or local symbol, depending. NT is +// not NULL if it is the name to use. + +void +Gogo::type_descriptor_backend_name(const Type* type, Named_type* nt, + Backend_name* bname) { // The type descriptor symbol for the unsafe.Pointer type is defined // in libgo/runtime/go-unsafe-pointer.c, so just use a reference to // that symbol for all unsafe pointer types. if (type->is_unsafe_pointer_type()) - return "unsafe.Pointer..d"; + { + bname->set_asm_name("unsafe.Pointer..d"); + return; + } + + bool is_pointer = false; + if (nt == NULL && type->points_to() != NULL) + { + nt = type->points_to()->unalias()->named_type(); + is_pointer = true; + } if (nt == NULL) { @@ -981,63 +1085,28 @@ Gogo::type_descriptor_name(const Type* type, Named_type* nt) // using a named type, like "int". go_assert(!type->is_basic_type()); - return "type.." + type->mangled_name(this); + type->backend_name(this, bname); + bname->set_prefix("type.."); } - - std::string ret; - Named_object* no = nt->named_object(); - unsigned int index; - const Named_object* in_function = nt->in_function(&index); - if (nt->is_builtin()) - go_assert(in_function == NULL); else { - if (in_function != NULL) - { - const Typed_identifier* rcvr = - in_function->func_value()->type()->receiver(); - if (rcvr != NULL) - ret.append(rcvr->type()->deref()->mangled_name(this)); - else if (in_function->package() == NULL) - ret.append(this->pkgpath()); - else - ret.append(in_function->package()->pkgpath()); - ret.push_back('.'); - ret.append(Gogo::unpack_hidden_name(in_function->name())); - ret.push_back('.'); - } - - if (no->package() == NULL) - ret.append(this->pkgpath()); - else - ret.append(no->package()->pkgpath()); - ret.push_back('.'); - } - - Gogo::append_possibly_hidden_name(&ret, no->name()); - - if (in_function != NULL && index > 0) - { - char buf[30]; - snprintf(buf, sizeof buf, "..i%u", index); - ret.append(buf); + nt->backend_name(this, bname); + bname->set_suffix(is_pointer ? "..p" : "..d"); } - - ret.append("..d"); - - return ret; } // Return the name of the type descriptor list symbol of a package. +// This is passed directly to the backend without further encoding. std::string -Gogo::type_descriptor_list_symbol(const std::string& pkgpath) +Gogo::type_descriptor_list_symbol(const std::string& pkgpath_symbol) { - return pkgpath + "..types"; + return pkgpath_symbol + "..types"; } // Return the name of the list of all type descriptor lists. This is -// only used in the main package. +// only used in the main package. This is passed directly to the +// backend without further encoding. std::string Gogo::typelists_symbol() @@ -1045,24 +1114,30 @@ Gogo::typelists_symbol() return "go..typelists"; } -// Return the name for the GC symbol for a type. This is used to -// initialize the gcdata field of a type descriptor. This is a local -// name never referenced outside of this assembly file. (Note that -// some type descriptors will initialize the gcdata field with a name -// generated by ptrmask_symbol_name rather than this method.) +// Return the assembler name for the GC symbol for a type. This is +// used to initialize the gcdata field of a type descriptor. This is +// a local name never referenced outside of this assembly file. (Note +// that some type descriptors will initialize the gcdata field with a +// name generated by ptrmask_symbol_name rather than this method.) +// This is passed directly to the backend without further encoding. std::string Gogo::gc_symbol_name(Type* type) { - return this->type_descriptor_name(type, type->named_type()) + "..g"; + Backend_name bname; + this->type_descriptor_backend_name(type, type->named_type(), &bname); + bname.append_suffix("..g"); + return bname.asm_name(); } -// Return the name for a ptrmask variable. PTRMASK_SYM_NAME is a -// base32 string encoding the ptrmask (as returned by Ptrmask::symname -// in types.cc). This name is used to intialize the gcdata field of a -// type descriptor. These names are globally visible. (Note that -// some type descriptors will initialize the gcdata field with a name -// generated by gc_symbol_name rather than this method.) +// Return the assembler name for a ptrmask variable. PTRMASK_SYM_NAME +// is a base32 string encoding the ptrmask (as returned by +// Ptrmask::symname in types.cc). This name is used to intialize the +// gcdata field of a type descriptor. These names are globally +// visible. (Note that some type descriptors will initialize the +// gcdata field with a name generated by gc_symbol_name rather than +// this method.) This is passed directly to the backend without +// further encoding. std::string Gogo::ptrmask_symbol_name(const std::string& ptrmask_sym_name) @@ -1070,34 +1145,134 @@ Gogo::ptrmask_symbol_name(const std::string& ptrmask_sym_name) return "gcbits.." + ptrmask_sym_name; } -// Return the name to use for an interface method table used for the -// ordinary type TYPE converted to the interface type ITYPE. +// Return the assembler name to use for an interface method table used +// for the ordinary type TYPE converted to the interface type ITYPE. // IS_POINTER is true if this is for the method set for a pointer -// receiver. +// receiver. This is passed directly to the backend without further +// encoding. std::string Gogo::interface_method_table_name(Interface_type* itype, Type* type, bool is_pointer) { + Backend_name iname; + itype->backend_name(this, &iname); + Backend_name tname; + type->backend_name(this, &tname); return ((is_pointer ? "pimt.." : "imt..") - + itype->mangled_name(this) + + iname.asm_name() + ".." - + type->mangled_name(this)); + + tname.asm_name()); +} + +// If NAME is a special name with a ".." suffix, return the position +// of that suffix. This is needed because various special names use +// "..SUFFIX", but unpack_hidden_name just looks for '.', and because +// we don't want to encode the suffix. + +size_t +Gogo::special_name_pos(const std::string& name) +{ + size_t pos = name.rfind(".."); + if (pos == std::string::npos) + return pos; + std::string suffix(name.substr(pos)); + if (suffix == "..hash" + || suffix == "..eq" + || suffix == "..stub" + || suffix == "..d" + || suffix == "..f" + || suffix == "..r" + || suffix == "..import") + return pos; + if ((suffix.compare(2, 4, "func") == 0 + || suffix.compare(2, 4, "init") == 0) + && Gogo::is_digits(suffix.substr(6))) + return pos; + if (suffix.compare(2, 5, "thunk") == 0 + && Gogo::is_digits(suffix.substr(7))) + return pos; + return std::string::npos; } -// Return whether NAME is a special name that can not be passed to -// unpack_hidden_name. This is needed because various special names -// use "..SUFFIX", but unpack_hidden_name just looks for '.'. +// Return whether the string is non-empty and contains only digits. bool -Gogo::is_special_name(const std::string& name) +Gogo::is_digits(const std::string& s) +{ + if (s.empty()) + return false; + for (size_t i = 0; i < s.size(); ++i) + if (s[i] < '0' || s[i] > '9') + return false; + return true; +} + +// Class Backend_name. + +// Get the user visible name. + +std::string +Backend_name::name() const +{ + if (this->is_asm_name_) + return this->components_[0]; + + // If there is some character in the name that can't appear in an + // identifier, use the assembler name as the user name. This avoids + // possible problems in the assembler or debugger. The usual + // demangling scheme will still work. We use a prefix of "g." to + // tell the debugger about this. + if (this->is_non_identifier_) + return "g." + this->asm_name(); + + std::string ret; + if (this->prefix_ != NULL) + ret.append(this->prefix_); + for (int i = 0; i < this->count_; i++) + { + if (i > 0) + ret.push_back('.'); + ret.append(this->components_[i]); + } + if (!this->suffix_.empty()) + ret.append(this->suffix_); + return ret; +} + +// Get the assembler name. + +std::string +Backend_name::asm_name() const +{ + if (this->is_asm_name_) + return this->components_[0]; + std::string ret; + if (this->prefix_ != NULL) + ret.append(this->prefix_); + for (int i = 0; i < this->count_; i++) + { + if (i > 0) + ret.push_back('.'); + ret.append(go_encode_id(this->components_[i])); + } + if (!this->suffix_.empty()) + ret.append(this->suffix_); + return ret; +} + +// Get the assembler name, or the empty string if it is the same as +// the user visible name. + +std::string +Backend_name::optional_asm_name() const { - return (name.find("..hash") != std::string::npos - || name.find("..eq") != std::string::npos - || name.find("..stub") != std::string::npos - || name.find("..func") != std::string::npos - || name.find("..r") != std::string::npos - || name.find("..init") != std::string::npos - || name.find("..thunk") != std::string::npos - || name.find("..import") != std::string::npos); + if (this->is_asm_name_) + return ""; + if (this->is_non_identifier_) + return this->asm_name(); + for (int i = 0; i < this->count_; i++) + if (go_id_needs_encoding(this->components_[i])) + return this->asm_name(); + return ""; } diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index ef59415..1664fe3 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -995,7 +995,7 @@ Parse::parameter_list(bool* is_varargs) } if (mix_error) { - go_error_at(location, "invalid named/anonymous mix"); + go_error_at(location, "mixed named and unnamed function parameters"); saw_error = true; } if (saw_error) @@ -1442,6 +1442,7 @@ Parse::const_decl() void Parse::const_spec(int iota, Type** last_type, Expression_list** last_expr_list) { + Location loc = this->location(); Typed_identifier_list til; this->identifier_list(&til); @@ -1466,7 +1467,11 @@ Parse::const_spec(int iota, Type** last_type, Expression_list** last_expr_list) for (Expression_list::const_iterator p = (*last_expr_list)->begin(); p != (*last_expr_list)->end(); ++p) - expr_list->push_back((*p)->copy()); + { + Expression* copy = (*p)->copy(); + copy->set_location(loc); + expr_list->push_back(copy); + } } else { @@ -1567,7 +1572,6 @@ Parse::type_spec(void*, unsigned int pragmas) go_error_at(this->location(), "unexpected semicolon or newline in type declaration"); type = Type::make_error_type(); - this->advance_token(); } if (type->is_error_type()) @@ -2071,6 +2075,7 @@ Parse::create_dummy_global(Type* type, Expression* init, if (type == NULL && init == NULL) type = Type::lookup_bool_type(); Variable* var = new Variable(type, init, true, false, false, location); + var->set_is_global_sink(); static int count; char buf[30]; snprintf(buf, sizeof buf, "_.%d", count); @@ -2165,8 +2170,12 @@ Parse::simple_var_decl_or_assignment(const std::string& name, id = this->gogo_->pack_hidden_name(id, is_id_exported); ins = uniq_idents.insert(id); if (!ins.second && !Gogo::is_sink_name(id)) - go_error_at(id_location, "multiple assignments to %s", - Gogo::message_name(id).c_str()); + { + // Use %s to print := to avoid -Wformat-diag warning. + go_error_at(id_location, + "%qs repeated on left side of %s", + Gogo::message_name(id).c_str(), ":="); + } til.push_back(Typed_identifier(id, NULL, location)); } else @@ -2219,7 +2228,11 @@ Parse::simple_var_decl_or_assignment(const std::string& name, const Token* token = this->advance_token(); if (!dup_name.empty()) - go_error_at(dup_loc, "multiple assignments to %s", dup_name.c_str()); + { + // Use %s to print := to avoid -Wformat-diag warning. + go_error_at(dup_loc, "%qs repeated on left side of %s", + dup_name.c_str(), ":="); + } if (p_range_clause != NULL && token->is_keyword(KEYWORD_RANGE)) { @@ -4414,7 +4427,7 @@ Parse::if_stat() { Location semi_loc = this->location(); if (this->advance_token()->is_op(OPERATOR_LCURLY)) - go_error_at(semi_loc, "missing %<{%> after if clause"); + go_error_at(semi_loc, "unexpected semicolon or newline, expecting %<{%> after if clause"); // Otherwise we will get an error when we call this->block // below. } @@ -4478,7 +4491,7 @@ Parse::switch_stat(Label* label) bool saw_simple_stat = false; Expression* switch_val = NULL; - bool saw_send_stmt; + bool saw_send_stmt = false; Type_switch type_switch; bool have_type_switch_block = false; if (this->simple_stat_may_start_here()) @@ -4810,7 +4823,7 @@ Parse::type_switch_body(Label* label, const Type_switch& type_switch, } } if (!used) - go_error_at(type_switch.location, "%qs declared and not used", + go_error_at(type_switch.location, "%qs declared but not used", Gogo::message_name(var_name).c_str()); } return statement; @@ -5313,7 +5326,7 @@ Parse::for_stat(Label* label) { // We might be looking at a Condition, an InitStat, or a // RangeClause. - bool saw_send_stmt; + bool saw_send_stmt = false; cond = this->simple_stat(false, &saw_send_stmt, &range_clause, NULL); if (!this->peek_token()->is_op(OPERATOR_SEMICOLON)) { @@ -5351,7 +5364,7 @@ Parse::for_stat(Label* label) { Location semi_loc = this->location(); if (this->advance_token()->is_op(OPERATOR_LCURLY)) - go_error_at(semi_loc, "missing %<{%> after for clause"); + go_error_at(semi_loc, "unexpected semicolon or newline, expecting %<{%> after for clause"); // Otherwise we will get an error when we call this->block // below. } @@ -5422,7 +5435,7 @@ Parse::for_clause(Expression** cond, Block** post) *cond = NULL; else if (this->peek_token()->is_op(OPERATOR_LCURLY)) { - go_error_at(this->location(), "missing %<{%> after for clause"); + go_error_at(this->location(), "unexpected semicolon or newline, expecting %<{%> after for clause"); *cond = NULL; *post = NULL; return; @@ -5780,7 +5793,7 @@ Parse::import_spec(void*, unsigned int pragmas) if (!token->is_string()) { - go_error_at(this->location(), "import statement not a string"); + go_error_at(this->location(), "import path must be a string"); this->advance_token(); return; } diff --git a/gcc/go/gofrontend/runtime.def b/gcc/go/gofrontend/runtime.def index 0796cba..ec01be0 100644 --- a/gcc/go/gofrontend/runtime.def +++ b/gcc/go/gofrontend/runtime.def @@ -62,12 +62,6 @@ DEF_GO_RUNTIME(STRINGTOSLICERUNE, "runtime.stringtoslicerune", P2(POINTER, STRING), R1(SLICE)) -// Complex division. -DEF_GO_RUNTIME(COMPLEX64_DIV, "__go_complex64_div", - P2(COMPLEX64, COMPLEX64), R1(COMPLEX64)) -DEF_GO_RUNTIME(COMPLEX128_DIV, "__go_complex128_div", - P2(COMPLEX128, COMPLEX128), R1(COMPLEX128)) - // Make a slice. DEF_GO_RUNTIME(MAKESLICE, "runtime.makeslice", P3(TYPE, INT, INT), R1(POINTER)) @@ -83,7 +77,7 @@ DEF_GO_RUNTIME(MAKEMAP64, "runtime.makemap64", P3(TYPE, INT64, POINTER), R1(MAP)) // Make a map with no hint, or a small constant hint. -DEF_GO_RUNTIME(MAKEMAP_SMALL, "runtime.makemap_small", P0(), R1(MAP)) +DEF_GO_RUNTIME(MAKEMAP_SMALL, "runtime.makemap__small", P0(), R1(MAP)) // Build a map from a composite literal. DEF_GO_RUNTIME(CONSTRUCT_MAP, "__go_construct_map", @@ -95,19 +89,19 @@ DEF_GO_RUNTIME(MAPACCESS1, "runtime.mapaccess1", P3(TYPE, MAP, POINTER), R1(POINTER)) // Look up a uint32 key in a map. -DEF_GO_RUNTIME(MAPACCESS1_FAST32, "runtime.mapaccess1_fast32", +DEF_GO_RUNTIME(MAPACCESS1_FAST32, "runtime.mapaccess1__fast32", P3(TYPE, MAP, UINT32), R1(POINTER)) // Look up a uint64 key in a map. -DEF_GO_RUNTIME(MAPACCESS1_FAST64, "runtime.mapaccess1_fast64", +DEF_GO_RUNTIME(MAPACCESS1_FAST64, "runtime.mapaccess1__fast64", P3(TYPE, MAP, UINT64), R1(POINTER)) // Look up a string key in a map. -DEF_GO_RUNTIME(MAPACCESS1_FASTSTR, "runtime.mapaccess1_faststr", +DEF_GO_RUNTIME(MAPACCESS1_FASTSTR, "runtime.mapaccess1__faststr", P3(TYPE, MAP, STRING), R1(POINTER)) // Look up a key in a map when the value is large. -DEF_GO_RUNTIME(MAPACCESS1_FAT, "runtime.mapaccess1_fat", +DEF_GO_RUNTIME(MAPACCESS1_FAT, "runtime.mapaccess1__fat", P4(TYPE, MAP, POINTER, POINTER), R1(POINTER)) // Look up a key in a map returning the value and whether it is @@ -117,22 +111,22 @@ DEF_GO_RUNTIME(MAPACCESS2, "runtime.mapaccess2", P3(TYPE, MAP, POINTER), // Look up a uint32 key in a map returning the value and whether // it is present. -DEF_GO_RUNTIME(MAPACCESS2_FAST32, "runtime.mapaccess2_fast32", +DEF_GO_RUNTIME(MAPACCESS2_FAST32, "runtime.mapaccess2__fast32", P3(TYPE, MAP, UINT32), R2(POINTER, BOOL)) // Look up a uint64 key in a map returning the value and whether // it is present. -DEF_GO_RUNTIME(MAPACCESS2_FAST64, "runtime.mapaccess2_fast64", +DEF_GO_RUNTIME(MAPACCESS2_FAST64, "runtime.mapaccess2__fast64", P3(TYPE, MAP, UINT64), R2(POINTER, BOOL)) // Look up a string key in a map returning the value and whether // it is present. -DEF_GO_RUNTIME(MAPACCESS2_FASTSTR, "runtime.mapaccess2_faststr", +DEF_GO_RUNTIME(MAPACCESS2_FASTSTR, "runtime.mapaccess2__faststr", P3(TYPE, MAP, STRING), R2(POINTER, BOOL)) // Look up a key in a map, returning the value and whether it is // present, when the value is large. -DEF_GO_RUNTIME(MAPACCESS2_FAT, "runtime.mapaccess2_fat", +DEF_GO_RUNTIME(MAPACCESS2_FAT, "runtime.mapaccess2__fat", P4(TYPE, MAP, POINTER, POINTER), R2(POINTER, BOOL)) // Assignment to a key in a map. @@ -140,38 +134,38 @@ DEF_GO_RUNTIME(MAPASSIGN, "runtime.mapassign", P3(TYPE, MAP, POINTER), R1(POINTER)) // Assignment to a uint32 key in a map. -DEF_GO_RUNTIME(MAPASSIGN_FAST32, "runtime.mapassign_fast32", +DEF_GO_RUNTIME(MAPASSIGN_FAST32, "runtime.mapassign__fast32", P3(TYPE, MAP, UINT32), R1(POINTER)) // Assignment to a uint64 key in a map. -DEF_GO_RUNTIME(MAPASSIGN_FAST64, "runtime.mapassign_fast64", +DEF_GO_RUNTIME(MAPASSIGN_FAST64, "runtime.mapassign__fast64", P3(TYPE, MAP, UINT64), R1(POINTER)) // Assignment to a 32-bit pointer key in a map. -DEF_GO_RUNTIME(MAPASSIGN_FAST32PTR, "runtime.mapassign_fast32ptr", +DEF_GO_RUNTIME(MAPASSIGN_FAST32PTR, "runtime.mapassign__fast32ptr", P3(TYPE, MAP, POINTER), R1(POINTER)) // Assignment to a 64-bit pointer key in a map. -DEF_GO_RUNTIME(MAPASSIGN_FAST64PTR, "runtime.mapassign_fast64ptr", +DEF_GO_RUNTIME(MAPASSIGN_FAST64PTR, "runtime.mapassign__fast64ptr", P3(TYPE, MAP, POINTER), R1(POINTER)) // Assignment to a string key in a map. -DEF_GO_RUNTIME(MAPASSIGN_FASTSTR, "runtime.mapassign_faststr", +DEF_GO_RUNTIME(MAPASSIGN_FASTSTR, "runtime.mapassign__faststr", P3(TYPE, MAP, STRING), R1(POINTER)) // Delete a key from a map. DEF_GO_RUNTIME(MAPDELETE, "runtime.mapdelete", P3(TYPE, MAP, POINTER), R0()) // Delete a uint32 key from a map. -DEF_GO_RUNTIME(MAPDELETE_FAST32, "runtime.mapdelete_fast32", +DEF_GO_RUNTIME(MAPDELETE_FAST32, "runtime.mapdelete__fast32", P3(TYPE, MAP, UINT32), R0()) // Delete a uint64 key from a map. -DEF_GO_RUNTIME(MAPDELETE_FAST64, "runtime.mapdelete_fast64", +DEF_GO_RUNTIME(MAPDELETE_FAST64, "runtime.mapdelete__fast64", P3(TYPE, MAP, UINT64), R0()) // Delete a string key from a map. -DEF_GO_RUNTIME(MAPDELETE_FASTSTR, "runtime.mapdelete_faststr", +DEF_GO_RUNTIME(MAPDELETE_FASTSTR, "runtime.mapdelete__faststr", P3(TYPE, MAP, STRING), R0()) // Begin a range over a map. @@ -201,8 +195,8 @@ DEF_GO_RUNTIME(CHANRECV2, "runtime.chanrecv2", P2(CHAN, POINTER), R1(BOOL)) // Run a select, returning the index of the selected clause and // whether that channel received a value. -DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo", P3(POINTER, POINTER, INT), - R2(INT, BOOL)) +DEF_GO_RUNTIME(SELECTGO, "runtime.selectgo", + P5(POINTER, POINTER, INT, INT, BOOL), R2(INT, BOOL)) // Non-blocking send a value on a channel, used for two-case select // statement with a default case. @@ -248,14 +242,6 @@ DEF_GO_RUNTIME(DEFERRETURN, "runtime.deferreturn", P1(BOOLPTR), R0()) DEF_GO_RUNTIME(CLOSE, "runtime.closechan", P1(CHAN), R0()) -// Copy. -DEF_GO_RUNTIME(SLICECOPY, "runtime.slicecopy", - P5(POINTER, INT, POINTER, INT, UINTPTR), R1(INT)) - -// Copy from string. -DEF_GO_RUNTIME(SLICESTRINGCOPY, "runtime.slicestringcopy", - P3(POINTER, INT, STRING), R1(INT)) - // Copy of value containing pointers. DEF_GO_RUNTIME(TYPEDSLICECOPY, "runtime.typedslicecopy", P5(TYPE, POINTER, INT, POINTER, INT), R1(INT)) @@ -265,6 +251,11 @@ DEF_GO_RUNTIME(GROWSLICE, "runtime.growslice", P5(TYPE, POINTER, INT, INT, INT), R1(SLICE)) +// Check the length and cap passed to make, without making a slice. +// This is used for apend(s, make([]T, len)...). +DEF_GO_RUNTIME(CHECK_MAKE_SLICE, "runtime.checkMakeSlice", P3(TYPE, INT, INT), + R1(UINTPTR)) + // Register roots (global variables) for the garbage collector. DEF_GO_RUNTIME(REGISTER_GC_ROOTS, "runtime.registerGCRoots", P1(POINTER), R0()) diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index ad89807..da0e084 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -1985,18 +1985,42 @@ Tuple_type_guard_assignment_statement::lower_to_object_type( NULL, loc); b->add_statement(val_temp); - // ok = CODE(type_descriptor, expr, &val_temp) + // var ok_temp bool + Temporary_statement* ok_temp = NULL; + if (!this->ok_->is_sink_expression()) + { + ok_temp = Statement::make_temporary(this->ok_->type(), + NULL, loc); + b->add_statement(ok_temp); + } + + // ok_temp = CODE(type_descriptor, expr, &val_temp) Expression* p1 = Expression::make_type_descriptor(this->type_, loc); Expression* ref = Expression::make_temporary_reference(val_temp, loc); Expression* p3 = Expression::make_unary(OPERATOR_AND, ref, loc); Expression* call = Runtime::make_call(code, loc, 3, p1, this->expr_, p3); - Statement* s = Statement::make_assignment(this->ok_, call, loc); + Statement* s; + if (ok_temp == NULL) + s = Statement::make_statement(call, true); + else + { + Expression* ok_ref = Expression::make_temporary_reference(ok_temp, loc); + s = Statement::make_assignment(ok_ref, call, loc); + } b->add_statement(s); // val = val_temp ref = Expression::make_temporary_reference(val_temp, loc); s = Statement::make_assignment(this->val_, ref, loc); b->add_statement(s); + + // ok = ok_temp + if (ok_temp != NULL) + { + ref = Expression::make_temporary_reference(ok_temp, loc); + s = Statement::make_assignment(this->ok_, ref, loc); + b->add_statement(s); + } } // Dump the AST representation for a tuple type guard statement. @@ -4514,7 +4538,7 @@ Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing, Type::make_nil_type(), NULL)) { go_error_at(this->val_->location(), - "cannot switch on value whose type that may not be compared"); + "cannot switch on value whose type may not be compared"); return Statement::make_error_statement(loc); } @@ -5267,22 +5291,23 @@ Select_clauses::Select_clause::traverse(Traverse* traverse) void Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, Block* b, Temporary_statement* scases, - size_t index, Temporary_statement* recvok) + int index, Temporary_statement* recvok) { Location loc = this->location_; - Expression* scase = Expression::make_temporary_reference(scases, loc); - Expression* index_expr = Expression::make_integer_ul(index, NULL, loc); - scase = Expression::make_array_index(scase, index_expr, NULL, NULL, loc); + this->set_case_index(index); if (this->is_default_) { go_assert(this->channel_ == NULL && this->val_ == NULL); - this->lower_default(b, scase); this->is_lowered_ = true; return; } + Expression* scase = Expression::make_temporary_reference(scases, loc); + Expression* index_expr = Expression::make_integer_sl(index, NULL, loc); + scase = Expression::make_array_index(scase, index_expr, NULL, NULL, loc); + // Evaluate the channel before the select statement. Temporary_statement* channel_temp = Statement::make_temporary(NULL, this->channel_, @@ -5302,15 +5327,6 @@ Select_clauses::Select_clause::lower(Gogo* gogo, Named_object* function, this->val_ = NULL; } -// Lower a default clause in a select statement. - -void -Select_clauses::Select_clause::lower_default(Block* b, Expression* scase) -{ - Location loc = this->location_; - this->set_case(b, scase, Expression::make_nil(loc), NULL, caseDefault); -} - // Lower a send clause in a select statement. void @@ -5342,7 +5358,7 @@ Select_clauses::Select_clause::lower_send(Block* b, Expression* scase, Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type()); valaddr = Expression::make_cast(unsafe_pointer_type, valaddr, loc); - this->set_case(b, scase, chanref, valaddr, caseSend); + this->set_case(b, scase, chanref, valaddr); } // Lower a receive clause in a select statement. @@ -5368,7 +5384,7 @@ Select_clauses::Select_clause::lower_recv(Gogo* gogo, Named_object* function, Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type()); valaddr = Expression::make_cast(unsafe_pointer_type, valaddr, loc); - this->set_case(b, scase, chanref, valaddr, caseRecv); + this->set_case(b, scase, chanref, valaddr); // If the block of statements is executed, arrange for the received // value to move from VAL to the place where the statements expect @@ -5423,8 +5439,7 @@ void Select_clauses::Select_clause::set_case(Block* b, Expression* scase, Expression* chanref, - Expression* elem, - int kind) + Expression* elem) { Location loc = this->location_; Struct_type* scase_type = scase->type()->struct_type(); @@ -5445,14 +5460,6 @@ Select_clauses::Select_clause::set_case(Block* b, s = Statement::make_assignment(ref, elem, loc); b->add_statement(s); } - - field_index = 2; - go_assert(scase_type->field(field_index)->is_field_name("kind")); - Type* uint16_type = Type::lookup_integer_type("uint16"); - Expression* k = Expression::make_integer_ul(kind, uint16_type, loc); - ref = Expression::make_field_reference(scase->copy(), field_index, loc); - s = Statement::make_assignment(ref, k, loc); - b->add_statement(s); } // Determine types. @@ -5553,6 +5560,19 @@ Select_clauses::Select_clause::dump_clause( // Class Select_clauses. +// Whether there is a default case. + +bool +Select_clauses::has_default() const +{ + for (Clauses::const_iterator p = this->clauses_.begin(); + p != this->clauses_.end(); + ++p) + if (p->is_default()) + return true; + return false; +} + // Traversal. int @@ -5570,17 +5590,60 @@ Select_clauses::traverse(Traverse* traverse) // Lowering. Here we pull out the channel and the send values, to // enforce the order of evaluation. We also add explicit send and -// receive statements to the clauses. +// receive statements to the clauses. This builds the entries in the +// local array of scase values. It sets *P_SEND_COUNT and +// *P_RECV_COUNT. void Select_clauses::lower(Gogo* gogo, Named_object* function, Block* b, - Temporary_statement* scases, Temporary_statement* recvok) + Temporary_statement* scases, Temporary_statement* recvok, + int *p_send_count, int *p_recv_count) { - size_t i = 0; + int send_count = 0; + int recv_count = 0; + bool has_default = false; for (Clauses::iterator p = this->clauses_.begin(); p != this->clauses_.end(); - ++p, ++i) - p->lower(gogo, function, b, scases, i, recvok); + ++p) + { + if (p->is_default()) + has_default = true; + else if (p->is_send()) + ++send_count; + else + ++recv_count; + } + + *p_send_count = send_count; + *p_recv_count = recv_count; + + int send_index = 0; + int recv_index = send_count; + for (Clauses::iterator p = this->clauses_.begin(); + p != this->clauses_.end(); + ++p) + { + int index; + if (p->is_default()) + index = -1; + else if (p->is_send()) + { + index = send_index; + ++send_index; + } + else + { + index = recv_index; + ++recv_index; + } + + p->lower(gogo, function, b, scases, index, recvok); + } + + go_assert(send_index == send_count); + go_assert(recv_index == send_count + recv_count); + go_assert(static_cast<size_t>(recv_index + (has_default ? 1 : 0)) + == this->size()); } // Determine types. @@ -5640,7 +5703,8 @@ Select_clauses::get_backend(Translate_context* context, p != this->clauses_.end(); ++p, ++i) { - Expression* index_expr = Expression::make_integer_ul(i, int_type, + Expression* index_expr = Expression::make_integer_sl(p->case_index(), + int_type, location); cases[i].push_back(index_expr->get_backend(context)); @@ -5725,6 +5789,7 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function, Block* b = new Block(enclosing, loc); int ncases = this->clauses_->size(); + bool has_default = this->clauses_->has_default(); // Zero-case select. Just block the execution. if (ncases == 0) @@ -5742,11 +5807,13 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function, // Two-case select with one default case. It is a non-blocking // send/receive. - if (ncases == 2 - && (this->clauses_->at(0).is_default() - || this->clauses_->at(1).is_default())) + if (ncases == 2 && has_default) return this->lower_two_case(b); + // We don't allocate an entry in scases for the default case. + if (has_default) + --ncases; + Type* scase_type = Channel_type::select_case_type(); Expression* ncases_expr = Expression::make_integer_ul(ncases, NULL, @@ -5779,7 +5846,10 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function, b->add_statement(recvok); // Initialize the scases array. - this->clauses_->lower(gogo, function, b, scases, recvok); + int send_count; + int recv_count; + this->clauses_->lower(gogo, function, b, scases, recvok, &send_count, + &recv_count); // Build the call to selectgo. Later, in do_get_backend, we will // build a switch on the result that branches to the various cases. @@ -5793,11 +5863,18 @@ Select_statement::do_lower(Gogo* gogo, Named_object* function, order_ref = Expression::make_unary(OPERATOR_AND, order_ref, loc); order_ref = Expression::make_cast(unsafe_pointer_type, order_ref, loc); - Expression* count_expr = Expression::make_integer_ul(ncases, int_type, loc); + Expression* send_count_expr = Expression::make_integer_sl(send_count, + int_type, + loc); + Expression* recv_count_expr = Expression::make_integer_sl(recv_count, + int_type, + loc); + Expression* block_expr = Expression::make_boolean(!has_default, loc); - Call_expression* call = Runtime::make_call(Runtime::SELECTGO, loc, 3, + Call_expression* call = Runtime::make_call(Runtime::SELECTGO, loc, 5, scases_ref, order_ref, - count_expr); + send_count_expr, recv_count_expr, + block_expr); Expression* result = Expression::make_call_result(call, 0); Expression* ref = Expression::make_temporary_reference(this->index_, loc); @@ -6317,7 +6394,7 @@ For_range_statement::do_lower(Gogo* gogo, Named_object*, Block* enclosing, else if (range_type->is_string_type()) { index_type = Type::lookup_integer_type("int"); - value_type = gogo->lookup_global("rune")->type_value(); + value_type = Type::lookup_integer_type("rune"); } else if (range_type->map_type() != NULL) { @@ -6788,7 +6865,7 @@ For_range_statement::lower_range_string(Gogo* gogo, rune_type = value_temp->type(); else { - rune_type = gogo->lookup_global("rune")->type_value(); + rune_type = Type::lookup_integer_type("rune"); value_temp = Statement::make_temporary(rune_type, NULL, loc); init->add_statement(value_temp); } diff --git a/gcc/go/gofrontend/statements.h b/gcc/go/gofrontend/statements.h index 47092b4..c08b493 100644 --- a/gcc/go/gofrontend/statements.h +++ b/gcc/go/gofrontend/statements.h @@ -1092,6 +1092,9 @@ class Select_clauses size() const { return this->clauses_.size(); } + bool + has_default() const; + // Traverse the select clauses. int traverse(Traverse*); @@ -1099,7 +1102,7 @@ class Select_clauses // Lower statements. void lower(Gogo*, Named_object*, Block*, Temporary_statement*, - Temporary_statement*); + Temporary_statement*, int* send_count, int* recv_count); // Determine types. void @@ -1138,8 +1141,9 @@ class Select_clauses Named_object* closedvar, bool is_default, Block* statements, Location location) : channel_(channel), val_(val), closed_(closed), var_(var), - closedvar_(closedvar), statements_(statements), location_(location), - is_send_(is_send), is_default_(is_default), is_lowered_(false) + closedvar_(closedvar), statements_(statements), case_index_(0), + location_(location), is_send_(is_send), is_default_(is_default), + is_lowered_(false), is_case_index_set_(false) { go_assert(is_default ? channel == NULL : channel != NULL); } // Traverse the select clause. @@ -1148,7 +1152,7 @@ class Select_clauses // Lower statements. void - lower(Gogo*, Named_object*, Block*, Temporary_statement*, size_t, + lower(Gogo*, Named_object*, Block*, Temporary_statement*, int, Temporary_statement*); // Determine types. @@ -1210,6 +1214,23 @@ class Select_clauses location() const { return this->location_; } + // Return the case index for this clause. + int + case_index() const + { + go_assert(this->is_case_index_set_); + return this->case_index_; + } + + // Set the case index. + void + set_case_index(int i) + { + go_assert(!this->is_case_index_set_); + this->case_index_ = i; + this->is_case_index_set_ = true; + } + // Whether this clause may fall through to the statement which // follows the overall select statement. bool @@ -1224,17 +1245,6 @@ class Select_clauses dump_clause(Ast_dump_context*) const; private: - // These values must match the values in libgo/go/runtime/select.go. - enum - { - caseRecv = 1, - caseSend = 2, - caseDefault = 3, - }; - - void - lower_default(Block*, Expression*); - void lower_send(Block*, Expression*, Expression*); @@ -1243,7 +1253,7 @@ class Select_clauses Temporary_statement*); void - set_case(Block*, Expression*, Expression*, Expression*, int); + set_case(Block*, Expression*, Expression*, Expression*); // The channel. Expression* channel_; @@ -1259,6 +1269,10 @@ class Select_clauses Named_object* closedvar_; // The statements to execute. Block* statements_; + // The index of this clause in the switch statement. If + // runtime.selectgo returns this index, this clause has been + // chosen. + int case_index_; // The location of this clause. Location location_; // Whether this is a send or a receive. @@ -1267,6 +1281,8 @@ class Select_clauses bool is_default_; // Whether this has been lowered. bool is_lowered_; + // Whether the case index has been set. + bool is_case_index_set_; }; Select_clause& diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index eb9c766..7d4c47f 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -261,6 +261,15 @@ Type::is_error_type() const } } +// Note that this type is an error. This is called by children when +// they discover an error during the verify_types pass. + +void +Type::set_is_error() +{ + this->classification_ = TYPE_ERROR; +} + // If this is a pointer type, return the type to which it points. // Otherwise, return NULL. @@ -1342,19 +1351,21 @@ Type::make_type_descriptor_var(Gogo* gogo) Type* td_type = Type::make_type_descriptor_type(); Btype* td_btype = td_type->get_backend(gogo); - std::string name = gogo->type_descriptor_name(this, nt); - std::string asm_name(go_selectively_encode_id(name)); + Backend_name bname; + gogo->type_descriptor_backend_name(this, nt, &bname); this->type_descriptor_var_ = - gogo->backend()->immutable_struct_reference(name, asm_name, - td_btype, - bloc); + gogo->backend()->immutable_struct_reference(bname.name(), + bname.optional_asm_name(), + td_btype, + bloc); if (phash != NULL) *phash = this->type_descriptor_var_; return; } - std::string var_name = gogo->type_descriptor_name(this, nt); + Backend_name bname; + gogo->type_descriptor_backend_name(this, nt, &bname); // Build the contents of the type descriptor. Expression* initializer = this->do_type_descriptor(gogo, NULL); @@ -1366,11 +1377,11 @@ Type::make_type_descriptor_var(Gogo* gogo) const Package* dummy; if (this->type_descriptor_defined_elsewhere(nt, &dummy)) { - std::string asm_name(go_selectively_encode_id(var_name)); this->type_descriptor_var_ = - gogo->backend()->immutable_struct_reference(var_name, asm_name, - initializer_btype, - loc); + gogo->backend()->immutable_struct_reference(bname.name(), + bname.optional_asm_name(), + initializer_btype, + loc); if (phash != NULL) *phash = this->type_descriptor_var_; return; @@ -1399,10 +1410,10 @@ Type::make_type_descriptor_var(Gogo* gogo) // ensure that type_descriptor_pointer will work if called while // converting INITIALIZER. - std::string asm_name(go_selectively_encode_id(var_name)); this->type_descriptor_var_ = - gogo->backend()->immutable_struct(var_name, asm_name, false, is_common, - initializer_btype, loc); + gogo->backend()->immutable_struct(bname.name(), bname.optional_asm_name(), + false, is_common, initializer_btype, + loc); if (phash != NULL) *phash = this->type_descriptor_var_; @@ -1411,7 +1422,7 @@ Type::make_type_descriptor_var(Gogo* gogo) Bexpression* binitializer = initializer->get_backend(&context); gogo->backend()->immutable_struct_set_init(this->type_descriptor_var_, - var_name, false, is_common, + bname.name(), false, is_common, initializer_btype, loc, binitializer); @@ -1924,19 +1935,20 @@ Type::build_hash_function(Gogo* gogo, int64_t size, Function_type* hash_fntype) return ins.first->second; } - std::string hash_name = gogo->hash_function_name(type); + Backend_name bname; + gogo->hash_function_name(type, &bname); Location bloc = Linemap::predeclared_location(); - Named_object* hash_fn = gogo->declare_package_function(hash_name, + Named_object* hash_fn = gogo->declare_package_function(bname.name(), hash_fntype, bloc); ins.first->second = hash_fn; if (gogo->in_global_scope()) - type->write_hash_function(gogo, size, hash_name, hash_fntype); + type->write_hash_function(gogo, size, &bname, hash_fntype); else - gogo->queue_hash_function(type, size, hash_name, hash_fntype); + gogo->queue_hash_function(type, size, &bname, hash_fntype); return hash_fn; } @@ -1944,8 +1956,7 @@ Type::build_hash_function(Gogo* gogo, int64_t size, Function_type* hash_fntype) // Write the hash function for a type that needs it written specially. void -Type::write_hash_function(Gogo* gogo, int64_t size, - const std::string& hash_name, +Type::write_hash_function(Gogo* gogo, int64_t size, const Backend_name* bname, Function_type* hash_fntype) { Location bloc = Linemap::predeclared_location(); @@ -1958,8 +1969,9 @@ Type::write_hash_function(Gogo* gogo, int64_t size, go_assert(this->is_comparable()); - Named_object* hash_fn = gogo->start_function(hash_name, hash_fntype, false, - bloc); + Named_object* hash_fn = gogo->start_function(bname->name(), hash_fntype, + false, bloc); + hash_fn->func_value()->set_asm_name(bname->asm_name()); hash_fn->func_value()->set_is_type_specific_function(); gogo->start_block(bloc); @@ -2245,7 +2257,8 @@ Type::build_equal_function(Gogo* gogo, Named_type* name, int64_t size, return ins.first->second; } - std::string equal_name = gogo->equal_function_name(this, name); + Backend_name bname; + gogo->equal_function_name(this, name, &bname); Location bloc = Linemap::predeclared_location(); @@ -2255,19 +2268,21 @@ Type::build_equal_function(Gogo* gogo, Named_type* name, int64_t size, Named_object* equal_fn; if (is_defined_elsewhere) - equal_fn = Named_object::make_function_declaration(equal_name, package, + equal_fn = Named_object::make_function_declaration(bname.name(), package, equal_fntype, bloc); else - equal_fn = gogo->declare_package_function(equal_name, equal_fntype, bloc); + equal_fn = gogo->declare_package_function(bname.name(), equal_fntype, bloc); ins.first->second = equal_fn; - if (!is_defined_elsewhere) + if (is_defined_elsewhere) + equal_fn->func_declaration_value()->set_asm_name(bname.asm_name()); + else { if (gogo->in_global_scope()) - this->write_equal_function(gogo, name, size, equal_name, equal_fntype); + this->write_equal_function(gogo, name, size, &bname, equal_fntype); else - gogo->queue_equal_function(this, name, size, equal_name, equal_fntype); + gogo->queue_equal_function(this, name, size, &bname, equal_fntype); } return equal_fn; @@ -2278,7 +2293,7 @@ Type::build_equal_function(Gogo* gogo, Named_type* name, int64_t size, void Type::write_equal_function(Gogo* gogo, Named_type* name, int64_t size, - const std::string& equal_name, + const Backend_name* bname, Function_type* equal_fntype) { Location bloc = Linemap::predeclared_location(); @@ -2291,8 +2306,9 @@ Type::write_equal_function(Gogo* gogo, Named_type* name, int64_t size, go_assert(this->is_comparable()); - Named_object* equal_fn = gogo->start_function(equal_name, equal_fntype, + Named_object* equal_fn = gogo->start_function(bname->name(), equal_fntype, false, bloc); + equal_fn->func_value()->set_asm_name(bname->asm_name()); equal_fn->func_value()->set_is_type_specific_function(); gogo->start_block(bloc); @@ -2671,9 +2687,8 @@ Type::make_gc_symbol_var(Gogo* gogo) const Package* dummy; if (this->type_descriptor_defined_elsewhere(nt, &dummy)) { - std::string asm_name(go_selectively_encode_id(sym_name)); this->gc_symbol_var_ = - gogo->backend()->implicit_variable_reference(sym_name, asm_name, + gogo->backend()->implicit_variable_reference(sym_name, "", sym_btype); if (phash != NULL) *phash = this->gc_symbol_var_; @@ -2699,10 +2714,9 @@ Type::make_gc_symbol_var(Gogo* gogo) // Since we are building the GC symbol in this package, we must create the // variable before converting the initializer to its backend representation // because the initializer may refer to the GC symbol for this type. - std::string asm_name(go_selectively_encode_id(sym_name)); this->gc_symbol_var_ = - gogo->backend()->implicit_variable(sym_name, asm_name, - sym_btype, false, true, is_common, 0); + gogo->backend()->implicit_variable(sym_name, "", sym_btype, false, true, + is_common, 0); if (phash != NULL) *phash = this->gc_symbol_var_; @@ -2750,7 +2764,7 @@ class Ptrmask symname() const; Expression* - constructor(Gogo* gogo) const; + constructor() const; private: void @@ -2876,14 +2890,17 @@ Ptrmask::set_from(Gogo* gogo, Type* type, int64_t ptrsize, int64_t offset) } } -// Return a symbol name for this ptrmask. This is used to coalesce identical -// ptrmasks, which are common. The symbol name must use only characters that are -// valid in symbols. It's nice if it's short. For smaller ptrmasks, we convert -// it to a string that uses only 32 characters, avoiding digits and u and U. For -// longer pointer masks, apply the same process to the SHA1 digest of the bits, -// so as to avoid pathologically long symbol names (see related Go issues #32083 -// and #11583 for more on this). To avoid collisions between the two encoding -// schemes, use a prefix ("X") for the SHA form to disambiguate. +// Return a symbol name for this ptrmask. This is used to coalesce +// identical ptrmasks, which are common. The symbol name must use +// only characters that are valid in symbols. It's nice if it's +// short. For smaller ptrmasks, we convert it to a string that uses +// only 32 characters. For longer pointer masks, apply the same +// process to the SHA1 digest of the bits, so as to avoid +// pathologically long symbol names (see related Go issues #32083 and +// #11583 for more on this). To avoid collisions between the two +// encoding schemes, use a prefix ("X") for the SHA form to +// disambiguate. + std::string Ptrmask::symname() const { @@ -2911,7 +2928,7 @@ Ptrmask::symname() const bits = &shabits; } - const char chars[33] = "abcdefghijklmnopqrstvwxyzABCDEFG"; + const char chars[33] = "abcdefghijklmnopqrstuvwxyzABCDEF"; go_assert(chars[32] == '\0'); std::string ret(prefix); unsigned int b = 0; @@ -2942,10 +2959,10 @@ Ptrmask::symname() const // initialize the runtime ptrmask value. Expression* -Ptrmask::constructor(Gogo* gogo) const +Ptrmask::constructor() const { Location bloc = Linemap::predeclared_location(); - Type* byte_type = gogo->lookup_global("byte")->type_value(); + Type* byte_type = Type::lookup_integer_type("byte"); Expression* len = Expression::make_integer_ul(this->bits_.size(), NULL, bloc); Array_type* at = Type::make_array_type(byte_type, len); @@ -2990,14 +3007,13 @@ Type::gc_ptrmask_var(Gogo* gogo, int64_t ptrsize, int64_t ptrdata) return ins.first->second; } - Expression* val = ptrmask.constructor(gogo); + Expression* val = ptrmask.constructor(); Translate_context context(gogo, NULL, NULL, NULL); context.set_is_const(); Bexpression* bval = val->get_backend(&context); - std::string asm_name(go_selectively_encode_id(sym_name)); Btype *btype = val->type()->get_backend(gogo); - Bvariable* ret = gogo->backend()->implicit_variable(sym_name, asm_name, + Bvariable* ret = gogo->backend()->implicit_variable(sym_name, "", btype, false, true, true, 0); gogo->backend()->implicit_variable_set_init(ret, sym_name, btype, false, @@ -3030,7 +3046,7 @@ class GCProg end(); Expression* - constructor(Gogo* gogo) const; + constructor() const; private: void @@ -3341,7 +3357,7 @@ GCProg::end() // Return an Expression for the bytes in a GC program. Expression* -GCProg::constructor(Gogo* gogo) const +GCProg::constructor() const { Location bloc = Linemap::predeclared_location(); @@ -3351,7 +3367,7 @@ GCProg::constructor(Gogo* gogo) const Type* uint32_type = Type::lookup_integer_type("uint32"); - Type* byte_type = gogo->lookup_global("byte")->type_value(); + Type* byte_type = Type::lookup_integer_type("byte"); Expression* len = Expression::make_integer_ul(this->bytes_.size(), NULL, bloc); Array_type* at = Type::make_array_type(byte_type, len); @@ -3398,7 +3414,7 @@ Type::gcprog_constructor(Gogo* gogo, int64_t ptrsize, int64_t ptrdata) go_assert(offset >= ptrdata && offset <= type_size); - return prog.constructor(gogo); + return prog.constructor(); } // Return a composite literal for the uncommon type information for @@ -4125,6 +4141,23 @@ Integer_type::create_abstract_character_type() return abstract_type; } +// Create an alias to an integer type. This is used for byte and rune. + +Named_type* +Integer_type::create_integer_type_alias(const char* name, + Named_type* real_type) +{ + std::string sname(name); + Named_object* no = Named_object::make_type(sname, NULL, real_type, + Linemap::predeclared_location()); + Named_type* nt = no->type_value(); + nt->set_is_alias(); + std::pair<Named_integer_types::iterator, bool> ins = + Integer_type::named_integer_types.insert(std::make_pair(sname, nt)); + go_assert(ins.second); + return nt; +} + // Integer type compatibility. bool @@ -4202,6 +4235,14 @@ Type::make_abstract_character_type() return Integer_type::create_abstract_character_type(); } +// Make an integer type alias. + +Named_type* +Type::make_integer_type_alias(const char* name, Named_type* real_type) +{ + return Integer_type::create_integer_type_alias(name, real_type); +} + // Look up an integer type. Named_type* @@ -4450,7 +4491,7 @@ String_type::do_get_backend(Gogo* gogo) { std::vector<Backend::Btyped_identifier> fields(2); - Type* b = gogo->lookup_global("byte")->type_value(); + Type* b = Type::lookup_integer_type("byte"); Type* pb = Type::make_pointer_type(b); // We aren't going to get back to this field to finish the @@ -4561,7 +4602,7 @@ class Sink_type : public Type { go_unreachable(); } void - do_mangled_name(Gogo*, std::string*) const + do_mangled_name(Gogo*, std::string*, bool*) const { go_unreachable(); } }; @@ -5671,7 +5712,7 @@ class Call_multiple_result_type : public Type { go_assert(saw_errors()); } void - do_mangled_name(Gogo*, std::string*) const + do_mangled_name(Gogo*, std::string*, bool*) const { go_assert(saw_errors()); } private: @@ -5864,6 +5905,7 @@ Struct_type::do_verify() { go_error_at(p->location(), "embedded type may not be a pointer"); p->set_type(Type::make_error_type()); + this->set_is_error(); } else if (t->points_to() != NULL && t->points_to()->interface_type() != NULL) @@ -5871,6 +5913,7 @@ Struct_type::do_verify() go_error_at(p->location(), "embedded type may not be pointer to interface"); p->set_type(Type::make_error_type()); + this->set_is_error(); } } } @@ -6048,7 +6091,7 @@ Struct_type::do_hash_might_panic() // Return whether this struct type is permitted to be in the heap. bool -Struct_type::do_in_heap() +Struct_type::do_in_heap() const { const Struct_field_list* fields = this->fields_; if (fields == NULL) @@ -7229,6 +7272,13 @@ Array_type::verify_length() Type_context context(Type::lookup_integer_type("int"), false); this->length_->determine_type(&context); + if (this->length_->is_error_expression() + || this->length_->type()->is_error()) + { + go_assert(saw_errors()); + return false; + } + if (!this->length_->is_constant()) { go_error_at(this->length_->location(), "array bound is not constant"); @@ -7303,7 +7353,10 @@ Array_type::do_verify() if (this->element_type()->is_error_type()) return false; if (!this->verify_length()) - this->length_ = Expression::make_error(this->length_->location()); + { + this->length_ = Expression::make_error(this->length_->location()); + this->set_is_error(); + } return true; } @@ -8092,11 +8145,9 @@ Map_type::backend_zero_value(Gogo* gogo) Btype* barray_type = gogo->backend()->array_type(buint8_type, blength); std::string zname = Map_type::zero_value->name(); - std::string asm_name(go_selectively_encode_id(zname)); Bvariable* zvar = - gogo->backend()->implicit_variable(zname, asm_name, - barray_type, false, false, true, - Map_type::zero_value_align); + gogo->backend()->implicit_variable(zname, "", barray_type, false, false, + true, Map_type::zero_value_align); gogo->backend()->implicit_variable_set_init(zvar, zname, barray_type, false, false, true, NULL); return zvar; @@ -8120,11 +8171,20 @@ Map_type::do_verify() { // The runtime support uses "map[void]void". if (!this->key_type_->is_comparable() && !this->key_type_->is_void_type()) - go_error_at(this->location_, "invalid map key type"); + { + go_error_at(this->location_, "invalid map key type"); + this->set_is_error(); + } if (!this->key_type_->in_heap()) - go_error_at(this->location_, "go:notinheap map key not allowed"); + { + go_error_at(this->location_, "go:notinheap map key not allowed"); + this->set_is_error(); + } if (!this->val_type_->in_heap()) - go_error_at(this->location_, "go:notinheap map value not allowed"); + { + go_error_at(this->location_, "go:notinheap map value not allowed"); + this->set_is_error(); + } return true; } @@ -8655,8 +8715,11 @@ Channel_type::do_verify() // We have no location for this error, but this is not something the // ordinary user will see. if (!this->element_type_->in_heap()) - go_error_at(Linemap::unknown_location(), - "chan of go:notinheap type not allowed"); + { + go_error_at(Linemap::unknown_location(), + "chan of go:notinheap type not allowed"); + this->set_is_error(); + } return true; } @@ -8782,7 +8845,22 @@ Channel_type::do_reflection(Gogo* gogo, std::string* ret) const if (!this->may_receive_) ret->append("<-"); ret->push_back(' '); + + bool need_paren = false; + if (this->may_send_ + && this->may_receive_ + && this->element_type_->channel_type() != NULL + && this->element_type_->unalias()->named_type() == NULL + && !this->element_type_->channel_type()->may_send()) + { + ret->push_back('('); + need_paren = true; + } + this->append_reflection(this->element_type_, gogo, ret); + + if (need_paren) + ret->push_back(')'); } // Export. @@ -8842,14 +8920,10 @@ Channel_type::select_case_type() { Type* unsafe_pointer_type = Type::make_pointer_type(Type::make_void_type()); - Type* uint16_type = Type::lookup_integer_type("uint16"); - Type* int64_type = Type::lookup_integer_type("int64"); scase_type = - Type::make_builtin_struct_type(4, + Type::make_builtin_struct_type(2, "c", unsafe_pointer_type, - "elem", unsafe_pointer_type, - "kind", uint16_type, - "releasetime", int64_type); + "elem", unsafe_pointer_type); scase_type->set_is_struct_incomparable(); } return scase_type; @@ -8921,8 +8995,11 @@ Interface_type::finalize_methods() else if (this->find_method(p->name()) == NULL) this->all_methods_->push_back(*p); else - go_error_at(p->location(), "duplicate method %qs", - Gogo::message_name(p->name()).c_str()); + { + go_error_at(p->location(), "duplicate method %qs", + Gogo::message_name(p->name()).c_str()); + this->set_is_error(); + } } std::vector<Named_type*> seen; @@ -8938,7 +9015,10 @@ Interface_type::finalize_methods() if (it == NULL) { if (!t->is_error()) - go_error_at(tl, "interface contains embedded non-interface"); + { + go_error_at(tl, "interface contains embedded non-interface"); + this->set_is_error(); + } continue; } if (it == this) @@ -8946,6 +9026,7 @@ Interface_type::finalize_methods() if (!issued_recursive_error) { go_error_at(tl, "invalid recursive interface"); + this->set_is_error(); issued_recursive_error = true; } continue; @@ -8964,6 +9045,7 @@ Interface_type::finalize_methods() if (*q == nt) { go_error_at(tl, "inherited interface loop"); + this->set_is_error(); break; } } @@ -8986,8 +9068,11 @@ Interface_type::finalize_methods() q->type(), tl)); else if (!Type::are_identical(q->type(), oldm->type(), Type::COMPARE_TAGS, NULL)) - go_error_at(tl, "duplicate method %qs", - Gogo::message_name(q->name()).c_str()); + { + go_error_at(tl, "duplicate method %qs", + Gogo::message_name(q->name()).c_str()); + this->set_is_error(); + } } } @@ -12014,6 +12099,15 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr, ambig2.c_str()); else if (found_pointer_method) go_error_at(location, "method requires a pointer receiver"); + else if (it != NULL && it->is_empty()) + go_error_at(location, + "reference to method %qs in interface with no methods", + Gogo::message_name(name).c_str()); + else if (it == NULL && type->deref()->interface_type() != NULL) + go_error_at(location, + ("reference to method %qs in type that is " + "pointer to interface, not interface"), + Gogo::message_name(name).c_str()); else if (nt == NULL && st == NULL && it == NULL) go_error_at(location, ("reference to field %qs in object which " diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index ef81589..f2880f9 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -49,6 +49,7 @@ class Function; class Translate_context; class Export; class Import; +class Backend_name; class Btype; class Bexpression; class Bvariable; @@ -461,6 +462,10 @@ class Type make_integer_type(const char* name, bool is_unsigned, int bits, int runtime_type_kind); + // Make a named integer type alias. This is used for byte and rune. + static Named_type* + make_integer_type_alias(const char* name, Named_type* real_type); + // Look up a named integer type. static Named_type* lookup_integer_type(const char* name); @@ -667,7 +672,7 @@ class Type // Whether the type is permitted in the heap. bool - in_heap() + in_heap() const { return this->do_in_heap(); } // Return a hash code for this type for the method hash table. @@ -1008,11 +1013,11 @@ class Type std::string reflection(Gogo*) const; - // Return a mangled name for the type. This is a name which can be - // used in assembler code. Identical types should have the same - // manged name. - std::string - mangled_name(Gogo*) const; + // Add the backend name for the type to BNAME. This will add one or + // two name components. Identical types should have the same + // backend name. + void + backend_name(Gogo*, Backend_name* bname) const; // If the size of the type can be determined, set *PSIZE to the size // in bytes and return true. Otherwise, return false. This queries @@ -1066,12 +1071,11 @@ class Type // Write the equal function for a type. void write_equal_function(Gogo*, Named_type*, int64_t size, - const std::string& equal_name, - Function_type* equal_fntype); + const Backend_name*, Function_type* equal_fntype); // Write the hash function for a type. void - write_hash_function(Gogo*, int64_t size, const std::string& hash_name, + write_hash_function(Gogo*, int64_t size, const Backend_name*, Function_type* hash_fntype); // Return the alignment required by the memequalN function. @@ -1120,7 +1124,7 @@ class Type { return false; } virtual bool - do_in_heap() + do_in_heap() const { return true; } virtual unsigned int @@ -1136,11 +1140,15 @@ class Type do_reflection(Gogo*, std::string*) const = 0; virtual void - do_mangled_name(Gogo*, std::string*) const = 0; + do_mangled_name(Gogo*, std::string*, bool*) const = 0; virtual void do_export(Export*) const; + // For children to call when they detect that they are in error. + void + set_is_error(); + // Return whether a method expects a pointer as the receiver. static bool method_expects_pointer(const Named_object*); @@ -1194,8 +1202,9 @@ class Type // For the benefit of child class mangling. void - append_mangled_name(const Type* type, Gogo* gogo, std::string* ret) const - { type->do_mangled_name(gogo, ret); } + append_mangled_name(const Type* type, Gogo* gogo, std::string* ret, + bool *is_non_identifier) const + { type->do_mangled_name(gogo, ret, is_non_identifier); } // Return the backend representation for the underlying type of a // named type. @@ -1426,8 +1435,6 @@ class Type // The GC symbol for this type. This starts out as NULL and // is filled in as needed. Bvariable* gc_symbol_var_; - // Whether this type can appear in the heap. - bool in_heap_; }; // Type hash table operations, treating aliases as identical to the @@ -1658,7 +1665,7 @@ class Error_type : public Type do_reflection(Gogo*, std::string*) const; void - do_mangled_name(Gogo*, std::string* ret) const; + do_mangled_name(Gogo*, std::string*, bool*) const; }; // The void type. @@ -1687,7 +1694,7 @@ class Void_type : public Type { } void - do_mangled_name(Gogo*, std::string* ret) const; + do_mangled_name(Gogo*, std::string*, bool*) const; }; // The boolean type. @@ -1716,7 +1723,7 @@ class Boolean_type : public Type { ret->append("bool"); } void - do_mangled_name(Gogo*, std::string* ret) const; + do_mangled_name(Gogo*, std::string*, bool*) const; }; // The type of an integer. @@ -1741,6 +1748,10 @@ class Integer_type : public Type static Integer_type* create_abstract_character_type(); + // Create an alias to an integer type. + static Named_type* + create_integer_type_alias(const char* name, Named_type* real_type); + // Whether this is an abstract integer type. bool is_abstract() const @@ -1798,7 +1809,7 @@ protected: do_reflection(Gogo*, std::string*) const; void - do_mangled_name(Gogo*, std::string*) const; + do_mangled_name(Gogo*, std::string*, bool*) const; private: Integer_type(bool is_abstract, bool is_unsigned, int bits, @@ -1884,7 +1895,7 @@ class Float_type : public Type do_reflection(Gogo*, std::string*) const; void - do_mangled_name(Gogo*, std::string*) const; + do_mangled_name(Gogo*, std::string*, bool*) const; private: Float_type(bool is_abstract, int bits, int runtime_type_kind) @@ -1962,7 +1973,7 @@ class Complex_type : public Type do_reflection(Gogo*, std::string*) const; void - do_mangled_name(Gogo*, std::string*) const; + do_mangled_name(Gogo*, std::string*, bool*) const; private: Complex_type(bool is_abstract, int bits, int runtime_type_kind) @@ -2016,7 +2027,7 @@ class String_type : public Type do_reflection(Gogo*, std::string*) const; void - do_mangled_name(Gogo*, std::string* ret) const; + do_mangled_name(Gogo*, std::string*, bool*) const; private: // The named string type. @@ -2176,7 +2187,7 @@ class Function_type : public Type do_reflection(Gogo*, std::string*) const; void - do_mangled_name(Gogo*, std::string*) const; + do_mangled_name(Gogo*, std::string*, bool*) const; void do_export(Export*) const; @@ -2305,7 +2316,7 @@ class Pointer_type : public Type do_reflection(Gogo*, std::string*) const; void - do_mangled_name(Gogo*, std::string*) const; + do_mangled_name(Gogo*, std::string*, bool*) const; void do_export(Export*) const; @@ -2343,7 +2354,7 @@ class Nil_type : public Type { go_unreachable(); } void - do_mangled_name(Gogo*, std::string* ret) const; + do_mangled_name(Gogo*, std::string*, bool*) const; }; // The type of a field in a struct. @@ -2662,7 +2673,7 @@ class Struct_type : public Type do_hash_might_panic(); bool - do_in_heap(); + do_in_heap() const; unsigned int do_hash_for_method(Gogo*, int) const; @@ -2677,7 +2688,7 @@ class Struct_type : public Type do_reflection(Gogo*, std::string*) const; void - do_mangled_name(Gogo*, std::string*) const; + do_mangled_name(Gogo*, std::string*, bool*) const; void do_export(Export*) const; @@ -2844,7 +2855,7 @@ class Array_type : public Type { return this->length_ != NULL && this->element_type_->hash_might_panic(); } bool - do_in_heap() + do_in_heap() const { return this->length_ == NULL || this->element_type_->in_heap(); } unsigned int @@ -2860,7 +2871,7 @@ class Array_type : public Type do_reflection(Gogo*, std::string*) const; void - do_mangled_name(Gogo*, std::string*) const; + do_mangled_name(Gogo*, std::string*, bool*) const; void do_export(Export*) const; @@ -2998,7 +3009,7 @@ class Map_type : public Type do_reflection(Gogo*, std::string*) const; void - do_mangled_name(Gogo*, std::string*) const; + do_mangled_name(Gogo*, std::string*, bool*) const; void do_export(Export*) const; @@ -3112,7 +3123,7 @@ class Channel_type : public Type do_reflection(Gogo*, std::string*) const; void - do_mangled_name(Gogo*, std::string*) const; + do_mangled_name(Gogo*, std::string*, bool*) const; void do_export(Export*) const; @@ -3288,7 +3299,7 @@ class Interface_type : public Type do_reflection(Gogo*, std::string*) const; void - do_mangled_name(Gogo*, std::string*) const; + do_mangled_name(Gogo*, std::string*, bool*) const; void do_export(Export*) const; @@ -3559,10 +3570,11 @@ class Named_type : public Type void append_reflection_type_name(Gogo*, bool use_alias, std::string*) const; - // Append the mangled type name as for Type::append_mangled_name, + // Append the symbol type name as for Type::append_mangled_name, // but if USE_ALIAS use the alias name rather than the alias target. void - append_mangled_type_name(Gogo*, bool use_alias, std::string*) const; + append_symbol_type_name(Gogo*, bool use_alias, std::string*, + bool* is_non_identifier) const; // Import a named type. static void @@ -3593,7 +3605,7 @@ class Named_type : public Type do_needs_key_update(); bool - do_in_heap() + do_in_heap() const { return this->in_heap_ && this->type_->in_heap(); } unsigned int @@ -3609,7 +3621,7 @@ class Named_type : public Type do_reflection(Gogo*, std::string*) const; void - do_mangled_name(Gogo*, std::string* ret) const; + do_mangled_name(Gogo*, std::string*, bool*) const; void do_export(Export*) const; @@ -3756,7 +3768,7 @@ class Forward_declaration_type : public Type { return this->real_type()->needs_key_update(); } bool - do_in_heap() + do_in_heap() const { return this->real_type()->in_heap(); } unsigned int @@ -3773,7 +3785,7 @@ class Forward_declaration_type : public Type do_reflection(Gogo*, std::string*) const; void - do_mangled_name(Gogo*, std::string* ret) const; + do_mangled_name(Gogo*, std::string*, bool*) const; void do_export(Export*) const; diff --git a/gcc/go/gofrontend/wb.cc b/gcc/go/gofrontend/wb.cc index 1eadb3e..ac1f0a1 100644 --- a/gcc/go/gofrontend/wb.cc +++ b/gcc/go/gofrontend/wb.cc @@ -683,8 +683,9 @@ Gogo::write_barrier_variable() Location bloc = Linemap::predeclared_location(); Type* bool_type = Type::lookup_bool_type(); - Array_type* pad_type = Type::make_array_type(this->lookup_global("byte")->type_value(), - Expression::make_integer_ul(3, NULL, bloc)); + Array_type* pad_type = + Type::make_array_type(Type::lookup_integer_type("byte"), + Expression::make_integer_ul(3, NULL, bloc)); Type* uint64_type = Type::lookup_integer_type("uint64"); Type* wb_type = Type::make_builtin_struct_type(5, "enabled", bool_type, |