+2017-10-05 Ian Lance Taylor <iant@golang.org>
+
+ * Make-lang.in (GO_OBJS): Add go/names.o.
+
2017-08-30 Richard Sandiford <richard.sandiford@linaro.org>
Alan Hayward <alan.hayward@arm.com>
David Sherwood <david.sherwood@arm.com>
go/import.o \
go/import-archive.o \
go/lex.o \
+ go/names.o \
go/parse.o \
go/runtime.o \
go/statements.o \
-5989ef1cd0add98f107839759a5bc57f34354d39
+048914caa26b34eebabd0423ed48ee3ac34c919c
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
// 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());
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);
}
}
- 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);
// 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);
|| 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);
}
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
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*
"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;
}
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())
{
// 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
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.
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();
{
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())
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.
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));
: 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.
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;
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;
}
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
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
--- /dev/null
+// 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<unsigned int>(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<unsigned int>(*p));
+ out.append(buf);
+ }
+ }
+ char buf[20];
+ snprintf(buf, sizeof buf, "T%u_",
+ static_cast<unsigned int>(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<unsigned int>(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<unsigned int>(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<unsigned int>(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));
+}
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,
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);
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.
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();
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);
// 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<GC_gcbits_vars::iterator, bool> ins =
Type::gc_gcbits_vars.insert(std::make_pair(sym_name, bvnull));
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
}
}
-// 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()
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()
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.
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*
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*
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*
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*
}
}
-// 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
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
}
}
-// 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.
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<unsigned int>(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<unsigned int>(*p));
- out.append(buf);
- }
- }
- char buf[20];
- snprintf(buf, sizeof buf, "T%u_",
- static_cast<unsigned int>(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.
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*
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);
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
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
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<unsigned int>(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
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<unsigned int>(name.length()));
- ret->append(buf);
- ret->append(name);
-}
-
// Export the type. This is called to export a global type.
void
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,
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<unsigned int>(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).
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
std::vector<Typed_identifier> 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
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