From: Ian Lance Taylor Date: Thu, 5 Oct 2017 17:20:30 +0000 (+0000) Subject: compiler: centralize all symbol name handling X-Git-Url: https://git.libre-soc.org/?a=commitdiff_plain;h=9add86be80b805afd59414c62e56019252591eea;p=gcc.git compiler: centralize all symbol name handling Consolidate all symbol name handling into the new file names.cc. This is intended to define all the names that will appear in the generated assembly code. Names that will not appear in the assembly code, such as local variable names or label names, remain where they are. This consolidation is not intended to change any of the existing symbol names. Tested by building without and without this patch and comparing the libgo symbol table. Reviewed-on: https://go-review.googlesource.com/68310 * Make-lang.in (GO_OBJS): Add go/names.o. From-SVN: r253458 --- 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. + +// Return the backend representation of an Error type. -class Error_type : public 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 : public Type -{ - 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(); } +// Class Void_type. - void - do_reflection(Gogo*, std::string*) const - { } +// Get the backend representation of a void type. - void - do_mangled_name(Gogo*, std::string* ret) const - { ret->push_back('v'); } -}; +Btype* +Void_type::do_get_backend(Gogo* gogo) +{ + 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 : public Type -{ - public: - Boolean_type() - : Type(TYPE_BOOLEAN) - { } +// Class Boolean_type. - protected: - bool - do_compare_is_identity(Gogo*) - { return true; } +// Return the backend representation of the boolean type. - 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'); } -}; +Btype* +Boolean_type::do_get_backend(Gogo* gogo) +{ + 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 : public Type -{ - 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()); } +// Class Nil_type. - Expression* - do_type_descriptor(Gogo*, Named_type*) - { go_unreachable(); } +// Get the backend representation of a nil type. FIXME: Is this ever +// actually called? - void - do_reflection(Gogo*, std::string*) const - { go_unreachable(); } - - void - do_mangled_name(Gogo*, std::string* ret) const - { ret->push_back('n'); } -}; +Btype* +Nil_type::do_get_backend(Gogo* gogo) +{ + 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