diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog index 83138d35c28..3918fa814d7 100644 --- a/gcc/go/ChangeLog +++ b/gcc/go/ChangeLog @@ -1,3 +1,7 @@ +2017-10-05 Ian Lance Taylor + + * Make-lang.in (GO_OBJS): Add go/names.o. + 2017-08-30 Richard Sandiford Alan Hayward David Sherwood diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in index b65d347f93a..60fecad0c8f 100644 --- a/gcc/go/Make-lang.in +++ b/gcc/go/Make-lang.in @@ -68,6 +68,7 @@ GO_OBJS = \ go/import.o \ go/import-archive.o \ go/lex.o \ + go/names.o \ go/parse.o \ go/runtime.o \ go/statements.o \ diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE index 07cde8979cc..3e33c626cc8 100644 --- a/gcc/go/gofrontend/MERGE +++ b/gcc/go/gofrontend/MERGE @@ -1,4 +1,4 @@ -5989ef1cd0add98f107839759a5bc57f34354d39 +048914caa26b34eebabd0423ed48ee3ac34c919c 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/escape.cc b/gcc/go/gofrontend/escape.cc index a90c527a361..dea21188c92 100644 --- a/gcc/go/gofrontend/escape.cc +++ b/gcc/go/gofrontend/escape.cc @@ -575,7 +575,7 @@ debug_function_name(Named_object* fn) // Extract #. std::string name = Gogo::unpack_hidden_name(fn->name()); - int closure_num = (int)strtol(name.substr(6).c_str(), NULL, 0); + int closure_num = Gogo::nested_function_num(fn->name()); closure_num++; name = Gogo::unpack_hidden_name(enclosing->name()); diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 88162327b5f..8337cbeb602 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -1299,28 +1299,12 @@ Func_descriptor_expression::do_get_backend(Translate_context* context) return context->backend()->var_expression(this->dvar_, VE_rvalue, loc); Gogo* gogo = context->gogo(); - std::string var_name; + std::string var_name(gogo->function_descriptor_name(no)); bool is_descriptor = false; if (no->is_function_declaration() && !no->func_declaration_value()->asm_name().empty() && Linemap::is_predeclared_location(no->location())) - { - if (no->func_declaration_value()->asm_name().substr(0, 8) != "runtime.") - var_name = no->func_declaration_value()->asm_name() + "_descriptor"; - else - var_name = no->func_declaration_value()->asm_name() + "$descriptor"; - is_descriptor = true; - } - else - { - if (no->package() == NULL) - var_name = gogo->pkgpath_symbol(); - else - var_name = no->package()->pkgpath_symbol(); - var_name.push_back('.'); - var_name.append(Gogo::unpack_hidden_name(no->name())); - var_name.append("$descriptor"); - } + is_descriptor = true; Btype* btype = this->type()->get_backend(gogo); @@ -4348,27 +4332,23 @@ Unary_expression::do_get_backend(Translate_context* context) } } - static unsigned int counter; - char buf[100]; if (this->is_gc_root_ || this->is_slice_init_) { + std::string var_name; bool copy_to_heap = false; if (this->is_gc_root_) { // Build a decl for a GC root variable. GC roots are mutable, so // they cannot be represented as an immutable_struct in the // backend. - static unsigned int root_counter; - snprintf(buf, sizeof buf, "gc%u", root_counter); - ++root_counter; + var_name = gogo->gc_root_name(); } else { // Build a decl for a slice value initializer. An immutable slice // value initializer may have to be copied to the heap if it // contains pointers in a non-constant context. - snprintf(buf, sizeof buf, "C%u", counter); - ++counter; + var_name = gogo->initializer_name(); Array_type* at = this->expr_->type()->array_type(); go_assert(at != NULL); @@ -4379,12 +4359,12 @@ Unary_expression::do_get_backend(Translate_context* context) // read-only, because the program is permitted to change it. copy_to_heap = context->function() != NULL; } - std::string asm_name(go_selectively_encode_id(buf)); + std::string asm_name(go_selectively_encode_id(var_name)); Bvariable* implicit = - gogo->backend()->implicit_variable(buf, asm_name, + gogo->backend()->implicit_variable(var_name, asm_name, btype, true, copy_to_heap, false, 0); - gogo->backend()->implicit_variable_set_init(implicit, buf, btype, + gogo->backend()->implicit_variable_set_init(implicit, var_name, btype, true, copy_to_heap, false, bexpr); bexpr = gogo->backend()->var_expression(implicit, VE_rvalue, loc); @@ -4407,16 +4387,13 @@ Unary_expression::do_get_backend(Translate_context* context) || this->expr_->string_expression() != NULL) && this->expr_->is_static_initializer()) { - // Build a decl for a constant constructor. - snprintf(buf, sizeof buf, "C%u", counter); - ++counter; - - std::string asm_name(go_selectively_encode_id(buf)); + std::string var_name(gogo->initializer_name()); + std::string asm_name(go_selectively_encode_id(var_name)); Bvariable* decl = - gogo->backend()->immutable_struct(buf, asm_name, + gogo->backend()->immutable_struct(var_name, asm_name, true, false, btype, loc); - gogo->backend()->immutable_struct_set_init(decl, buf, true, false, - btype, loc, bexpr); + gogo->backend()->immutable_struct_set_init(decl, var_name, true, + false, btype, loc, bexpr); bexpr = gogo->backend()->var_expression(decl, VE_rvalue, loc); } @@ -15403,10 +15380,9 @@ Interface_mtable_expression::do_get_backend(Translate_context* context) const Typed_identifier_list* interface_methods = this->itype_->methods(); go_assert(!interface_methods->empty()); - std::string mangled_name = ((this->is_pointer_ ? "__go_pimt__" : "__go_imt_") - + this->itype_->mangled_name(gogo) - + "__" - + this->type_->mangled_name(gogo)); + std::string mangled_name = + gogo->interface_method_table_name(this->itype_, this->type_, + this->is_pointer_); // Set is_public if we are converting a named type to an interface // type that is defined in the same package as the named type, and diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index adc8e8a2363..da8f3c584eb 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -868,32 +868,6 @@ Gogo::register_gc_vars(const std::vector& var_gc, init_stmts.push_back(this->backend()->expression_statement(init_bfn, bcall)); } -// Get the name to use for the import control function. If there is a -// global function or variable, then we know that that name must be -// unique in the link, and we use it as the basis for our name. - -const std::string& -Gogo::get_init_fn_name() -{ - if (this->init_fn_name_.empty()) - { - go_assert(this->package_ != NULL); - if (this->is_main_package()) - { - // Use a name which the runtime knows. - this->init_fn_name_ = "__go_init_main"; - } - else - { - std::string s = this->pkgpath_symbol(); - s.append("..import"); - this->init_fn_name_ = s; - } - } - - return this->init_fn_name_; -} - // Build the decl for the initialization function. Named_object* @@ -1774,11 +1748,7 @@ Gogo::start_function(const std::string& name, Function_type* type, "func init must have no arguments and no return values"); // There can be multiple "init" functions, so give them each a // different name. - static int init_count; - char buf[30]; - snprintf(buf, sizeof buf, ".$init%d", init_count); - ++init_count; - nested_name = buf; + nested_name = this->init_function_name(); pname = &nested_name; is_init = true; } @@ -1787,22 +1757,15 @@ Gogo::start_function(const std::string& name, Function_type* type, else { // Invent a name for a nested function. - static int nested_count; - char buf[30]; - snprintf(buf, sizeof buf, ".$nested%d", nested_count); - ++nested_count; - nested_name = buf; + nested_name = this->nested_function_name(); pname = &nested_name; } Named_object* ret; if (Gogo::is_sink_name(*pname)) { - static int sink_count; - char buf[30]; - snprintf(buf, sizeof buf, ".$sink%d", sink_count); - ++sink_count; - ret = Named_object::make_function(buf, NULL, function); + std::string sname(this->sink_function_name()); + ret = Named_object::make_function(sname, NULL, function); ret->func_value()->set_is_sink(); if (!type->is_method()) @@ -1845,11 +1808,8 @@ Gogo::start_function(const std::string& name, Function_type* type, { // Redefinition error. Invent a name to avoid knockon // errors. - static int redefinition_count; - char buf[30]; - snprintf(buf, sizeof buf, ".$redefined%d", redefinition_count); - ++redefinition_count; - ret = this->package_->bindings()->add_function(buf, NULL, function); + std::string rname(this->redefined_function_name()); + ret = this->package_->bindings()->add_function(rname, NULL, function); } } else @@ -2274,47 +2234,6 @@ Gogo::record_interface_type(Interface_type* itype) this->interface_types_.push_back(itype); } -// Return an erroneous name that indicates that an error has already -// been reported. - -std::string -Gogo::erroneous_name() -{ - static int erroneous_count; - char name[50]; - snprintf(name, sizeof name, "$erroneous%d", erroneous_count); - ++erroneous_count; - return name; -} - -// Return whether a name is an erroneous name. - -bool -Gogo::is_erroneous_name(const std::string& name) -{ - return name.compare(0, 10, "$erroneous") == 0; -} - -// Return a name for a thunk object. - -std::string -Gogo::thunk_name() -{ - static int thunk_count; - char thunk_name[50]; - snprintf(thunk_name, sizeof thunk_name, "$thunk%d", thunk_count); - ++thunk_count; - return thunk_name; -} - -// Return whether a function is a thunk. - -bool -Gogo::is_thunk(const Named_object* no) -{ - return no->name().compare(0, 6, "$thunk") == 0; -} - // Define the global names. We do this only after parsing all the // input files, because the program might define the global names // itself. @@ -4195,10 +4114,10 @@ Build_recover_thunks::function(Named_object* orig_no) if (orig_fntype->is_varargs()) new_fntype->set_is_varargs(); - std::string name = orig_no->name(); + Type* rtype = NULL; if (orig_fntype->is_method()) - name += "$" + orig_fntype->receiver()->type()->mangled_name(gogo); - name += "$recover"; + rtype = orig_fntype->receiver()->type(); + std::string name(gogo->recover_thunk_name(orig_no->name(), rtype)); Named_object *new_no = gogo->start_function(name, new_fntype, false, location); Function *new_func = new_no->func_value(); @@ -5449,29 +5368,10 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no) { if (!this->is_unnamed_type_stub_method_) is_visible = true; - std::string pkgpath = gogo->pkgpath_symbol(); - if (this->type_->is_method() - && Gogo::is_hidden_name(no->name()) - && Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath()) - { - // This is a method we created for an unexported - // method of an imported embedded type. We need to - // use the pkgpath of the imported package to avoid - // a possible name collision. See bug478 for a test - // case. - std::string p = Gogo::hidden_name_pkgpath(no->name()); - pkgpath = gogo->pkgpath_symbol_for_package(p); - } - - asm_name = pkgpath; - asm_name.append(1, '.'); - asm_name.append(Gogo::unpack_hidden_name(no->name())); - if (this->type_->is_method()) - { - asm_name.append(1, '.'); - Type* rtype = this->type_->receiver()->type(); - asm_name.append(rtype->mangled_name(gogo)); - } + Type* rtype = NULL; + if (this->type_->is_method()) + rtype = this->type_->receiver()->type(); + asm_name = gogo->function_asm_name(no->name(), NULL, rtype); } if (!this->asm_name_.empty()) @@ -5510,8 +5410,8 @@ Function::get_or_make_decl(Gogo* gogo, Named_object* no) disable_split_stack = true; // Encode name if asm_name not already set at this point - if (asm_name.empty() && go_id_needs_encoding(no->get_id(gogo))) - asm_name = go_encode_id(no->get_id(gogo)); + if (asm_name.empty()) + asm_name = gogo->unexported_function_asm_name(no->name()); // This should go into a unique section if that has been // requested elsewhere, or if this is a nointerface function. @@ -5553,30 +5453,12 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no) std::string asm_name; if (this->asm_name_.empty()) - { - asm_name = (no->package() == NULL - ? gogo->pkgpath_symbol() - : no->package()->pkgpath_symbol()); - if (this->fntype_->is_method() - && Gogo::is_hidden_name(no->name()) - && Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath()) - { - // This is a method created for an unexported method of - // an imported embedded type. Use the pkgpath of the - // imported package. This matches code in - // Function::get_or_make_decl, above. - std::string p = Gogo::hidden_name_pkgpath(no->name()); - asm_name = gogo->pkgpath_symbol_for_package(p); - } - asm_name.append(1, '.'); - asm_name.append(Gogo::unpack_hidden_name(no->name())); - if (this->fntype_->is_method()) - { - asm_name.append(1, '.'); - Type* rtype = this->fntype_->receiver()->type(); - asm_name.append(rtype->mangled_name(gogo)); - } - } + { + 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)); @@ -6815,18 +6697,8 @@ Variable::get_backend_variable(Gogo* gogo, Named_object* function, : gogo->package_name()); var_name.push_back('.'); var_name.append(n); - std::string asm_name; - if (Gogo::is_hidden_name(name)) - asm_name = var_name; - else - { - asm_name = package != NULL - ? package->pkgpath_symbol() - : gogo->pkgpath_symbol(); - asm_name.push_back('.'); - asm_name.append(n); - } - asm_name = go_encode_id(asm_name); + + std::string asm_name(gogo->global_var_asm_name(name, package)); bool is_hidden = Gogo::is_hidden_name(name); // Hack to export runtime.writeBarrier. FIXME. @@ -7416,23 +7288,18 @@ 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()); + 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 if (this->is_type() - && Linemap::is_predeclared_location(this->type_value()->location())) - { - // We don't need the package name for builtin types. - decl_name = Gogo::unpack_hidden_name(this->name_); - } else { std::string package_name; @@ -7466,22 +7333,6 @@ Named_object::get_id(Gogo* gogo) decl_name.append(fntype->receiver()->type()->mangled_name(gogo)); } } - if (this->is_type()) - { - unsigned int index; - const Named_object* in_function = this->type_value()->in_function(&index); - if (in_function != NULL) - { - decl_name += '$' + Gogo::unpack_hidden_name(in_function->name()); - if (index > 0) - { - char buf[30]; - snprintf(buf, sizeof buf, "%u", index); - decl_name += '$'; - decl_name += buf; - } - } - } return decl_name; } diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index a04a1a36ee3..018aca5e2ef 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -506,26 +506,6 @@ class Gogo void mark_locals_used(); - // 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 - // errors. - static std::string - erroneous_name(); - - // Return whether the name indicates an error. - static bool - is_erroneous_name(const std::string&); - - // Return a name to use for a thunk function. A thunk function is - // one we create during the compilation, for a go statement or a - // defer statement or a method expression. - static std::string - thunk_name(); - - // Return whether an object is a thunk. - static bool - is_thunk(const Named_object*); - // Note that we've seen an interface type. This is used to build // all required interface method tables. void @@ -781,10 +761,112 @@ 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); + + // Return the assembler name to use for an unexported function. + std::string + unexported_function_asm_name(const std::string& go_name); + + // Return the name to use for a function descriptor. + std::string + function_descriptor_name(Named_object*); + + // Return the name to use for a generated stub method. + std::string + stub_method_name(const std::string& method_name); + + // Return the names of the hash and equality functions for TYPE. + void + specific_type_function_names(const Type*, const Named_type*, + std::string* hash_name, + std::string* equal_name); + + // Return the assembler name to use for a global variable. + std::string + global_var_asm_name(const std::string& go_name, const Package*); + + // 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 + // errors. + static std::string + erroneous_name(); + + // Return whether the name indicates an error. + static bool + is_erroneous_name(const std::string&); + + // Return a name to use for a thunk function. A thunk function is + // one we create during the compilation, for a go statement or a + // defer statement or a method expression. + static std::string + thunk_name(); + + // Return whether an object is a thunk. + static bool + is_thunk(const Named_object*); + + // Return the name to use for an init function. + std::string + init_function_name(); + + // Return the name to use for a nested function. + static std::string + nested_function_name(); + + // Return the index of a nested function name. + static int + nested_function_num(const std::string&); + + // Return the name to use for a sink funciton. + std::string + sink_function_name(); + + // Return the name to use for an (erroneous) redefined function. + std::string + redefined_function_name(); + + // Return the name for use for a recover thunk. + std::string + recover_thunk_name(const std::string& name, const Type* rtype); + + // Return the name to use for the GC root variable. + std::string + gc_root_name(); + + // Return the name to use for a composite literal or string + // initializer. + std::string + initializer_name(); + + // Return the name of the variable used to represent the zero value + // of a map. + std::string + map_zero_value_name(); + // Get the name of the magic initialization function. const std::string& get_init_fn_name(); + // Return the name for a type descriptor symbol. + std::string + type_descriptor_name(Type*, Named_type*); + + // Return the assembler name for the GC symbol for a type. + std::string + gc_symbol_name(Type*); + + // Return the assembler name for a ptrmask variable. + std::string + ptrmask_symbol_name(const std::string& ptrmask_sym_name); + + // Return the name to use for an interface method table. + std::string + interface_method_table_name(Interface_type*, Type*, bool is_pointer); + private: // During parsing, we keep a stack of functions. Each function on // the stack is one that we are currently parsing. For each diff --git a/gcc/go/gofrontend/names.cc b/gcc/go/gofrontend/names.cc new file mode 100644 index 00000000000..48ffec08d9e --- /dev/null +++ b/gcc/go/gofrontend/names.cc @@ -0,0 +1,825 @@ +// names.cc -- Names used by gofrontend generated code. + +// Copyright 2017 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#include "go-system.h" + +#include "gogo.h" +#include "go-encode-id.h" +#include "types.h" +#include "expressions.h" + +// This file contains functions that generate names that appear in the +// assembly code. This is not used for names that appear only in the +// debug info. + +// 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 +// 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) +{ + std::string ret = (package == NULL + ? this->pkgpath_symbol() + : package->pkgpath_symbol()); + + if (rtype != NULL + && Gogo::is_hidden_name(go_name) + && Gogo::hidden_name_pkgpath(go_name) != this->pkgpath()) + { + // This is a method created for an unexported method of an + // imported embedded type. Use the pkgpath of the imported + // package. + std::string p = Gogo::hidden_name_pkgpath(go_name); + ret = this->pkgpath_symbol_for_package(p); + } + + ret.append(1, '.'); + ret.append(Gogo::unpack_hidden_name(go_name)); + + if (rtype != NULL) + { + ret.append(1, '.'); + ret.append(rtype->mangled_name(this)); + } + + return go_encode_id(ret); +} + +// Return the assembler name to use for an unexported function. +// FIXME: This should probably be removed and the callers changed to +// simply call function_name. + +std::string +Gogo::unexported_function_asm_name(const std::string& go_name) +{ + std::string ret = this->package_name(); + ret.append(1, '.'); + ret.append(Gogo::unpack_hidden_name(go_name)); + return go_encode_id(ret); +} + +// Return the name to use for a function descriptor. These symbols +// are globally visible. + +std::string +Gogo::function_descriptor_name(Named_object* no) +{ + std::string var_name; + if (no->is_function_declaration() + && !no->func_declaration_value()->asm_name().empty() + && Linemap::is_predeclared_location(no->location())) + { + if (no->func_declaration_value()->asm_name().substr(0, 8) != "runtime.") + var_name = no->func_declaration_value()->asm_name() + "_descriptor"; + else + var_name = no->func_declaration_value()->asm_name() + "$descriptor"; + } + else + { + if (no->package() == NULL) + var_name = this->pkgpath_symbol(); + else + var_name = no->package()->pkgpath_symbol(); + var_name.push_back('.'); + var_name.append(Gogo::unpack_hidden_name(no->name())); + var_name.append("$descriptor"); + } + return var_name; +} + +// Return the name to use for a generated stub method. MNAME is the +// method name. 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. + +std::string +Gogo::stub_method_name(const std::string& mname) +{ + return mname + "$stub"; +} + +// Return the names of the hash and equality functions for TYPE. If +// NAME is not NULL it is the name of the type. Set *HASH_NAME and +// *EQUAL_NAME. + +void +Gogo::specific_type_function_names(const Type* type, const Named_type* name, + std::string *hash_name, + std::string *equal_name) +{ + std::string base_name; + if (name == NULL) + { + // Mangled names can have '.' if they happen to refer to named + // types in some way. That's fine if this is simply a named + // type, but otherwise it will confuse the code that builds + // function identifiers. Remove '.' when necessary. + base_name = type->mangled_name(this); + size_t i; + while ((i = base_name.find('.')) != std::string::npos) + base_name[i] = '$'; + base_name = this->pack_hidden_name(base_name, false); + } + else + { + // This name is already hidden or not as appropriate. + base_name = name->name(); + unsigned int index; + const Named_object* in_function = name->in_function(&index); + if (in_function != NULL) + { + base_name.append(1, '$'); + const Typed_identifier* rcvr = + in_function->func_value()->type()->receiver(); + if (rcvr != NULL) + { + Named_type* rcvr_type = rcvr->type()->deref()->named_type(); + base_name.append(Gogo::unpack_hidden_name(rcvr_type->name())); + base_name.append(1, '$'); + } + base_name.append(Gogo::unpack_hidden_name(in_function->name())); + if (index > 0) + { + char buf[30]; + snprintf(buf, sizeof buf, "%u", index); + base_name += '$'; + base_name += buf; + } + } + } + *hash_name = base_name + "$hash"; + *equal_name = base_name + "$equal"; +} + +// 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. + +std::string +Gogo::global_var_asm_name(const std::string& go_name, const Package* package) +{ + // FIXME: Using package_name for hidden names and pkgpath_symbol for + // non-hidden names doesn't make sense, but it dates back to the + // first public commit of the gofrontend repo. + std::string ret; + if (Gogo::is_hidden_name(go_name)) + ret = (package != NULL + ? package->package_name() + : this->package_name()); + else + ret = (package != NULL + ? package->pkgpath_symbol() + : this->pkgpath_symbol()); + ret.push_back('.'); + ret.append(Gogo::unpack_hidden_name(go_name)); + return go_encode_id(ret); +} + +// Return an erroneous name that indicates that an error has already +// been reported. + +std::string +Gogo::erroneous_name() +{ + static int erroneous_count; + char name[50]; + snprintf(name, sizeof name, "$erroneous%d", erroneous_count); + ++erroneous_count; + return name; +} + +// Return whether a name is an erroneous name. + +bool +Gogo::is_erroneous_name(const std::string& name) +{ + return name.compare(0, 10, "$erroneous") == 0; +} + +// Return a name for a thunk object. + +std::string +Gogo::thunk_name() +{ + static int thunk_count; + char thunk_name[50]; + snprintf(thunk_name, sizeof thunk_name, "$thunk%d", thunk_count); + ++thunk_count; + return thunk_name; +} + +// Return whether a function is a thunk. + +bool +Gogo::is_thunk(const Named_object* no) +{ + return no->name().compare(0, 6, "$thunk") == 0; +} + +// Return the name to use for an init function. There can be multiple +// functions named "init" so each one needs a different name. + +std::string +Gogo::init_function_name() +{ + static int init_count; + char buf[30]; + snprintf(buf, sizeof buf, ".$init%d", init_count); + ++init_count; + return buf; +} + +// Return the name to use for a nested function. + +std::string +Gogo::nested_function_name() +{ + static int nested_count; + char buf[30]; + snprintf(buf, sizeof buf, ".$nested%d", nested_count); + ++nested_count; + return buf; +} + +// Return the index of a nested function name. + +int +Gogo::nested_function_num(const std::string& name) +{ + std::string n(Gogo::unpack_hidden_name(name)); + go_assert(n.compare(0, 8, ".$nested") == 0); + return strtol(n.substr(8).c_str(), NULL, 0); +} + +// Return the name to use for a sink function, a function whose name +// is simply underscore. We don't really need these functions but we +// do have to generate them for error checking. + +std::string +Gogo::sink_function_name() +{ + static int sink_count; + char buf[30]; + snprintf(buf, sizeof buf, ".$sink%d", sink_count); + ++sink_count; + return buf; +} + +// Return the name to use for a redefined function. These functions +// are erroneous but we still generate them for further error +// checking. + +std::string +Gogo::redefined_function_name() +{ + static int redefinition_count; + char buf[30]; + snprintf(buf, sizeof buf, ".$redefined%d", redefinition_count); + ++redefinition_count; + return buf; +} + +// Return the name to use for a recover thunk for the function NAME. +// If the function is a method, RTYPE is the receiver type. + +std::string +Gogo::recover_thunk_name(const std::string& name, const Type* rtype) +{ + std::string ret(name); + if (rtype != NULL) + { + ret.push_back('$'); + ret.append(rtype->mangled_name(this)); + } + ret.append("$recover"); + return ret; +} + +// Return the name to use for a GC root variable. The GC root +// variable is a composite literal that is passed to +// runtime.registerGCRoots. There is at most one of these variables +// per compilation. + +std::string +Gogo::gc_root_name() +{ + return "gc0"; +} + +// Return the name to use for a composite literal or string +// initializer. This is a local name never referenced outside of this +// file. + +std::string +Gogo::initializer_name() +{ + static unsigned int counter; + char buf[30]; + snprintf(buf, sizeof buf, "C%u", counter); + ++counter; + return buf; +} + +// Return the 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() +{ + return "go$zerovalue"; +} + +// Return the name to use for the import control function. + +const std::string& +Gogo::get_init_fn_name() +{ + if (this->init_fn_name_.empty()) + { + go_assert(this->package_ != NULL); + if (this->is_main_package()) + { + // Use a name that the runtime knows. + this->init_fn_name_ = "__go_init_main"; + } + else + { + std::string s = this->pkgpath_symbol(); + s.append("..import"); + this->init_fn_name_ = s; + } + } + + return this->init_fn_name_; +} + +// Return a mangled name for a type. 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 +{ + std::string ret; + + // The do_mangled_name virtual function should set RET to the + // mangled name. For a composite type it should append a code for + // the composition and then call do_mangled_name on the components. + this->do_mangled_name(gogo, &ret); + + return ret; +} + +// The mangled name is implemented as a method on each instance of +// Type. + +void +Error_type::do_mangled_name(Gogo*, std::string* ret) const +{ + ret->push_back('E'); +} + +void +Void_type::do_mangled_name(Gogo*, std::string* ret) const +{ + ret->push_back('v'); +} + +void +Boolean_type::do_mangled_name(Gogo*, std::string* ret) const +{ + ret->push_back('b'); +} + +void +Integer_type::do_mangled_name(Gogo*, std::string* ret) const +{ + char buf[100]; + snprintf(buf, sizeof buf, "i%s%s%de", + this->is_abstract_ ? "a" : "", + this->is_unsigned_ ? "u" : "", + this->bits_); + ret->append(buf); +} + +void +Float_type::do_mangled_name(Gogo*, std::string* ret) const +{ + char buf[100]; + snprintf(buf, sizeof buf, "f%s%de", + this->is_abstract_ ? "a" : "", + this->bits_); + ret->append(buf); +} + +void +Complex_type::do_mangled_name(Gogo*, std::string* ret) const +{ + char buf[100]; + snprintf(buf, sizeof buf, "c%s%de", + this->is_abstract_ ? "a" : "", + this->bits_); + ret->append(buf); +} + +void +String_type::do_mangled_name(Gogo*, std::string* ret) const +{ + ret->push_back('z'); +} + +void +Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const +{ + ret->push_back('F'); + + if (this->receiver_ != NULL) + { + ret->push_back('m'); + this->append_mangled_name(this->receiver_->type(), gogo, ret); + } + + const Typed_identifier_list* params = this->parameters(); + if (params != NULL) + { + ret->push_back('p'); + for (Typed_identifier_list::const_iterator p = params->begin(); + p != params->end(); + ++p) + this->append_mangled_name(p->type(), gogo, ret); + if (this->is_varargs_) + ret->push_back('V'); + ret->push_back('e'); + } + + const Typed_identifier_list* results = this->results(); + if (results != NULL) + { + ret->push_back('r'); + for (Typed_identifier_list::const_iterator p = results->begin(); + p != results->end(); + ++p) + this->append_mangled_name(p->type(), gogo, ret); + ret->push_back('e'); + } + + ret->push_back('e'); +} + +void +Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret) const +{ + ret->push_back('p'); + this->append_mangled_name(this->to_type_, gogo, ret); +} + +void +Nil_type::do_mangled_name(Gogo*, std::string* ret) const +{ + ret->push_back('n'); +} + +void +Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const +{ + ret->push_back('S'); + + const Struct_field_list* fields = this->fields_; + if (fields != NULL) + { + for (Struct_field_list::const_iterator p = fields->begin(); + p != fields->end(); + ++p) + { + if (p->is_anonymous()) + ret->append("0_"); + else + { + + std::string n(Gogo::mangle_possibly_hidden_name(p->field_name())); + char buf[20]; + snprintf(buf, sizeof buf, "%u_", + static_cast(n.length())); + ret->append(buf); + ret->append(n); + } + + // For an anonymous field with an alias type, the field name + // is the alias name. + if (p->is_anonymous() + && p->type()->named_type() != NULL + && p->type()->named_type()->is_alias()) + p->type()->named_type()->append_mangled_type_name(gogo, true, ret); + else + this->append_mangled_name(p->type(), gogo, ret); + if (p->has_tag()) + { + const std::string& tag(p->tag()); + std::string out; + for (std::string::const_iterator p = tag.begin(); + p != tag.end(); + ++p) + { + if (ISALNUM(*p) || *p == '_') + out.push_back(*p); + else + { + char buf[20]; + snprintf(buf, sizeof buf, ".%x.", + static_cast(*p)); + out.append(buf); + } + } + char buf[20]; + snprintf(buf, sizeof buf, "T%u_", + static_cast(out.length())); + ret->append(buf); + ret->append(out); + } + } + } + + if (this->is_struct_incomparable_) + ret->push_back('x'); + + ret->push_back('e'); +} + +void +Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const +{ + ret->push_back('A'); + this->append_mangled_name(this->element_type_, gogo, ret); + if (this->length_ != NULL) + { + Numeric_constant nc; + if (!this->length_->numeric_constant_value(&nc)) + { + go_assert(saw_errors()); + return; + } + mpz_t val; + if (!nc.to_int(&val)) + { + go_assert(saw_errors()); + return; + } + char *s = mpz_get_str(NULL, 10, val); + ret->append(s); + free(s); + mpz_clear(val); + if (this->is_array_incomparable_) + ret->push_back('x'); + } + ret->push_back('e'); +} + +void +Map_type::do_mangled_name(Gogo* gogo, std::string* ret) const +{ + ret->push_back('M'); + this->append_mangled_name(this->key_type_, gogo, ret); + ret->append("__"); + this->append_mangled_name(this->val_type_, gogo, ret); +} + +void +Channel_type::do_mangled_name(Gogo* gogo, std::string* ret) const +{ + ret->push_back('C'); + this->append_mangled_name(this->element_type_, gogo, ret); + if (this->may_send_) + ret->push_back('s'); + if (this->may_receive_) + ret->push_back('r'); + ret->push_back('e'); +} + +void +Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const +{ + go_assert(this->methods_are_finalized_); + + ret->push_back('I'); + + const Typed_identifier_list* methods = this->all_methods_; + if (methods != NULL && !this->seen_) + { + this->seen_ = true; + for (Typed_identifier_list::const_iterator p = methods->begin(); + p != methods->end(); + ++p) + { + if (!p->name().empty()) + { + std::string n(Gogo::mangle_possibly_hidden_name(p->name())); + char buf[20]; + snprintf(buf, sizeof buf, "%u_", + static_cast(n.length())); + ret->append(buf); + ret->append(n); + } + this->append_mangled_name(p->type(), gogo, ret); + } + this->seen_ = false; + } + + ret->push_back('e'); +} + +void +Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const +{ + this->append_mangled_type_name(gogo, false, ret); +} + +void +Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret) const +{ + if (this->is_defined()) + this->append_mangled_name(this->real_type(), gogo, ret); + else + { + const Named_object* no = this->named_object(); + std::string name; + if (no->package() == NULL) + name = gogo->pkgpath_symbol(); + else + name = no->package()->pkgpath_symbol(); + name += '.'; + name += Gogo::unpack_hidden_name(no->name()); + char buf[20]; + snprintf(buf, sizeof buf, "N%u_", + static_cast(name.length())); + ret->append(buf); + ret->append(name); + } +} + +// Append the mangled 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 +{ + if (this->is_error_) + return; + if (this->is_alias_ && !use_alias) + { + if (this->seen_alias_) + return; + this->seen_alias_ = true; + this->append_mangled_name(this->type_, gogo, ret); + this->seen_alias_ = false; + return; + } + Named_object* no = this->named_object_; + std::string name; + if (this->is_builtin()) + go_assert(this->in_function_ == NULL); + else + { + const std::string& pkgpath(no->package() == NULL + ? gogo->pkgpath_symbol() + : no->package()->pkgpath_symbol()); + name = pkgpath; + name.append(1, '.'); + if (this->in_function_ != NULL) + { + const Typed_identifier* rcvr = + this->in_function_->func_value()->type()->receiver(); + if (rcvr != NULL) + { + Named_type* rcvr_type = rcvr->type()->deref()->named_type(); + name.append(Gogo::unpack_hidden_name(rcvr_type->name())); + name.append(1, '.'); + } + name.append(Gogo::unpack_hidden_name(this->in_function_->name())); + name.append(1, '$'); + if (this->in_function_index_ > 0) + { + char buf[30]; + snprintf(buf, sizeof buf, "%u", this->in_function_index_); + name.append(buf); + name.append(1, '$'); + } + } + } + name.append(Gogo::unpack_hidden_name(no->name())); + char buf[20]; + snprintf(buf, sizeof buf, "N%u_", static_cast(name.length())); + ret->append(buf); + ret->append(name); +} + +// 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. + +std::string +Gogo::type_descriptor_name(Type* type, Named_type* nt) +{ + // 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. + if (type->is_unsafe_pointer_type()) + return "__go_tdn_unsafe.Pointer"; + + if (nt == NULL) + return "__go_td_" + type->mangled_name(this); + + Named_object* no = nt->named_object(); + unsigned int index; + const Named_object* in_function = nt->in_function(&index); + std::string ret = "__go_tdn_"; + if (nt->is_builtin()) + go_assert(in_function == NULL); + else + { + const std::string& pkgpath(no->package() == NULL + ? this->pkgpath_symbol() + : no->package()->pkgpath_symbol()); + ret.append(pkgpath); + ret.append(1, '.'); + if (in_function != NULL) + { + const Typed_identifier* rcvr = + in_function->func_value()->type()->receiver(); + if (rcvr != NULL) + { + Named_type* rcvr_type = rcvr->type()->deref()->named_type(); + ret.append(Gogo::unpack_hidden_name(rcvr_type->name())); + ret.append(1, '.'); + } + ret.append(Gogo::unpack_hidden_name(in_function->name())); + ret.append(1, '.'); + if (index > 0) + { + char buf[30]; + snprintf(buf, sizeof buf, "%u", index); + ret.append(buf); + ret.append(1, '.'); + } + } + } + + std::string mname(Gogo::mangle_possibly_hidden_name(no->name())); + ret.append(mname); + + return ret; +} + +// 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.) + +std::string +Gogo::gc_symbol_name(Type* type) +{ + return this->type_descriptor_name(type, type->named_type()) + "$gc"; +} + +// Return the name for a ptrmask variable. PTRMASK_SYM_NAME is a +// base64 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.) + +std::string +Gogo::ptrmask_symbol_name(const std::string& ptrmask_sym_name) +{ + return "runtime.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. +// IS_POINTER is true if this is for the method set for a pointer +// receiver. + +std::string +Gogo::interface_method_table_name(Interface_type* itype, Type* type, + bool is_pointer) +{ + return ((is_pointer ? "__go_pimt__" : "__go_imt_") + + itype->mangled_name(this) + + "__" + + type->mangled_name(this)); +} diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index b6323f8135e..5b0c84a0f56 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -1257,7 +1257,7 @@ Type::make_type_descriptor_var(Gogo* gogo) Type* td_type = Type::make_type_descriptor_type(); Btype* td_btype = td_type->get_backend(gogo); - const char *name = "__go_tdn_unsafe.Pointer"; + std::string name = gogo->type_descriptor_name(this, nt); std::string asm_name(go_selectively_encode_id(name)); this->type_descriptor_var_ = gogo->backend()->immutable_struct_reference(name, asm_name, @@ -1269,7 +1269,7 @@ Type::make_type_descriptor_var(Gogo* gogo) return; } - std::string var_name = this->type_descriptor_var_name(gogo, nt); + std::string var_name = gogo->type_descriptor_name(this, nt); // Build the contents of the type descriptor. Expression* initializer = this->do_type_descriptor(gogo, NULL); @@ -1331,56 +1331,6 @@ Type::make_type_descriptor_var(Gogo* gogo) binitializer); } -// Return the name of the type descriptor variable. If NT is not -// NULL, use it to get the name. Otherwise this is an unnamed type. - -std::string -Type::type_descriptor_var_name(Gogo* gogo, Named_type* nt) -{ - if (nt == NULL) - return "__go_td_" + this->mangled_name(gogo); - - Named_object* no = nt->named_object(); - unsigned int index; - const Named_object* in_function = nt->in_function(&index); - std::string ret = "__go_tdn_"; - if (nt->is_builtin()) - go_assert(in_function == NULL); - else - { - const std::string& pkgpath(no->package() == NULL - ? gogo->pkgpath_symbol() - : no->package()->pkgpath_symbol()); - ret.append(pkgpath); - ret.append(1, '.'); - if (in_function != NULL) - { - const Typed_identifier* rcvr = - in_function->func_value()->type()->receiver(); - if (rcvr != NULL) - { - Named_type* rcvr_type = rcvr->type()->deref()->named_type(); - ret.append(Gogo::unpack_hidden_name(rcvr_type->name())); - ret.append(1, '.'); - } - ret.append(Gogo::unpack_hidden_name(in_function->name())); - ret.append(1, '.'); - if (index > 0) - { - char buf[30]; - snprintf(buf, sizeof buf, "%u", index); - ret.append(buf); - ret.append(1, '.'); - } - } - } - - std::string mname(Gogo::mangle_possibly_hidden_name(no->name())); - ret.append(mname); - - return ret; -} - // Return true if this type descriptor is defined in a different // package. If this returns true it sets *PACKAGE to the package. @@ -1967,48 +1917,9 @@ Type::specific_type_functions(Gogo* gogo, Named_type* name, int64_t size, return; } - std::string base_name; - if (name == NULL) - { - // Mangled names can have '.' if they happen to refer to named - // types in some way. That's fine if this is simply a named - // type, but otherwise it will confuse the code that builds - // function identifiers. Remove '.' when necessary. - base_name = this->mangled_name(gogo); - size_t i; - while ((i = base_name.find('.')) != std::string::npos) - base_name[i] = '$'; - base_name = gogo->pack_hidden_name(base_name, false); - } - else - { - // This name is already hidden or not as appropriate. - base_name = name->name(); - unsigned int index; - const Named_object* in_function = name->in_function(&index); - if (in_function != NULL) - { - base_name.append(1, '$'); - const Typed_identifier* rcvr = - in_function->func_value()->type()->receiver(); - if (rcvr != NULL) - { - Named_type* rcvr_type = rcvr->type()->deref()->named_type(); - base_name.append(Gogo::unpack_hidden_name(rcvr_type->name())); - base_name.append(1, '$'); - } - base_name.append(Gogo::unpack_hidden_name(in_function->name())); - if (index > 0) - { - char buf[30]; - snprintf(buf, sizeof buf, "%u", index); - base_name += '$'; - base_name += buf; - } - } - } - std::string hash_name = base_name + "$hash"; - std::string equal_name = base_name + "$equal"; + std::string hash_name; + std::string equal_name; + gogo->specific_type_function_names(this, name, &hash_name, &equal_name); Location bloc = Linemap::predeclared_location(); @@ -2525,7 +2436,7 @@ Type::make_gc_symbol_var(Gogo* gogo) return; } - std::string sym_name = this->type_descriptor_var_name(gogo, nt) + "$gc"; + std::string sym_name = gogo->gc_symbol_name(this); // Build the contents of the gc symbol. Expression* sym_init = this->gcprog_constructor(gogo, ptrsize, ptrdata); @@ -2818,7 +2729,8 @@ Type::gc_ptrmask_var(Gogo* gogo, int64_t ptrsize, int64_t ptrdata) // This can happen in error cases. Just build an empty gcbits. go_assert(saw_errors()); } - std::string sym_name = "runtime.gcbits." + ptrmask.symname(); + + std::string sym_name = gogo->ptrmask_symbol_name(ptrmask.symname()); Bvariable* bvnull = NULL; std::pair ins = Type::gc_gcbits_vars.insert(std::make_pair(sym_name, bvnull)); @@ -3462,21 +3374,6 @@ Type::reflection(Gogo* gogo) const return ret; } -// Return a mangled name for the type. - -std::string -Type::mangled_name(Gogo* gogo) const -{ - std::string ret; - - // The do_mangled_name virtual function should set RET to the - // mangled name. For a composite type it should append a code for - // the composition and then call do_mangled_name on the components. - this->do_mangled_name(gogo, &ret); - - return ret; -} - // Return whether the backend size of the type is known. bool @@ -3796,37 +3693,32 @@ Type::import_type(Import* imp) } } -// A type used to indicate a parsing error. This exists to simplify -// later error detection. +// Class Error_type. -class Error_type : public Type +// Return the backend representation of an Error type. + +Btype* +Error_type::do_get_backend(Gogo* gogo) { - public: - Error_type() - : Type(TYPE_ERROR) - { } + return gogo->backend()->error_type(); +} - protected: - bool - do_compare_is_identity(Gogo*) - { return false; } +// Return an expression for the type descriptor for an error type. - Btype* - do_get_backend(Gogo* gogo) - { return gogo->backend()->error_type(); } - Expression* - do_type_descriptor(Gogo*, Named_type*) - { return Expression::make_error(Linemap::predeclared_location()); } +Expression* +Error_type::do_type_descriptor(Gogo*, Named_type*) +{ + return Expression::make_error(Linemap::predeclared_location()); +} - void - do_reflection(Gogo*, std::string*) const - { go_assert(saw_errors()); } +// We should not be asked for the reflection string for an error type. - void - do_mangled_name(Gogo*, std::string* ret) const - { ret->push_back('E'); } -}; +void +Error_type::do_reflection(Gogo*, std::string*) const +{ + go_assert(saw_errors()); +} Type* Type::make_error_type() @@ -3835,36 +3727,15 @@ Type::make_error_type() return &singleton_error_type; } -// The void type. +// Class Void_type. -class Void_type : public Type +// Get the backend representation of a void type. + +Btype* +Void_type::do_get_backend(Gogo* gogo) { - public: - Void_type() - : Type(TYPE_VOID) - { } - - protected: - bool - do_compare_is_identity(Gogo*) - { return false; } - - Btype* - do_get_backend(Gogo* gogo) - { return gogo->backend()->void_type(); } - - Expression* - do_type_descriptor(Gogo*, Named_type*) - { go_unreachable(); } - - void - do_reflection(Gogo*, std::string*) const - { } - - void - do_mangled_name(Gogo*, std::string* ret) const - { ret->push_back('v'); } -}; + return gogo->backend()->void_type(); +} Type* Type::make_void_type() @@ -3873,36 +3744,15 @@ Type::make_void_type() return &singleton_void_type; } -// The boolean type. +// Class Boolean_type. -class Boolean_type : public Type +// Return the backend representation of the boolean type. + +Btype* +Boolean_type::do_get_backend(Gogo* gogo) { - public: - Boolean_type() - : Type(TYPE_BOOLEAN) - { } - - protected: - bool - do_compare_is_identity(Gogo*) - { return true; } - - Btype* - do_get_backend(Gogo* gogo) - { return gogo->backend()->bool_type(); } - - Expression* - do_type_descriptor(Gogo*, Named_type* name); - - // We should not be asked for the reflection string of a basic type. - void - do_reflection(Gogo*, std::string* ret) const - { ret->append("bool"); } - - void - do_mangled_name(Gogo*, std::string* ret) const - { ret->push_back('b'); } -}; + return gogo->backend()->bool_type(); +} // Make the type descriptor. @@ -4069,19 +3919,6 @@ Integer_type::do_reflection(Gogo*, std::string*) const go_assert(saw_errors()); } -// Mangled name. - -void -Integer_type::do_mangled_name(Gogo*, std::string* ret) const -{ - char buf[100]; - snprintf(buf, sizeof buf, "i%s%s%de", - this->is_abstract_ ? "a" : "", - this->is_unsigned_ ? "u" : "", - this->bits_); - ret->append(buf); -} - // Make an integer type. Named_type* @@ -4204,18 +4041,6 @@ Float_type::do_reflection(Gogo*, std::string*) const go_assert(saw_errors()); } -// Mangled name. - -void -Float_type::do_mangled_name(Gogo*, std::string* ret) const -{ - char buf[100]; - snprintf(buf, sizeof buf, "f%s%de", - this->is_abstract_ ? "a" : "", - this->bits_); - ret->append(buf); -} - // Make a floating point type. Named_type* @@ -4331,18 +4156,6 @@ Complex_type::do_reflection(Gogo*, std::string*) const go_assert(saw_errors()); } -// Mangled name. - -void -Complex_type::do_mangled_name(Gogo*, std::string* ret) const -{ - char buf[100]; - snprintf(buf, sizeof buf, "c%s%de", - this->is_abstract_ ? "a" : "", - this->bits_); - ret->append(buf); -} - // Make a complex type. Named_type* @@ -4428,14 +4241,6 @@ String_type::do_reflection(Gogo*, std::string* ret) const ret->append("string"); } -// Mangled name of a string type. - -void -String_type::do_mangled_name(Gogo*, std::string* ret) const -{ - ret->push_back('z'); -} - // Make a string type. Type* @@ -5082,46 +4887,6 @@ Function_type::do_reflection(Gogo* gogo, std::string* ret) const } } -// Mangled name. - -void -Function_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - ret->push_back('F'); - - if (this->receiver_ != NULL) - { - ret->push_back('m'); - this->append_mangled_name(this->receiver_->type(), gogo, ret); - } - - const Typed_identifier_list* params = this->parameters(); - if (params != NULL) - { - ret->push_back('p'); - for (Typed_identifier_list::const_iterator p = params->begin(); - p != params->end(); - ++p) - this->append_mangled_name(p->type(), gogo, ret); - if (this->is_varargs_) - ret->push_back('V'); - ret->push_back('e'); - } - - const Typed_identifier_list* results = this->results(); - if (results != NULL) - { - ret->push_back('r'); - for (Typed_identifier_list::const_iterator p = results->begin(); - p != results->end(); - ++p) - this->append_mangled_name(p->type(), gogo, ret); - ret->push_back('e'); - } - - ret->push_back('e'); -} - // Export a function type. void @@ -5484,13 +5249,6 @@ Pointer_type::do_reflection(Gogo* gogo, std::string* ret) const this->append_reflection(this->to_type_, gogo, ret); } -void -Pointer_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - ret->push_back('p'); - this->append_mangled_name(this->to_type_, gogo, ret); -} - // Export. void @@ -5572,38 +5330,16 @@ Type::finish_pointer_types(Gogo* gogo) } } -// The nil type. We use a special type for nil because it is not the -// same as any other type. In C term nil has type void*, but there is -// no such type in Go. +// Class Nil_type. -class Nil_type : public Type +// Get the backend representation of a nil type. FIXME: Is this ever +// actually called? + +Btype* +Nil_type::do_get_backend(Gogo* gogo) { - public: - Nil_type() - : Type(TYPE_NIL) - { } - - protected: - bool - do_compare_is_identity(Gogo*) - { return false; } - - Btype* - do_get_backend(Gogo* gogo) - { return gogo->backend()->pointer_type(gogo->backend()->void_type()); } - - Expression* - do_type_descriptor(Gogo*, Named_type*) - { go_unreachable(); } - - void - do_reflection(Gogo*, std::string*) const - { go_unreachable(); } - - void - do_mangled_name(Gogo*, std::string* ret) const - { ret->push_back('n'); } -}; + return gogo->backend()->pointer_type(gogo->backend()->void_type()); +} // Make the nil type. @@ -6692,74 +6428,6 @@ Struct_type::do_reflection(Gogo* gogo, std::string* ret) const ret->push_back('}'); } -// Mangled name. - -void -Struct_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - ret->push_back('S'); - - const Struct_field_list* fields = this->fields_; - if (fields != NULL) - { - for (Struct_field_list::const_iterator p = fields->begin(); - p != fields->end(); - ++p) - { - if (p->is_anonymous()) - ret->append("0_"); - else - { - - std::string n(Gogo::mangle_possibly_hidden_name(p->field_name())); - char buf[20]; - snprintf(buf, sizeof buf, "%u_", - static_cast(n.length())); - ret->append(buf); - ret->append(n); - } - - // For an anonymous field with an alias type, the field name - // is the alias name. - if (p->is_anonymous() - && p->type()->named_type() != NULL - && p->type()->named_type()->is_alias()) - p->type()->named_type()->append_mangled_type_name(gogo, true, ret); - else - this->append_mangled_name(p->type(), gogo, ret); - if (p->has_tag()) - { - const std::string& tag(p->tag()); - std::string out; - for (std::string::const_iterator p = tag.begin(); - p != tag.end(); - ++p) - { - if (ISALNUM(*p) || *p == '_') - out.push_back(*p); - else - { - char buf[20]; - snprintf(buf, sizeof buf, ".%x.", - static_cast(*p)); - out.append(buf); - } - } - char buf[20]; - snprintf(buf, sizeof buf, "T%u_", - static_cast(out.length())); - ret->append(buf); - ret->append(out); - } - } - } - - if (this->is_struct_incomparable_) - ret->push_back('x'); - - ret->push_back('e'); -} - // If the offset of field INDEX in the backend implementation can be // determined, set *POFFSET to the offset in bytes and return true. // Otherwise, return false. @@ -7951,37 +7619,6 @@ Array_type::do_reflection(Gogo* gogo, std::string* ret) const this->append_reflection(this->element_type_, gogo, ret); } -// Mangled name. - -void -Array_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - ret->push_back('A'); - this->append_mangled_name(this->element_type_, gogo, ret); - if (this->length_ != NULL) - { - Numeric_constant nc; - if (!this->length_->numeric_constant_value(&nc)) - { - go_assert(saw_errors()); - return; - } - mpz_t val; - if (!nc.to_int(&val)) - { - go_assert(saw_errors()); - return; - } - char *s = mpz_get_str(NULL, 10, val); - ret->append(s); - free(s); - mpz_clear(val); - if (this->is_array_incomparable_) - ret->push_back('x'); - } - ret->push_back('e'); -} - // Make an array type. Array_type* @@ -8037,8 +7674,8 @@ Map_type::fat_zero_value(Gogo* gogo) Array_type* array_type = Type::make_array_type(uint8_type, size); array_type->set_is_array_incomparable(); Variable* var = new Variable(array_type, NULL, true, false, false, bloc); - Map_type::zero_value = Named_object::make_variable("go$zerovalue", NULL, - var); + std::string name = gogo->map_zero_value_name(); + Map_type::zero_value = Named_object::make_variable(name, NULL, var); } Expression* z = Expression::make_var_reference(Map_type::zero_value, bloc); @@ -8582,17 +8219,6 @@ Map_type::do_reflection(Gogo* gogo, std::string* ret) const this->append_reflection(this->val_type_, gogo, ret); } -// Mangled name for a map. - -void -Map_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - ret->push_back('M'); - this->append_mangled_name(this->key_type_, gogo, ret); - ret->append("__"); - this->append_mangled_name(this->val_type_, gogo, ret); -} - // Export a map type. void @@ -8765,20 +8391,6 @@ Channel_type::do_reflection(Gogo* gogo, std::string* ret) const this->append_reflection(this->element_type_, gogo, ret); } -// Mangled name. - -void -Channel_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - ret->push_back('C'); - this->append_mangled_name(this->element_type_, gogo, ret); - if (this->may_send_) - ret->push_back('s'); - if (this->may_receive_) - ret->push_back('r'); - ret->push_back('e'); -} - // Export. void @@ -9702,40 +9314,6 @@ Interface_type::do_reflection(Gogo* gogo, std::string* ret) const ret->append("}"); } -// Mangled name. - -void -Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - go_assert(this->methods_are_finalized_); - - ret->push_back('I'); - - const Typed_identifier_list* methods = this->all_methods_; - if (methods != NULL && !this->seen_) - { - this->seen_ = true; - for (Typed_identifier_list::const_iterator p = methods->begin(); - p != methods->end(); - ++p) - { - if (!p->name().empty()) - { - std::string n(Gogo::mangle_possibly_hidden_name(p->name())); - char buf[20]; - snprintf(buf, sizeof buf, "%u_", - static_cast(n.length())); - ret->append(buf); - ret->append(n); - } - this->append_mangled_name(p->type(), gogo, ret); - } - this->seen_ = false; - } - - ret->push_back('e'); -} - // Export. void @@ -11178,71 +10756,6 @@ Named_type::append_reflection_type_name(Gogo* gogo, bool use_alias, ret->append(Gogo::unpack_hidden_name(this->named_object_->name())); } -// Get the mangled name. - -void -Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - this->append_mangled_type_name(gogo, false, ret); -} - -// Get the mangled name. For an alias we normally get 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 -{ - if (this->is_error_) - return; - if (this->is_alias_ && !use_alias) - { - if (this->seen_alias_) - return; - this->seen_alias_ = true; - this->append_mangled_name(this->type_, gogo, ret); - this->seen_alias_ = false; - return; - } - Named_object* no = this->named_object_; - std::string name; - if (this->is_builtin()) - go_assert(this->in_function_ == NULL); - else - { - const std::string& pkgpath(no->package() == NULL - ? gogo->pkgpath_symbol() - : no->package()->pkgpath_symbol()); - name = pkgpath; - name.append(1, '.'); - if (this->in_function_ != NULL) - { - const Typed_identifier* rcvr = - this->in_function_->func_value()->type()->receiver(); - if (rcvr != NULL) - { - Named_type* rcvr_type = rcvr->type()->deref()->named_type(); - name.append(Gogo::unpack_hidden_name(rcvr_type->name())); - name.append(1, '.'); - } - name.append(Gogo::unpack_hidden_name(this->in_function_->name())); - name.append(1, '$'); - if (this->in_function_index_ > 0) - { - char buf[30]; - snprintf(buf, sizeof buf, "%u", this->in_function_index_); - name.append(buf); - name.append(1, '$'); - } - } - } - name.append(Gogo::unpack_hidden_name(no->name())); - char buf[20]; - snprintf(buf, sizeof buf, "N%u_", static_cast(name.length())); - ret->append(buf); - ret->append(name); -} - // Export the type. This is called to export a global type. void @@ -11623,7 +11136,7 @@ Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods, package = NULL; else package = type->named_type()->named_object()->package(); - std::string stub_name = name + "$stub"; + std::string stub_name = gogo->stub_method_name(name); Named_object* stub; if (package != NULL) stub = Named_object::make_function_declaration(stub_name, package, @@ -12453,31 +11966,6 @@ Forward_declaration_type::do_reflection(Gogo* gogo, std::string* ret) const this->append_reflection(this->real_type(), gogo, ret); } -// The mangled name. - -void -Forward_declaration_type::do_mangled_name(Gogo* gogo, std::string* ret) const -{ - if (this->is_defined()) - this->append_mangled_name(this->real_type(), gogo, ret); - else - { - const Named_object* no = this->named_object(); - std::string name; - if (no->package() == NULL) - name = gogo->pkgpath_symbol(); - else - name = no->package()->pkgpath_symbol(); - name += '.'; - name += Gogo::unpack_hidden_name(no->name()); - char buf[20]; - snprintf(buf, sizeof buf, "N%u_", - static_cast(name.length())); - ret->append(buf); - ret->append(name); - } -} - // Export a forward declaration. This can happen when a defined type // refers to a type which is only declared (and is presumably defined // in some other file in the same package). diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index f15f08ae4f0..a1e388414c2 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -1213,11 +1213,6 @@ class Type void make_gc_symbol_var(Gogo*); - // Return the name of the type descriptor variable. If NAME is not - // NULL, it is the name to use. - std::string - type_descriptor_var_name(Gogo*, Named_type* name); - // Return true if the type descriptor for this type should be // defined in some other package. If NAME is not NULL, it is the // name of this type. If this returns true it sets *PACKAGE to the @@ -1558,6 +1553,92 @@ class Typed_identifier_list std::vector entries_; }; +// A type used to indicate a parsing error. This exists to simplify +// later error detection. + +class Error_type : public Type +{ + public: + Error_type() + : Type(TYPE_ERROR) + { } + + protected: + bool + do_compare_is_identity(Gogo*) + { return false; } + + Btype* + do_get_backend(Gogo* gogo); + + Expression* + do_type_descriptor(Gogo*, Named_type*); + + void + do_reflection(Gogo*, std::string*) const; + + void + do_mangled_name(Gogo*, std::string* ret) const; +}; + +// The void type. + +class Void_type : public Type +{ + public: + Void_type() + : Type(TYPE_VOID) + { } + + protected: + bool + do_compare_is_identity(Gogo*) + { return false; } + + Btype* + do_get_backend(Gogo* gogo); + + Expression* + do_type_descriptor(Gogo*, Named_type*) + { go_unreachable(); } + + void + do_reflection(Gogo*, std::string*) const + { } + + void + do_mangled_name(Gogo*, std::string* ret) const; +}; + +// The boolean type. + +class Boolean_type : public Type +{ + public: + Boolean_type() + : Type(TYPE_BOOLEAN) + { } + + protected: + bool + do_compare_is_identity(Gogo*) + { return true; } + + Btype* + do_get_backend(Gogo* gogo); + + Expression* + do_type_descriptor(Gogo*, Named_type* name); + + // We should not be asked for the reflection string of a basic type. + void + do_reflection(Gogo*, std::string* ret) const + { ret->append("bool"); } + + void + do_mangled_name(Gogo*, std::string* ret) const; +}; + // The type of an integer. class Integer_type : public Type @@ -2143,6 +2224,37 @@ class Pointer_type : public Type Type* to_type_; }; +// The nil type. We use a special type for nil because it is not the +// same as any other type. In C term nil has type void*, but there is +// no such type in Go. + +class Nil_type : public Type +{ + public: + Nil_type() + : Type(TYPE_NIL) + { } + + protected: + bool + do_compare_is_identity(Gogo*) + { return false; } + + Btype* + do_get_backend(Gogo* gogo); + + Expression* + do_type_descriptor(Gogo*, Named_type*) + { go_unreachable(); } + + void + do_reflection(Gogo*, std::string*) const + { go_unreachable(); } + + void + do_mangled_name(Gogo*, std::string* ret) const; +}; + // The type of a field in a struct. class Struct_field