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