I committed this patch to the 4.8 branch to bring in the last set of Go 1.1.2 bug fixes and patches. Bootstrapped and ran Go testsuite on x86_64-unknown-linux-gnu.
Ian 2013-10-16 Ian Lance Taylor <i...@google.com> Bring in from mainline: 2013-10-11 Chris Manghane <cm...@google.com> * go-gcc.cc (Gcc_backend::function_code_expression): New function. 2013-10-10 Chris Manghane <cm...@google.com> * go-gcc.cc (Backend::error_function): New function. (Backend::function): New function. (Backend::make_function): New function. (function_to_tree): New function.
Index: libgo/Makefile.am =================================================================== --- libgo/Makefile.am (revision 203707) +++ libgo/Makefile.am (working copy) @@ -424,6 +424,7 @@ runtime_files = \ runtime/go-caller.c \ runtime/go-callers.c \ runtime/go-can-convert-interface.c \ + runtime/go-cdiv.c \ runtime/go-cgo.c \ runtime/go-check-interface.c \ runtime/go-construct-map.c \ Index: libgo/runtime/go-signal.c =================================================================== --- libgo/runtime/go-signal.c (revision 203707) +++ libgo/runtime/go-signal.c (working copy) @@ -399,6 +399,9 @@ sig_tramp_info (int sig, Siginfo *info, { G *gp; M *mp; +#ifdef USING_SPLIT_STACK + void *stack_context[10]; +#endif /* We are now running on the stack registered via sigaltstack. (Actually there is a small span of time between runtime_siginit @@ -409,7 +412,7 @@ sig_tramp_info (int sig, Siginfo *info, if (gp != NULL) { #ifdef USING_SPLIT_STACK - __splitstack_getcontext (&gp->stack_context[0]); + __splitstack_getcontext (&stack_context[0]); #endif } @@ -432,7 +435,7 @@ sig_tramp_info (int sig, Siginfo *info, if (gp != NULL) { #ifdef USING_SPLIT_STACK - __splitstack_setcontext (&gp->stack_context[0]); + __splitstack_setcontext (&stack_context[0]); #endif } } Index: libgo/runtime/go-cdiv.c =================================================================== --- libgo/runtime/go-cdiv.c (revision 0) +++ libgo/runtime/go-cdiv.c (revision 0) @@ -0,0 +1,46 @@ +/* go-cdiv.c -- complex division routines + + Copyright 2013 The Go Authors. All rights reserved. + Use of this source code is governed by a BSD-style + license that can be found in the LICENSE file. */ + +/* Calls to these functions are generated by the Go frontend for + division of complex64 or complex128. We use these because Go's + complex division expects slightly different results from the GCC + default. When dividing NaN+1.0i / 0+0i, Go expects NaN+NaNi but + GCC generates NaN+Infi. NaN+Infi seems wrong seems the rules of + C99 Annex G specify that if either side of a complex number is Inf, + the the whole number is Inf, but an operation involving NaN ought + to result in NaN, not Inf. */ + +__complex float +__go_complex64_div (__complex float a, __complex float b) +{ + if (__builtin_expect (b == 0+0i, 0)) + { + if (!__builtin_isinff (__real__ a) + && !__builtin_isinff (__imag__ a) + && (__builtin_isnanf (__real__ a) || __builtin_isnanf (__imag__ a))) + { + /* Pass "1" to nanf to match math/bits.go. */ + return __builtin_nanf("1") + __builtin_nanf("1")*1i; + } + } + return a / b; +} + +__complex double +__go_complex128_div (__complex double a, __complex double b) +{ + if (__builtin_expect (b == 0+0i, 0)) + { + if (!__builtin_isinf (__real__ a) + && !__builtin_isinf (__imag__ a) + && (__builtin_isnan (__real__ a) || __builtin_isnan (__imag__ a))) + { + /* Pass "1" to nan to match math/bits.go. */ + return __builtin_nan("1") + __builtin_nan("1")*1i; + } + } + return a / b; +} Index: libgo/runtime/go-make-slice.c =================================================================== --- libgo/runtime/go-make-slice.c (revision 203707) +++ libgo/runtime/go-make-slice.c (working copy) @@ -34,7 +34,10 @@ __go_make_slice2 (const struct __go_type std = (const struct __go_slice_type *) td; ilen = (intgo) len; - if (ilen < 0 || (uintptr_t) ilen != len) + if (ilen < 0 + || (uintptr_t) ilen != len + || (std->__element_type->__size > 0 + && len > MaxMem / std->__element_type->__size)) runtime_panicstring ("makeslice: len out of range"); icap = (intgo) cap; Index: gcc/go/go-gcc.cc =================================================================== --- gcc/go/go-gcc.cc (revision 203707) +++ gcc/go/go-gcc.cc (working copy) @@ -232,6 +232,9 @@ class Gcc_backend : public Backend Bexpression* convert_expression(Btype* type, Bexpression* expr, Location); + Bexpression* + function_code_expression(Bfunction*, Location); + // Statements. Bstatement* @@ -334,6 +337,17 @@ class Gcc_backend : public Backend Bexpression* label_address(Blabel*, Location); + // Functions. + + Bfunction* + error_function() + { return this->make_function(error_mark_node); } + + Bfunction* + function(Btype* fntype, const std::string& name, const std::string& asm_name, + bool is_visible, bool is_declaration, bool is_inlinable, + bool disable_split_stack, bool in_unique_section, Location); + private: // Make a Bexpression from a tree. Bexpression* @@ -350,6 +364,10 @@ class Gcc_backend : public Backend make_type(tree t) { return new Btype(t); } + Bfunction* + make_function(tree t) + { return new Bfunction(t); } + Btype* fill_in_struct(Btype*, const std::vector<Btyped_identifier>&); @@ -966,6 +984,19 @@ Gcc_backend::convert_expression(Btype* t return tree_to_expr(ret); } +// Get the address of a function. + +Bexpression* +Gcc_backend::function_code_expression(Bfunction* bfunc, Location location) +{ + tree func = bfunc->get_tree(); + if (func == error_mark_node) + return this->error_expression(); + + tree ret = build_fold_addr_expr_loc(location.gcc_location(), func); + return this->make_expression(ret); +} + // An expression as a statement. Bstatement* @@ -1724,6 +1755,56 @@ Gcc_backend::label_address(Blabel* label return this->make_expression(ret); } +// Declare or define a new function. + +Bfunction* +Gcc_backend::function(Btype* fntype, const std::string& name, + const std::string& asm_name, bool is_visible, + bool is_declaration, bool is_inlinable, + bool disable_split_stack, bool in_unique_section, + Location location) +{ + tree functype = fntype->get_tree(); + if (functype != error_mark_node) + { + gcc_assert(FUNCTION_POINTER_TYPE_P(functype)); + functype = TREE_TYPE(functype); + } + tree id = get_identifier_from_string(name); + if (functype == error_mark_node || id == error_mark_node) + return this->error_function(); + + tree decl = build_decl(location.gcc_location(), FUNCTION_DECL, id, functype); + if (!asm_name.empty()) + SET_DECL_ASSEMBLER_NAME(decl, get_identifier_from_string(asm_name)); + if (is_visible) + TREE_PUBLIC(decl) = 1; + if (is_declaration) + DECL_EXTERNAL(decl) = 1; + else + { + tree restype = TREE_TYPE(functype); + tree resdecl = + build_decl(location.gcc_location(), RESULT_DECL, NULL_TREE, restype); + DECL_ARTIFICIAL(resdecl) = 1; + DECL_IGNORED_P(resdecl) = 1; + DECL_CONTEXT(resdecl) = decl; + DECL_RESULT(decl) = resdecl; + } + if (!is_inlinable) + DECL_UNINLINABLE(decl) = 1; + if (disable_split_stack) + { + tree attr = get_identifier("__no_split_stack__"); + DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE); + } + if (in_unique_section) + resolve_unique_section(decl, 0, 1); + + go_preserve_from_gc(decl); + return new Bfunction(decl); +} + // The single backend. static Gcc_backend gcc_backend; @@ -1799,3 +1880,9 @@ var_to_tree(Bvariable* bv) { return bv->get_tree(); } + +tree +function_to_tree(Bfunction* bf) +{ + return bf->get_tree(); +} Index: gcc/go/gofrontend/expressions.cc =================================================================== --- gcc/go/gofrontend/expressions.cc (revision 203707) +++ gcc/go/gofrontend/expressions.cc (working copy) @@ -1219,7 +1219,7 @@ Func_expression::do_type() // Get the tree for the code of a function expression. -tree +Bexpression* Func_expression::get_code_pointer(Gogo* gogo, Named_object* no, Location loc) { Function_type* fntype; @@ -1237,25 +1237,18 @@ Func_expression::get_code_pointer(Gogo* error_at(loc, "invalid use of special builtin function %qs; must be called", no->message_name().c_str()); - return error_mark_node; + return gogo->backend()->error_expression(); } - tree id = no->get_id(gogo); - if (id == error_mark_node) - return error_mark_node; - - tree fndecl; + Bfunction* fndecl; if (no->is_function()) - fndecl = no->func_value()->get_or_make_decl(gogo, no, id); + fndecl = no->func_value()->get_or_make_decl(gogo, no); else if (no->is_function_declaration()) - fndecl = no->func_declaration_value()->get_or_make_decl(gogo, no, id); + fndecl = no->func_declaration_value()->get_or_make_decl(gogo, no); else go_unreachable(); - if (fndecl == error_mark_node) - return error_mark_node; - - return build_fold_addr_expr_loc(loc.gcc_location(), fndecl); + return gogo->backend()->function_code_expression(fndecl, loc); } // Get the tree for a function expression. This is used when we take @@ -1492,8 +1485,10 @@ class Func_code_reference_expression : p tree Func_code_reference_expression::do_get_tree(Translate_context* context) { - return Func_expression::get_code_pointer(context->gogo(), this->function_, - this->location()); + Bexpression* ret = + Func_expression::get_code_pointer(context->gogo(), this->function_, + this->location()); + return expr_to_tree(ret); } // Make a reference to the code of a function. @@ -3055,8 +3050,7 @@ class Type_conversion_expression : publi do_lower(Gogo*, Named_object*, Statement_inserter*, int); bool - do_is_constant() const - { return this->expr_->is_constant(); } + do_is_constant() const; bool do_numeric_constant_value(Numeric_constant*) const; @@ -3198,6 +3192,27 @@ Type_conversion_expression::do_lower(Gog return this; } +// Return whether a type conversion is a constant. + +bool +Type_conversion_expression::do_is_constant() const +{ + if (!this->expr_->is_constant()) + return false; + + // A conversion to a type that may not be used as a constant is not + // a constant. For example, []byte(nil). + Type* type = this->type_; + if (type->integer_type() == NULL + && type->float_type() == NULL + && type->complex_type() == NULL + && !type->is_boolean_type() + && !type->is_string_type()) + return false; + + return true; +} + // Return the constant numeric value if there is one. bool @@ -5586,6 +5601,15 @@ Binary_expression::do_determine_type(con subcontext.type = NULL; } + if (this->op_ == OPERATOR_ANDAND || this->op_ == OPERATOR_OROR) + { + // For a logical operation, the context does not determine the + // types of the operands. The operands must be some boolean + // type but if the context has a boolean type they do not + // inherit it. See http://golang.org/issue/3924. + subcontext.type = NULL; + } + // Set the context for the left hand operand. if (is_shift_op) { @@ -5967,6 +5991,43 @@ Binary_expression::do_get_tree(Translate right); } + // For complex division Go wants slightly different results than the + // GCC library provides, so we have our own runtime routine. + if (this->op_ == OPERATOR_DIV && this->left_->type()->complex_type() != NULL) + { + const char *name; + tree *pdecl; + Type* ctype; + static tree complex64_div_decl; + static tree complex128_div_decl; + switch (this->left_->type()->complex_type()->bits()) + { + case 64: + name = "__go_complex64_div"; + pdecl = &complex64_div_decl; + ctype = Type::lookup_complex_type("complex64"); + break; + case 128: + name = "__go_complex128_div"; + pdecl = &complex128_div_decl; + ctype = Type::lookup_complex_type("complex128"); + break; + default: + go_unreachable(); + } + Btype* cbtype = ctype->get_backend(gogo); + tree ctype_tree = type_to_tree(cbtype); + return Gogo::call_builtin(pdecl, + this->location(), + name, + 2, + ctype_tree, + ctype_tree, + fold_convert_loc(gccloc, ctype_tree, left), + type, + fold_convert_loc(gccloc, ctype_tree, right)); + } + tree compute_type = excess_precision_type(type); if (compute_type != NULL_TREE) { @@ -7191,6 +7252,15 @@ Builtin_call_expression::do_lower(Gogo* if (this->code_ == BUILTIN_OFFSETOF) { Expression* arg = this->one_arg(); + + if (arg->bound_method_expression() != NULL + || arg->interface_field_reference_expression() != NULL) + { + this->report_error(_("invalid use of method value as argument " + "of Offsetof")); + return this; + } + Field_reference_expression* farg = arg->field_reference_expression(); while (farg != NULL) { @@ -7200,7 +7270,8 @@ Builtin_call_expression::do_lower(Gogo* // it must not be reached through pointer indirections. if (farg->expr()->deref() != farg->expr()) { - this->report_error(_("argument of Offsetof implies indirection of an embedded field")); + this->report_error(_("argument of Offsetof implies " + "indirection of an embedded field")); return this; } // Go up until we reach the original base. @@ -7476,7 +7547,7 @@ Builtin_call_expression::check_int_value switch (nc.to_unsigned_long(&v)) { case Numeric_constant::NC_UL_VALID: - return true; + break; case Numeric_constant::NC_UL_NOTINT: error_at(e->location(), "non-integer %s argument to make", is_length ? "len" : "cap"); @@ -7488,8 +7559,23 @@ Builtin_call_expression::check_int_value case Numeric_constant::NC_UL_BIG: // We don't want to give a compile-time error for a 64-bit // value on a 32-bit target. - return true; + break; } + + mpz_t val; + if (!nc.to_int(&val)) + go_unreachable(); + int bits = mpz_sizeinbase(val, 2); + mpz_clear(val); + Type* int_type = Type::lookup_integer_type("int"); + if (bits >= int_type->integer_type()->bits()) + { + error_at(e->location(), "%s argument too large for make", + is_length ? "len" : "cap"); + return false; + } + + return true; } if (e->type()->integer_type() != NULL) @@ -7595,6 +7681,8 @@ Find_call_expression::expression(Express bool Builtin_call_expression::do_is_constant() const { + if (this->is_error_expression()) + return true; switch (this->code_) { case BUILTIN_LEN: @@ -9744,14 +9832,8 @@ Call_expression::do_get_tree(Translate_c } tree fntype_tree = type_to_tree(fntype->get_backend(gogo)); - if (fntype_tree == error_mark_node) - return error_mark_node; - go_assert(POINTER_TYPE_P(fntype_tree)); - if (TREE_TYPE(fntype_tree) == error_mark_node) - return error_mark_node; - go_assert(TREE_CODE(TREE_TYPE(fntype_tree)) == RECORD_TYPE); - tree fnfield_type = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(fntype_tree))); - if (fnfield_type == error_mark_node) + tree fnfield_type = type_to_tree(fntype->get_backend_fntype(gogo)); + if (fntype_tree == error_mark_node || fnfield_type == error_mark_node) return error_mark_node; go_assert(FUNCTION_POINTER_TYPE_P(fnfield_type)); tree rettype = TREE_TYPE(TREE_TYPE(fnfield_type)); @@ -9763,7 +9845,7 @@ Call_expression::do_get_tree(Translate_c if (func != NULL) { Named_object* no = func->named_object(); - fn = Func_expression::get_code_pointer(gogo, no, location); + fn = expr_to_tree(Func_expression::get_code_pointer(gogo, no, location)); if (!has_closure) closure_tree = NULL_TREE; else @@ -10817,11 +10899,20 @@ String_index_expression::do_determine_ty void String_index_expression::do_check_types(Gogo*) { - if (this->start_->type()->integer_type() == NULL) + Numeric_constant nc; + unsigned long v; + if (this->start_->type()->integer_type() == NULL + && !this->start_->type()->is_error() + && (!this->start_->numeric_constant_value(&nc) + || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT)) this->report_error(_("index must be integer")); if (this->end_ != NULL && this->end_->type()->integer_type() == NULL - && !this->end_->is_nil_expression()) + && !this->end_->type()->is_error() + && !this->end_->is_nil_expression() + && !this->end_->is_error_expression() + && (!this->end_->numeric_constant_value(&nc) + || nc.to_unsigned_long(&v) == Numeric_constant::NC_UL_NOTINT)) this->report_error(_("slice end must be integer")); std::string sval; Index: gcc/go/gofrontend/expressions.h =================================================================== --- gcc/go/gofrontend/expressions.h (revision 203707) +++ gcc/go/gofrontend/expressions.h (working copy) @@ -1514,8 +1514,8 @@ class Func_expression : public Expressio closure() { return this->closure_; } - // Return a tree for the code for a function. - static tree + // Return a backend expression for the code of a function. + static Bexpression* get_code_pointer(Gogo*, Named_object* function, Location loc); protected: Index: gcc/go/gofrontend/backend.h =================================================================== --- gcc/go/gofrontend/backend.h (revision 203707) +++ gcc/go/gofrontend/backend.h (working copy) @@ -23,7 +23,7 @@ class Bexpression; // The backend representation of a statement. class Bstatement; -// The backend representation of a function definition. +// The backend representation of a function definition or declaration. class Bfunction; // The backend representation of a block. @@ -266,6 +266,11 @@ class Backend virtual Bexpression* convert_expression(Btype* type, Bexpression* expr, Location) = 0; + // Create an expression for the address of a function. This is used to + // get the address of the code for a function. + virtual Bexpression* + function_code_expression(Bfunction*, Location) = 0; + // Statements. // Create an error statement. This is used for cases which should @@ -498,6 +503,32 @@ class Backend // recover. virtual Bexpression* label_address(Blabel*, Location) = 0; + + // Functions. + + // Create an error function. This is used for cases which should + // not occur in a correct program, in order to keep the compilation + // going without crashing. + virtual Bfunction* + error_function() = 0; + + // Declare or define a function of FNTYPE. + // NAME is the Go name of the function. ASM_NAME, if not the empty string, is + // the name that should be used in the symbol table; this will be non-empty if + // a magic extern comment is used. + // IS_VISIBLE is true if this function should be visible outside of the + // current compilation unit. IS_DECLARATION is true if this is a function + // declaration rather than a definition; the function definition will be in + // another compilation unit. + // IS_INLINABLE is true if the function can be inlined. + // DISABLE_SPLIT_STACK is true if this function may not split the stack; this + // is used for the implementation of recover. + // IN_UNIQUE_SECTION is true if this function should be put into a unique + // location if possible; this is used for field tracking. + virtual Bfunction* + function(Btype* fntype, const std::string& name, const std::string& asm_name, + bool is_visible, bool is_declaration, bool is_inlinable, + bool disable_split_stack, bool in_unique_section, Location) = 0; }; // The backend interface has to define this function. @@ -517,5 +548,6 @@ extern tree expr_to_tree(Bexpression*); extern tree stat_to_tree(Bstatement*); extern tree block_to_tree(Bblock*); extern tree var_to_tree(Bvariable*); +extern tree function_to_tree(Bfunction*); #endif // !defined(GO_BACKEND_H) Index: gcc/go/gofrontend/gogo.h =================================================================== --- gcc/go/gofrontend/gogo.h (revision 203707) +++ gcc/go/gofrontend/gogo.h (working copy) @@ -48,6 +48,7 @@ class Bstatement; class Bblock; class Bvariable; class Blabel; +class Bfunction; // This file declares the basic classes used to hold the internal // representation of Go which is built by the parser. @@ -952,6 +953,15 @@ class Function this->nointerface_ = true; } + // Record that this function is a stub method created for an unnamed + // type. + void + set_is_unnamed_type_stub_method() + { + go_assert(this->is_method()); + this->is_unnamed_type_stub_method_ = true; + } + // Add a new field to the closure variable. void add_closure_field(Named_object* var, Location loc) @@ -1089,17 +1099,13 @@ class Function this->descriptor_ = descriptor; } - // Return the function's decl given an identifier. - tree - get_or_make_decl(Gogo*, Named_object*, tree id); + // Return the backend representation. + Bfunction* + get_or_make_decl(Gogo*, Named_object*); // Return the function's decl after it has been built. tree - get_decl() const - { - go_assert(this->fndecl_ != NULL); - return this->fndecl_; - } + get_decl() const; // Set the function decl to hold a tree of the function code. void @@ -1170,7 +1176,7 @@ class Function // The function descriptor, if any. Expression* descriptor_; // The function decl. - tree fndecl_; + Bfunction* fndecl_; // The defer stack variable. A pointer to this variable is used to // distinguish the defer stack for one function from another. This // is NULL unless we actually need a defer stack. @@ -1181,6 +1187,9 @@ class Function bool results_are_named_ : 1; // True if this method should not be included in the type descriptor. bool nointerface_ : 1; + // True if this function is a stub method created for an unnamed + // type. + bool is_unnamed_type_stub_method_ : 1; // True if this function calls the predeclared recover function. bool calls_recover_ : 1; // True if this a thunk built for a function which calls recover. @@ -1265,9 +1274,9 @@ class Function_declaration has_descriptor() const { return this->descriptor_ != NULL; } - // Return a decl for the function given an identifier. - tree - get_or_make_decl(Gogo*, Named_object*, tree id); + // Return a backend representation. + Bfunction* + get_or_make_decl(Gogo*, Named_object*); // If there is a descriptor, build it into the backend // representation. @@ -1290,7 +1299,7 @@ class Function_declaration // The function descriptor, if any. Expression* descriptor_; // The function decl if needed. - tree fndecl_; + Bfunction* fndecl_; }; // A variable. @@ -2181,8 +2190,8 @@ class Named_object Bvariable* get_backend_variable(Gogo*, Named_object* function); - // Return a tree for the external identifier for this object. - tree + // Return the external identifier for this object. + std::string get_id(Gogo*); // Return a tree representing this object. Index: gcc/go/gofrontend/parse.cc =================================================================== --- gcc/go/gofrontend/parse.cc (revision 203707) +++ gcc/go/gofrontend/parse.cc (working copy) @@ -744,6 +744,8 @@ Parse::signature(Typed_identifier* recei return NULL; Parse::Names names; + if (receiver != NULL) + names[receiver->name()] = receiver; if (params != NULL) this->check_signature_names(params, &names); if (results != NULL) Index: gcc/go/gofrontend/import.h =================================================================== --- gcc/go/gofrontend/import.h (revision 203707) +++ gcc/go/gofrontend/import.h (working copy) @@ -149,6 +149,11 @@ class Import location() const { return this->location_; } + // Return the package we are importing. + Package* + package() const + { return this->package_; } + // Return the next character. int peek_char() Index: gcc/go/gofrontend/runtime.cc =================================================================== --- gcc/go/gofrontend/runtime.cc (revision 203707) +++ gcc/go/gofrontend/runtime.cc (working copy) @@ -42,6 +42,8 @@ enum Runtime_function_type RFT_RUNE, // Go type float64, C type double. RFT_FLOAT64, + // Go type complex64, C type __complex float. + RFT_COMPLEX64, // Go type complex128, C type __complex double. RFT_COMPLEX128, // Go type string, C type struct __go_string. @@ -126,6 +128,10 @@ runtime_function_type(Runtime_function_t t = Type::lookup_float_type("float64"); break; + case RFT_COMPLEX64: + t = Type::lookup_complex_type("complex64"); + break; + case RFT_COMPLEX128: t = Type::lookup_complex_type("complex128"); break; @@ -216,6 +222,7 @@ convert_to_runtime_function_type(Runtime case RFT_UINTPTR: case RFT_RUNE: case RFT_FLOAT64: + case RFT_COMPLEX64: case RFT_COMPLEX128: case RFT_STRING: case RFT_POINTER: Index: gcc/go/gofrontend/lex.cc =================================================================== --- gcc/go/gofrontend/lex.cc (revision 203707) +++ gcc/go/gofrontend/lex.cc (working copy) @@ -873,7 +873,28 @@ Lex::gather_identifier() && (cc < 'a' || cc > 'z') && cc != '_' && (cc < '0' || cc > '9')) - break; + { + // Check for an invalid character here, as we get better + // error behaviour if we swallow them as part of the + // identifier we are building. + if ((cc >= ' ' && cc < 0x7f) + || cc == '\t' + || cc == '\r' + || cc == '\n') + break; + + this->lineoff_ = p - this->linebuf_; + error_at(this->location(), + "invalid character 0x%x in identifier", + cc); + if (!has_non_ascii_char) + { + buf.assign(pstart, p - pstart); + has_non_ascii_char = true; + } + if (!Lex::is_invalid_identifier(buf)) + buf.append("$INVALID$"); + } ++p; if (is_first) { Index: gcc/go/gofrontend/gogo-tree.cc =================================================================== --- gcc/go/gofrontend/gogo-tree.cc (revision 203707) +++ gcc/go/gofrontend/gogo-tree.cc (working copy) @@ -985,74 +985,6 @@ Gogo::write_globals() delete[] vec; } -// Get a tree for the identifier for a named object. - -tree -Named_object::get_id(Gogo* gogo) -{ - go_assert(!this->is_variable() && !this->is_result_variable()); - std::string decl_name; - if (this->is_function_declaration() - && !this->func_declaration_value()->asm_name().empty()) - decl_name = this->func_declaration_value()->asm_name(); - else if (this->is_type() - && Linemap::is_predeclared_location(this->type_value()->location())) - { - // We don't need the package name for builtin types. - decl_name = Gogo::unpack_hidden_name(this->name_); - } - else - { - std::string package_name; - 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)); - } - } - if (this->is_type()) - { - unsigned int index; - const Named_object* in_function = this->type_value()->in_function(&index); - if (in_function != NULL) - { - decl_name += '$' + Gogo::unpack_hidden_name(in_function->name()); - if (index > 0) - { - char buf[30]; - snprintf(buf, sizeof buf, "%u", index); - decl_name += '$'; - decl_name += buf; - } - } - } - return get_identifier_from_string(decl_name); -} - // Get a tree for a named object. tree @@ -1067,11 +999,6 @@ Named_object::get_tree(Gogo* gogo, Named return error_mark_node; } - tree name; - if (this->classification_ == NAMED_OBJECT_TYPE) - name = NULL_TREE; - else - name = this->get_id(gogo); tree decl; switch (this->classification_) { @@ -1099,6 +1026,7 @@ Named_object::get_tree(Gogo* gogo, Named decl = error_mark_node; else if (INTEGRAL_TYPE_P(TREE_TYPE(expr_tree))) { + tree name = get_identifier_from_string(this->get_id(gogo)); decl = build_decl(named_constant->location().gcc_location(), CONST_DECL, name, TREE_TYPE(expr_tree)); DECL_INITIAL(decl) = expr_tree; @@ -1161,7 +1089,7 @@ Named_object::get_tree(Gogo* gogo, Named case NAMED_OBJECT_FUNC: { Function* func = this->u_.func_value; - decl = func->get_or_make_decl(gogo, this, name); + decl = function_to_tree(func->get_or_make_decl(gogo, this)); if (decl != error_mark_node) { if (func->block() != NULL) @@ -1286,123 +1214,12 @@ Variable::get_init_block(Gogo* gogo, Nam return block_tree; } -// Get a tree for a function decl. +// Get the backend representation. -tree -Function::get_or_make_decl(Gogo* gogo, Named_object* no, tree id) +Bfunction* +Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no) { - if (this->fndecl_ == NULL_TREE) - { - tree functype = type_to_tree(this->type_->get_backend(gogo)); - - if (functype != error_mark_node) - { - // The type of a function comes back as a pointer to a - // struct whose first field is the function, but we want the - // real function type for a function declaration. - go_assert(POINTER_TYPE_P(functype) - && TREE_CODE(TREE_TYPE(functype)) == RECORD_TYPE); - functype = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(functype))); - go_assert(FUNCTION_POINTER_TYPE_P(functype)); - functype = TREE_TYPE(functype); - } - - if (functype == error_mark_node) - this->fndecl_ = error_mark_node; - else - { - tree decl = build_decl(this->location().gcc_location(), FUNCTION_DECL, - id, functype); - - this->fndecl_ = decl; - - if (no->package() != NULL) - ; - else if (this->enclosing_ != NULL || Gogo::is_thunk(no)) - ; - else if (Gogo::unpack_hidden_name(no->name()) == "init" - && !this->type_->is_method()) - ; - else if (Gogo::unpack_hidden_name(no->name()) == "main" - && gogo->is_main_package()) - TREE_PUBLIC(decl) = 1; - // Methods have to be public even if they are hidden because - // they can be pulled into type descriptors when using - // anonymous fields. - else if (!Gogo::is_hidden_name(no->name()) - || this->type_->is_method()) - { - TREE_PUBLIC(decl) = 1; - std::string pkgpath = gogo->pkgpath_symbol(); - if (this->type_->is_method() - && Gogo::is_hidden_name(no->name()) - && Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath()) - { - // This is a method we created for an unexported - // method of an imported embedded type. We need to - // use the pkgpath of the imported package to avoid - // a possible name collision. See bug478 for a test - // case. - pkgpath = Gogo::hidden_name_pkgpath(no->name()); - pkgpath = Gogo::pkgpath_for_symbol(pkgpath); - } - - std::string asm_name = pkgpath; - asm_name.append(1, '.'); - asm_name.append(Gogo::unpack_hidden_name(no->name())); - if (this->type_->is_method()) - { - asm_name.append(1, '.'); - Type* rtype = this->type_->receiver()->type(); - asm_name.append(rtype->mangled_name(gogo)); - } - SET_DECL_ASSEMBLER_NAME(decl, - get_identifier_from_string(asm_name)); - } - - // Why do we have to do this in the frontend? - tree restype = TREE_TYPE(functype); - tree resdecl = - build_decl(this->location().gcc_location(), RESULT_DECL, NULL_TREE, - restype); - DECL_ARTIFICIAL(resdecl) = 1; - DECL_IGNORED_P(resdecl) = 1; - DECL_CONTEXT(resdecl) = decl; - DECL_RESULT(decl) = resdecl; - - // If a function calls the predeclared recover function, we - // can't inline it, because recover behaves differently in a - // function passed directly to defer. If this is a recover - // thunk that we built to test whether a function can be - // recovered, we can't inline it, because that will mess up - // our return address comparison. - if (this->calls_recover_ || this->is_recover_thunk_) - DECL_UNINLINABLE(decl) = 1; - - // If this is a thunk created to call a function which calls - // the predeclared recover function, we need to disable - // stack splitting for the thunk. - if (this->is_recover_thunk_) - { - tree attr = get_identifier("__no_split_stack__"); - DECL_ATTRIBUTES(decl) = tree_cons(attr, NULL_TREE, NULL_TREE); - } - - if (this->in_unique_section_) - resolve_unique_section (decl, 0, 1); - - go_preserve_from_gc(decl); - } - } - return this->fndecl_; -} - -// Get a tree for a function declaration. - -tree -Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no, tree id) -{ - if (this->fndecl_ == NULL_TREE) + if (this->fndecl_ == NULL) { // Let Go code use an asm declaration to pick up a builtin // function. @@ -1412,56 +1229,44 @@ Function_declaration::get_or_make_decl(G builtin_functions.find(this->asm_name_); if (p != builtin_functions.end()) { - this->fndecl_ = p->second; + this->fndecl_ = tree_to_function(p->second); return this->fndecl_; } } - tree functype = type_to_tree(this->fntype_->get_backend(gogo)); + std::string asm_name; + if (this->asm_name_.empty()) + { + asm_name = (no->package() == NULL + ? gogo->pkgpath_symbol() + : no->package()->pkgpath_symbol()); + asm_name.append(1, '.'); + asm_name.append(Gogo::unpack_hidden_name(no->name())); + if (this->fntype_->is_method()) + { + asm_name.append(1, '.'); + Type* rtype = this->fntype_->receiver()->type(); + asm_name.append(rtype->mangled_name(gogo)); + } + } + + Btype* functype = this->fntype_->get_backend_fntype(gogo); + this->fndecl_ = + gogo->backend()->function(functype, no->get_id(gogo), asm_name, + true, true, true, false, false, + this->location()); + } - if (functype != error_mark_node) - { - // The type of a function comes back as a pointer to a - // struct whose first field is the function, but we want the - // real function type for a function declaration. - go_assert(POINTER_TYPE_P(functype) - && TREE_CODE(TREE_TYPE(functype)) == RECORD_TYPE); - functype = TREE_TYPE(TYPE_FIELDS(TREE_TYPE(functype))); - go_assert(FUNCTION_POINTER_TYPE_P(functype)); - functype = TREE_TYPE(functype); - } + return this->fndecl_; +} - tree decl; - if (functype == error_mark_node) - decl = error_mark_node; - else - { - decl = build_decl(this->location().gcc_location(), FUNCTION_DECL, id, - functype); - TREE_PUBLIC(decl) = 1; - DECL_EXTERNAL(decl) = 1; +// Return the function's decl after it has been built. - if (this->asm_name_.empty()) - { - std::string asm_name = (no->package() == NULL - ? gogo->pkgpath_symbol() - : no->package()->pkgpath_symbol()); - asm_name.append(1, '.'); - asm_name.append(Gogo::unpack_hidden_name(no->name())); - if (this->fntype_->is_method()) - { - asm_name.append(1, '.'); - Type* rtype = this->fntype_->receiver()->type(); - asm_name.append(rtype->mangled_name(gogo)); - } - SET_DECL_ASSEMBLER_NAME(decl, - get_identifier_from_string(asm_name)); - } - } - this->fndecl_ = decl; - go_preserve_from_gc(decl); - } - return this->fndecl_; +tree +Function::get_decl() const +{ + go_assert(this->fndecl_ != NULL); + return function_to_tree(this->fndecl_); } // We always pass the receiver to a method as a pointer. If the @@ -1558,7 +1363,7 @@ Function::copy_parm_to_heap(Gogo* gogo, void Function::build_tree(Gogo* gogo, Named_object* named_function) { - tree fndecl = this->fndecl_; + tree fndecl = this->get_decl(); go_assert(fndecl != NULL_TREE); tree params = NULL_TREE; @@ -1796,7 +1601,7 @@ Function::build_defer_wrapper(Gogo* gogo set = NULL_TREE; else set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node, - DECL_RESULT(this->fndecl_), retval); + DECL_RESULT(this->get_decl()), retval); tree ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR, void_type_node, set); append_to_statement_list(ret_stmt, &stmt_list); @@ -1851,7 +1656,7 @@ Function::build_defer_wrapper(Gogo* gogo retval = this->return_value(gogo, named_function, end_loc, &stmt_list); set = fold_build2_loc(end_loc.gcc_location(), MODIFY_EXPR, void_type_node, - DECL_RESULT(this->fndecl_), retval); + DECL_RESULT(this->get_decl()), retval); ret_stmt = fold_build1_loc(end_loc.gcc_location(), RETURN_EXPR, void_type_node, set); @@ -1869,7 +1674,7 @@ Function::build_defer_wrapper(Gogo* gogo *fini = stmt_list; } -// Return the value to assign to DECL_RESULT(this->fndecl_). This may +// Return the value to assign to DECL_RESULT(this->get_decl()). This may // also add statements to STMT_LIST, which need to be executed before // the assignment. This is used for a return statement with no // explicit values. @@ -1902,7 +1707,7 @@ Function::return_value(Gogo* gogo, Named } else { - tree rettype = TREE_TYPE(DECL_RESULT(this->fndecl_)); + tree rettype = TREE_TYPE(DECL_RESULT(this->get_decl())); retval = create_tmp_var(rettype, "RESULT"); tree field = TYPE_FIELDS(rettype); int index = 0; @@ -2323,18 +2128,14 @@ Gogo::interface_method_table_for_type(co go_assert(m != NULL); Named_object* no = m->named_object(); - - tree fnid = no->get_id(this); - - tree fndecl; + Bfunction* bf; if (no->is_function()) - fndecl = no->func_value()->get_or_make_decl(this, no, fnid); + bf = no->func_value()->get_or_make_decl(this, no); else if (no->is_function_declaration()) - fndecl = no->func_declaration_value()->get_or_make_decl(this, no, - fnid); + bf = no->func_declaration_value()->get_or_make_decl(this, no); else go_unreachable(); - fndecl = build_fold_addr_expr(fndecl); + tree fndecl = build_fold_addr_expr(function_to_tree(bf)); elt = pointers->quick_push(empty); elt->index = size_int(i); @@ -2353,10 +2154,11 @@ Gogo::interface_method_table_for_type(co TREE_CONSTANT(decl) = 1; DECL_INITIAL(decl) = constructor; - // If the interface type has hidden methods, then this is the only - // definition of the table. Otherwise it is a comdat table which - // may be defined in multiple packages. - if (has_hidden_methods) + // If the interface type has hidden methods, and the table is for a + // named type, then this is the only definition of the table. + // Otherwise it is a comdat table which may be defined in multiple + // packages. + if (has_hidden_methods && type->named_type() != NULL) TREE_PUBLIC(decl) = 1; else { Index: gcc/go/gofrontend/gogo.cc =================================================================== --- gcc/go/gofrontend/gogo.cc (revision 203707) +++ gcc/go/gofrontend/gogo.cc (working copy) @@ -3320,7 +3320,8 @@ Function::Function(Function_type* type, closure_var_(NULL), block_(block), location_(location), labels_(), local_type_count_(0), descriptor_(NULL), fndecl_(NULL), defer_stack_(NULL), is_sink_(false), results_are_named_(false), nointerface_(false), - calls_recover_(false), is_recover_thunk_(false), has_recover_thunk_(false), + is_unnamed_type_stub_method_(false), calls_recover_(false), + is_recover_thunk_(false), has_recover_thunk_(false), in_unique_section_(false) { } @@ -3819,6 +3820,81 @@ Function::import_func(Import* imp, std:: *presults = results; } +// Get the backend representation. + +Bfunction* +Function::get_or_make_decl(Gogo* gogo, Named_object* no) +{ + if (this->fndecl_ == NULL) + { + std::string asm_name; + bool is_visible = false; + if (no->package() != NULL) + ; + else if (this->enclosing_ != NULL || Gogo::is_thunk(no)) + ; + else if (Gogo::unpack_hidden_name(no->name()) == "init" + && !this->type_->is_method()) + ; + else if (Gogo::unpack_hidden_name(no->name()) == "main" + && gogo->is_main_package()) + is_visible = true; + // Methods have to be public even if they are hidden because + // they can be pulled into type descriptors when using + // anonymous fields. + else if (!Gogo::is_hidden_name(no->name()) + || this->type_->is_method()) + { + if (!this->is_unnamed_type_stub_method_) + is_visible = true; + std::string pkgpath = gogo->pkgpath_symbol(); + if (this->type_->is_method() + && Gogo::is_hidden_name(no->name()) + && Gogo::hidden_name_pkgpath(no->name()) != gogo->pkgpath()) + { + // This is a method we created for an unexported + // method of an imported embedded type. We need to + // use the pkgpath of the imported package to avoid + // a possible name collision. See bug478 for a test + // case. + pkgpath = Gogo::hidden_name_pkgpath(no->name()); + pkgpath = Gogo::pkgpath_for_symbol(pkgpath); + } + + asm_name = pkgpath; + asm_name.append(1, '.'); + asm_name.append(Gogo::unpack_hidden_name(no->name())); + if (this->type_->is_method()) + { + asm_name.append(1, '.'); + Type* rtype = this->type_->receiver()->type(); + asm_name.append(rtype->mangled_name(gogo)); + } + } + + // If a function calls the predeclared recover function, we + // can't inline it, because recover behaves differently in a + // function passed directly to defer. If this is a recover + // thunk that we built to test whether a function can be + // recovered, we can't inline it, because that will mess up + // our return address comparison. + bool is_inlinable = !(this->calls_recover_ || this->is_recover_thunk_); + + // If this is a thunk created to call a function which calls + // the predeclared recover function, we need to disable + // stack splitting for the thunk. + bool disable_split_stack = this->is_recover_thunk_; + + Btype* functype = this->type_->get_backend_fntype(gogo); + this->fndecl_ = + gogo->backend()->function(functype, no->get_id(gogo), asm_name, + is_visible, false, is_inlinable, + disable_split_stack, + this->in_unique_section_, this->location()); + } + return this->fndecl_; +} + // Class Block. Block::Block(Block* enclosing, Location location) @@ -5110,6 +5186,75 @@ Named_object::get_backend_variable(Gogo* 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()); + std::string decl_name; + if (this->is_function_declaration() + && !this->func_declaration_value()->asm_name().empty()) + decl_name = this->func_declaration_value()->asm_name(); + else if (this->is_type() + && Linemap::is_predeclared_location(this->type_value()->location())) + { + // We don't need the package name for builtin types. + decl_name = Gogo::unpack_hidden_name(this->name_); + } + else + { + std::string package_name; + 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)); + } + } + if (this->is_type()) + { + unsigned int index; + const Named_object* in_function = this->type_value()->in_function(&index); + if (in_function != NULL) + { + decl_name += '$' + Gogo::unpack_hidden_name(in_function->name()); + if (index > 0) + { + char buf[30]; + snprintf(buf, sizeof buf, "%u", index); + decl_name += '$'; + decl_name += buf; + } + } + } + return decl_name; +} + // Class Bindings. Bindings::Bindings(Bindings* enclosing) Index: gcc/go/gofrontend/runtime.def =================================================================== --- gcc/go/gofrontend/runtime.def (revision 203707) +++ gcc/go/gofrontend/runtime.def (working copy) @@ -68,6 +68,12 @@ DEF_GO_RUNTIME(STRING_TO_INT_ARRAY, "__g P1(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(MAKESLICE1, "__go_make_slice1", P2(TYPE, UINTPTR), R1(SLICE)) DEF_GO_RUNTIME(MAKESLICE2, "__go_make_slice2", P3(TYPE, UINTPTR, UINTPTR), Index: gcc/go/gofrontend/types.cc =================================================================== --- gcc/go/gofrontend/types.cc (revision 203707) +++ gcc/go/gofrontend/types.cc (working copy) @@ -3383,6 +3383,68 @@ Function_type::do_hash_for_method(Gogo* // Get the backend representation for a function type. Btype* +Function_type::get_backend_fntype(Gogo* gogo) +{ + if (this->fnbtype_ == NULL) + { + Backend::Btyped_identifier breceiver; + if (this->receiver_ != NULL) + { + breceiver.name = Gogo::unpack_hidden_name(this->receiver_->name()); + + // We always pass the address of the receiver parameter, in + // order to make interface calls work with unknown types. + Type* rtype = this->receiver_->type(); + if (rtype->points_to() == NULL) + rtype = Type::make_pointer_type(rtype); + breceiver.btype = rtype->get_backend(gogo); + breceiver.location = this->receiver_->location(); + } + + std::vector<Backend::Btyped_identifier> bparameters; + if (this->parameters_ != NULL) + { + bparameters.resize(this->parameters_->size()); + size_t i = 0; + for (Typed_identifier_list::const_iterator p = + this->parameters_->begin(); p != this->parameters_->end(); + ++p, ++i) + { + bparameters[i].name = Gogo::unpack_hidden_name(p->name()); + bparameters[i].btype = p->type()->get_backend(gogo); + bparameters[i].location = p->location(); + } + go_assert(i == bparameters.size()); + } + + std::vector<Backend::Btyped_identifier> bresults; + if (this->results_ != NULL) + { + bresults.resize(this->results_->size()); + size_t i = 0; + for (Typed_identifier_list::const_iterator p = + this->results_->begin(); p != this->results_->end(); + ++p, ++i) + { + bresults[i].name = Gogo::unpack_hidden_name(p->name()); + bresults[i].btype = p->type()->get_backend(gogo); + bresults[i].location = p->location(); + } + go_assert(i == bresults.size()); + } + + this->fnbtype_ = gogo->backend()->function_type(breceiver, bparameters, + bresults, + this->location()); + + } + + return this->fnbtype_; +} + +// Get the backend representation for a Go function type. + +Btype* Function_type::do_get_backend(Gogo* gogo) { // When we do anything with a function value other than call it, it @@ -3395,57 +3457,9 @@ Function_type::do_get_backend(Gogo* gogo gogo->backend()->placeholder_struct_type("__go_descriptor", loc); Btype* ptr_struct_type = gogo->backend()->pointer_type(struct_type); - Backend::Btyped_identifier breceiver; - if (this->receiver_ != NULL) - { - breceiver.name = Gogo::unpack_hidden_name(this->receiver_->name()); - - // We always pass the address of the receiver parameter, in - // order to make interface calls work with unknown types. - Type* rtype = this->receiver_->type(); - if (rtype->points_to() == NULL) - rtype = Type::make_pointer_type(rtype); - breceiver.btype = rtype->get_backend(gogo); - breceiver.location = this->receiver_->location(); - } - - std::vector<Backend::Btyped_identifier> bparameters; - if (this->parameters_ != NULL) - { - bparameters.resize(this->parameters_->size()); - size_t i = 0; - for (Typed_identifier_list::const_iterator p = this->parameters_->begin(); - p != this->parameters_->end(); - ++p, ++i) - { - bparameters[i].name = Gogo::unpack_hidden_name(p->name()); - bparameters[i].btype = p->type()->get_backend(gogo); - bparameters[i].location = p->location(); - } - go_assert(i == bparameters.size()); - } - - std::vector<Backend::Btyped_identifier> bresults; - if (this->results_ != NULL) - { - bresults.resize(this->results_->size()); - size_t i = 0; - for (Typed_identifier_list::const_iterator p = this->results_->begin(); - p != this->results_->end(); - ++p, ++i) - { - bresults[i].name = Gogo::unpack_hidden_name(p->name()); - bresults[i].btype = p->type()->get_backend(gogo); - bresults[i].location = p->location(); - } - go_assert(i == bresults.size()); - } - - Btype* fntype = gogo->backend()->function_type(breceiver, bparameters, - bresults, loc); std::vector<Backend::Btyped_identifier> fields(1); fields[0].name = "code"; - fields[0].btype = fntype; + fields[0].btype = this->get_backend_fntype(gogo); fields[0].location = loc; if (!gogo->backend()->set_placeholder_struct_type(struct_type, fields)) return gogo->backend()->error_type(); @@ -4264,12 +4278,7 @@ Struct_type::do_verify() ++p) { Type* t = p->type(); - if (t->is_undefined()) - { - error_at(p->location(), "struct field type is incomplete"); - p->set_type(Type::make_error_type()); - } - else if (p->is_anonymous()) + if (p->is_anonymous()) { if (t->named_type() != NULL && t->points_to() != NULL) { @@ -5249,6 +5258,19 @@ Struct_type::do_import(Import* imp) } Type* ftype = imp->read_type(); + // We don't pack the names of builtin types. In + // Struct_field::is_field_name we cope with a hack. Now we + // need another hack so that we don't accidentally think + // that an embedded builtin type is accessible from another + // package (we know that all the builtin types are not + // exported). + if (name.empty() && ftype->deref()->named_type() != NULL) + { + const std::string fn(ftype->deref()->named_type()->name()); + if (fn[0] >= 'a' && fn[0] <= 'z') + name = '.' + imp->package()->pkgpath() + '.' + fn; + } + Struct_field sf(Typed_identifier(name, ftype, imp->location())); if (imp->peek_char() == ' ') @@ -9022,6 +9044,8 @@ Type::build_stub_methods(Gogo* gogo, con fntype->is_varargs(), location); gogo->finish_function(fntype->location()); + if (type->named_type() == NULL && stub->is_function()) + stub->func_value()->set_is_unnamed_type_stub_method(); if (m->nointerface() && stub->is_function()) stub->func_value()->set_nointerface(); } Index: gcc/go/gofrontend/types.h =================================================================== --- gcc/go/gofrontend/types.h (revision 203707) +++ gcc/go/gofrontend/types.h (working copy) @@ -1717,7 +1717,8 @@ class Function_type : public Type Typed_identifier_list* results, Location location) : Type(TYPE_FUNCTION), receiver_(receiver), parameters_(parameters), results_(results), - location_(location), is_varargs_(false), is_builtin_(false) + location_(location), is_varargs_(false), is_builtin_(false), + fnbtype_(NULL) { } // Get the receiver. @@ -1798,6 +1799,11 @@ class Function_type : public Type static Type* make_function_type_descriptor_type(); + // Return the backend representation of this function type. This is used + // as the real type of a backend function declaration or defintion. + Btype* + get_backend_fntype(Gogo*); + protected: int do_traverse(Traverse*); @@ -1851,6 +1857,9 @@ class Function_type : public Type // Whether this is a special builtin function which can not simply // be called. This is used for len, cap, etc. bool is_builtin_; + // The backend representation of this type for backend function + // declarations and definitions. + Btype* fnbtype_; }; // The type of a pointer.