diff options
Diffstat (limited to 'gcc-4.8/gcc/go')
-rw-r--r-- | gcc-4.8/gcc/go/ChangeLog | 23 | ||||
-rw-r--r-- | gcc-4.8/gcc/go/go-gcc.cc | 87 | ||||
-rw-r--r-- | gcc-4.8/gcc/go/go-lang.c | 4 | ||||
-rw-r--r-- | gcc-4.8/gcc/go/gofrontend/backend.h | 34 | ||||
-rw-r--r-- | gcc-4.8/gcc/go/gofrontend/expressions.cc | 151 | ||||
-rw-r--r-- | gcc-4.8/gcc/go/gofrontend/expressions.h | 4 | ||||
-rw-r--r-- | gcc-4.8/gcc/go/gofrontend/gogo-tree.cc | 276 | ||||
-rw-r--r-- | gcc-4.8/gcc/go/gofrontend/gogo.cc | 172 | ||||
-rw-r--r-- | gcc-4.8/gcc/go/gofrontend/gogo.h | 39 | ||||
-rw-r--r-- | gcc-4.8/gcc/go/gofrontend/import.h | 5 | ||||
-rw-r--r-- | gcc-4.8/gcc/go/gofrontend/lex.cc | 21 | ||||
-rw-r--r-- | gcc-4.8/gcc/go/gofrontend/parse.cc | 2 | ||||
-rw-r--r-- | gcc-4.8/gcc/go/gofrontend/runtime.cc | 7 | ||||
-rw-r--r-- | gcc-4.8/gcc/go/gofrontend/runtime.def | 6 | ||||
-rw-r--r-- | gcc-4.8/gcc/go/gofrontend/types.cc | 255 | ||||
-rw-r--r-- | gcc-4.8/gcc/go/gofrontend/types.h | 37 |
16 files changed, 779 insertions, 344 deletions
diff --git a/gcc-4.8/gcc/go/ChangeLog b/gcc-4.8/gcc/go/ChangeLog index 6c1504db5..e5860d7ff 100644 --- a/gcc-4.8/gcc/go/ChangeLog +++ b/gcc-4.8/gcc/go/ChangeLog @@ -1,3 +1,26 @@ +2014-05-22 Release Manager + + * GCC 4.8.3 released. + +2013-12-11 Ian Lance Taylor <iant@google.com> + + * go-lang.c (go_langhook_post_options): Disable sibling calls by + default. + +2013-10-16 Ian Lance Taylor <iant@google.com> + + Bring in from mainline: + + 2013-10-11 Chris Manghane <cmang@google.com> + * go-gcc.cc (Gcc_backend::function_code_expression): New + function. + + 2013-10-10 Chris Manghane <cmang@google.com> + * go-gcc.cc (Backend::error_function): New function. + (Backend::function): New function. + (Backend::make_function): New function. + (function_to_tree): New function. + 2013-10-16 Release Manager * GCC 4.8.2 released. diff --git a/gcc-4.8/gcc/go/go-gcc.cc b/gcc-4.8/gcc/go/go-gcc.cc index fcfd41b34..81e9ad186 100644 --- a/gcc-4.8/gcc/go/go-gcc.cc +++ b/gcc-4.8/gcc/go/go-gcc.cc @@ -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* type, Bexpression* expr, Location) 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, Location location) 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(); +} diff --git a/gcc-4.8/gcc/go/go-lang.c b/gcc-4.8/gcc/go/go-lang.c index 659cd8ef7..7e92deb92 100644 --- a/gcc-4.8/gcc/go/go-lang.c +++ b/gcc-4.8/gcc/go/go-lang.c @@ -269,6 +269,10 @@ go_langhook_post_options (const char **pfilename ATTRIBUTE_UNUSED) if (flag_excess_precision_cmdline == EXCESS_PRECISION_DEFAULT) flag_excess_precision_cmdline = EXCESS_PRECISION_STANDARD; + /* Tail call optimizations can confuse uses of runtime.Callers. */ + if (!global_options_set.x_flag_optimize_sibling_calls) + global_options.x_flag_optimize_sibling_calls = 0; + /* Returning false means that the backend should be used. */ return false; } diff --git a/gcc-4.8/gcc/go/gofrontend/backend.h b/gcc-4.8/gcc/go/gofrontend/backend.h index fa3e3cc68..ca997f08a 100644 --- a/gcc-4.8/gcc/go/gofrontend/backend.h +++ b/gcc-4.8/gcc/go/gofrontend/backend.h @@ -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) diff --git a/gcc-4.8/gcc/go/gofrontend/expressions.cc b/gcc-4.8/gcc/go/gofrontend/expressions.cc index d5e3a6762..3e54084ff 100644 --- a/gcc-4.8/gcc/go/gofrontend/expressions.cc +++ b/gcc-4.8/gcc/go/gofrontend/expressions.cc @@ -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* gogo, Named_object* no, Location loc) 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 : public Expression tree Func_code_reference_expression::do_get_tree(Translate_context* context) { - return Func_expression::get_code_pointer(context->gogo(), this->function_, + 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 : public Expression 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(Gogo*, Named_object*, 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(const Type_context* context) 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_context* context) 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* gogo, Named_object* function, 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* gogo, Named_object* function, // 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(Expression* e, bool is_length) 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(Expression* e, bool is_length) 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(Expression** pexpr) 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_context* context) } 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_context* context) 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_type(const Type_context*) 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; diff --git a/gcc-4.8/gcc/go/gofrontend/expressions.h b/gcc-4.8/gcc/go/gofrontend/expressions.h index bc7a25f76..35bfcfe8e 100644 --- a/gcc-4.8/gcc/go/gofrontend/expressions.h +++ b/gcc-4.8/gcc/go/gofrontend/expressions.h @@ -1514,8 +1514,8 @@ class Func_expression : public Expression 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: diff --git a/gcc-4.8/gcc/go/gofrontend/gogo-tree.cc b/gcc-4.8/gcc/go/gofrontend/gogo-tree.cc index a95f29015..ef6c842c0 100644 --- a/gcc-4.8/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc-4.8/gcc/go/gofrontend/gogo-tree.cc @@ -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_object* function) 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_object* function) 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_object* function) 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, Named_object* function, tree var_decl) 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,38 +1229,15 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no, tree id) 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)); - - 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); - } - - 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; - + std::string asm_name; if (this->asm_name_.empty()) { - std::string asm_name = (no->package() == NULL + asm_name = (no->package() == NULL ? gogo->pkgpath_symbol() : no->package()->pkgpath_symbol()); asm_name.append(1, '.'); @@ -1454,16 +1248,27 @@ Function_declaration::get_or_make_decl(Gogo* gogo, Named_object* no, tree id) Type* rtype = this->fntype_->receiver()->type(); asm_name.append(rtype->mangled_name(gogo)); } - SET_DECL_ASSEMBLER_NAME(decl, - get_identifier_from_string(asm_name)); } + + 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()); } - this->fndecl_ = decl; - go_preserve_from_gc(decl); - } + return this->fndecl_; } +// Return the function's decl after it has been built. + +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 // receiver is actually declared as a non-pointer type, then we copy // the value into a local variable, so that it has the right type. In @@ -1558,7 +1363,7 @@ Function::copy_parm_to_heap(Gogo* gogo, Named_object* no, tree var_decl) 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, Named_object* named_function, 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, Named_object* named_function, 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, Named_object* named_function, *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_object* named_function, } 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(const Interface_type* interface, 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(const Interface_type* interface, 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 { diff --git a/gcc-4.8/gcc/go/gofrontend/gogo.cc b/gcc-4.8/gcc/go/gofrontend/gogo.cc index 9f918cb81..e16b0d3a5 100644 --- a/gcc-4.8/gcc/go/gofrontend/gogo.cc +++ b/gcc-4.8/gcc/go/gofrontend/gogo.cc @@ -2822,7 +2822,10 @@ Build_recover_thunks::function(Named_object* orig_no) if (orig_fntype->is_varargs()) new_fntype->set_is_varargs(); - std::string name = orig_no->name() + "$recover"; + std::string name = orig_no->name(); + if (orig_fntype->is_method()) + name += "$" + orig_fntype->receiver()->type()->mangled_name(gogo); + name += "$recover"; Named_object *new_no = gogo->start_function(name, new_fntype, false, location); Function *new_func = new_no->func_value(); @@ -2916,7 +2919,25 @@ Build_recover_thunks::function(Named_object* orig_no) && !orig_rec_no->var_value()->is_receiver()); orig_rec_no->var_value()->set_is_receiver(); - const std::string& new_receiver_name(orig_fntype->receiver()->name()); + std::string new_receiver_name(orig_fntype->receiver()->name()); + if (new_receiver_name.empty()) + { + // Find the receiver. It was named "r.NNN" in + // Gogo::start_function. + for (Bindings::const_definitions_iterator p = + new_bindings->begin_definitions(); + p != new_bindings->end_definitions(); + ++p) + { + const std::string& pname((*p)->name()); + if (pname[0] == 'r' && pname[1] == '.') + { + new_receiver_name = pname; + break; + } + } + go_assert(!new_receiver_name.empty()); + } Named_object* new_rec_no = new_bindings->lookup_local(new_receiver_name); if (new_rec_no == NULL) go_assert(saw_errors()); @@ -3320,7 +3341,8 @@ Function::Function(Function_type* type, Function* enclosing, Block* block, 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 +3841,81 @@ Function::import_func(Import* imp, std::string* pname, *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 +5207,75 @@ 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()); + 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) diff --git a/gcc-4.8/gcc/go/gofrontend/gogo.h b/gcc-4.8/gcc/go/gofrontend/gogo.h index 23968d4a1..31b258d62 100644 --- a/gcc-4.8/gcc/go/gofrontend/gogo.h +++ b/gcc-4.8/gcc/go/gofrontend/gogo.h @@ -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. diff --git a/gcc-4.8/gcc/go/gofrontend/import.h b/gcc-4.8/gcc/go/gofrontend/import.h index c6844cda8..9917937e4 100644 --- a/gcc-4.8/gcc/go/gofrontend/import.h +++ b/gcc-4.8/gcc/go/gofrontend/import.h @@ -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() diff --git a/gcc-4.8/gcc/go/gofrontend/lex.cc b/gcc-4.8/gcc/go/gofrontend/lex.cc index 22a1f6e2a..d03c4bde2 100644 --- a/gcc-4.8/gcc/go/gofrontend/lex.cc +++ b/gcc-4.8/gcc/go/gofrontend/lex.cc @@ -873,7 +873,28 @@ Lex::gather_identifier() && (cc < 'a' || cc > 'z') && cc != '_' && (cc < '0' || cc > '9')) + { + // 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) { diff --git a/gcc-4.8/gcc/go/gofrontend/parse.cc b/gcc-4.8/gcc/go/gofrontend/parse.cc index 498125bb2..9c7d8277e 100644 --- a/gcc-4.8/gcc/go/gofrontend/parse.cc +++ b/gcc-4.8/gcc/go/gofrontend/parse.cc @@ -744,6 +744,8 @@ Parse::signature(Typed_identifier* receiver, Location location) return NULL; Parse::Names names; + if (receiver != NULL) + names[receiver->name()] = receiver; if (params != NULL) this->check_signature_names(params, &names); if (results != NULL) diff --git a/gcc-4.8/gcc/go/gofrontend/runtime.cc b/gcc-4.8/gcc/go/gofrontend/runtime.cc index ecc508d0d..3b0f18807 100644 --- a/gcc-4.8/gcc/go/gofrontend/runtime.cc +++ b/gcc-4.8/gcc/go/gofrontend/runtime.cc @@ -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_type bft) 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_function_type bft, Expression* e, case RFT_UINTPTR: case RFT_RUNE: case RFT_FLOAT64: + case RFT_COMPLEX64: case RFT_COMPLEX128: case RFT_STRING: case RFT_POINTER: diff --git a/gcc-4.8/gcc/go/gofrontend/runtime.def b/gcc-4.8/gcc/go/gofrontend/runtime.def index 0d3fd3c43..a303a5041 100644 --- a/gcc-4.8/gcc/go/gofrontend/runtime.def +++ b/gcc-4.8/gcc/go/gofrontend/runtime.def @@ -68,6 +68,12 @@ DEF_GO_RUNTIME(STRING_TO_INT_ARRAY, "__go_string_to_int_array", 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), diff --git a/gcc-4.8/gcc/go/gofrontend/types.cc b/gcc-4.8/gcc/go/gofrontend/types.cc index e1d68e743..9bc356a73 100644 --- a/gcc-4.8/gcc/go/gofrontend/types.cc +++ b/gcc-4.8/gcc/go/gofrontend/types.cc @@ -1834,7 +1834,9 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, bloc); gogo->start_block(bloc); - if (this->struct_type() != NULL) + if (name != NULL && name->real_type()->named_type() != NULL) + this->write_named_hash(gogo, name, hash_fntype, equal_fntype); + else if (this->struct_type() != NULL) this->struct_type()->write_hash_function(gogo, name, hash_fntype, equal_fntype); else if (this->array_type() != NULL) @@ -1852,7 +1854,9 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, false, bloc); gogo->start_block(bloc); - if (this->struct_type() != NULL) + if (name != NULL && name->real_type()->named_type() != NULL) + this->write_named_equal(gogo, name); + else if (this->struct_type() != NULL) this->struct_type()->write_equal_function(gogo, name); else if (this->array_type() != NULL) this->array_type()->write_equal_function(gogo, name); @@ -1865,6 +1869,100 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, gogo->finish_function(bloc); } +// Write a hash function that simply calls the hash function for a +// named type. This is used when one named type is defined as +// another. This ensures that this case works when the other named +// type is defined in another package and relies on calling hash +// functions defined only in that package. + +void +Type::write_named_hash(Gogo* gogo, Named_type* name, + Function_type* hash_fntype, Function_type* equal_fntype) +{ + Location bloc = Linemap::predeclared_location(); + + Named_type* base_type = name->real_type()->named_type(); + go_assert(base_type != NULL); + + // The pointer to the type we are going to hash. This is an + // unsafe.Pointer. + Named_object* key_arg = gogo->lookup("key", NULL); + go_assert(key_arg != NULL); + + // The size of the type we are going to hash. + Named_object* keysz_arg = gogo->lookup("key_size", NULL); + go_assert(keysz_arg != NULL); + + Named_object* hash_fn; + Named_object* equal_fn; + name->real_type()->type_functions(gogo, base_type, hash_fntype, equal_fntype, + &hash_fn, &equal_fn); + + // Call the hash function for the base type. + Expression* key_ref = Expression::make_var_reference(key_arg, bloc); + Expression* keysz_ref = Expression::make_var_reference(keysz_arg, bloc); + Expression_list* args = new Expression_list(); + args->push_back(key_ref); + args->push_back(keysz_ref); + Expression* func = Expression::make_func_reference(hash_fn, NULL, bloc); + Expression* call = Expression::make_call(func, args, false, bloc); + + // Return the hash of the base type. + Expression_list* vals = new Expression_list(); + vals->push_back(call); + Statement* s = Statement::make_return_statement(vals, bloc); + gogo->add_statement(s); +} + +// Write an equality function that simply calls the equality function +// for a named type. This is used when one named type is defined as +// another. This ensures that this case works when the other named +// type is defined in another package and relies on calling equality +// functions defined only in that package. + +void +Type::write_named_equal(Gogo* gogo, Named_type* name) +{ + Location bloc = Linemap::predeclared_location(); + + // The pointers to the types we are going to compare. These have + // type unsafe.Pointer. + Named_object* key1_arg = gogo->lookup("key1", NULL); + Named_object* key2_arg = gogo->lookup("key2", NULL); + go_assert(key1_arg != NULL && key2_arg != NULL); + + Named_type* base_type = name->real_type()->named_type(); + go_assert(base_type != NULL); + + // Build temporaries with the base type. + Type* pt = Type::make_pointer_type(base_type); + + Expression* ref = Expression::make_var_reference(key1_arg, bloc); + ref = Expression::make_cast(pt, ref, bloc); + Temporary_statement* p1 = Statement::make_temporary(pt, ref, bloc); + gogo->add_statement(p1); + + ref = Expression::make_var_reference(key2_arg, bloc); + ref = Expression::make_cast(pt, ref, bloc); + Temporary_statement* p2 = Statement::make_temporary(pt, ref, bloc); + gogo->add_statement(p2); + + // Compare the values for equality. + Expression* t1 = Expression::make_temporary_reference(p1, bloc); + t1 = Expression::make_unary(OPERATOR_MULT, t1, bloc); + + Expression* t2 = Expression::make_temporary_reference(p2, bloc); + t2 = Expression::make_unary(OPERATOR_MULT, t2, bloc); + + Expression* cond = Expression::make_binary(OPERATOR_EQEQ, t1, t2, bloc); + + // Return the equality comparison. + Expression_list* vals = new Expression_list(); + vals->push_back(cond); + Statement* s = Statement::make_return_statement(vals, bloc); + gogo->add_statement(s); +} + // Return a composite literal for the type descriptor for a plain type // of kind RUNTIME_TYPE_KIND named NAME. @@ -2164,26 +2262,9 @@ Type::method_constructor(Gogo*, Type* method_type, ++p; go_assert(p->is_field_name("typ")); - if (!only_value_methods && m->is_value_method()) - { - // This is a value method on a pointer type. Change the type of - // the method to use a pointer receiver. The implementation - // always uses a pointer receiver anyhow. - Type* rtype = mtype->receiver()->type(); - Type* prtype = Type::make_pointer_type(rtype); - Typed_identifier* receiver = - new Typed_identifier(mtype->receiver()->name(), prtype, - mtype->receiver()->location()); - mtype = Type::make_function_type(receiver, - (mtype->parameters() == NULL - ? NULL - : mtype->parameters()->copy()), - (mtype->results() == NULL - ? NULL - : mtype->results()->copy()), - mtype->location()); - } - vals->push_back(Expression::make_type_descriptor(mtype, bloc)); + bool want_pointer_receiver = !only_value_methods && m->is_value_method(); + nonmethod_type = mtype->copy_with_receiver_as_param(want_pointer_receiver); + vals->push_back(Expression::make_type_descriptor(nonmethod_type, bloc)); ++p; go_assert(p->is_field_name("tfn")); @@ -3383,18 +3464,10 @@ Function_type::do_hash_for_method(Gogo* gogo) const // Get the backend representation for a function type. Btype* -Function_type::do_get_backend(Gogo* gogo) +Function_type::get_backend_fntype(Gogo* gogo) { - // When we do anything with a function value other than call it, it - // is represented as a pointer to a struct whose first field is the - // actual function. So that is what we return as the type of a Go - // function. - - Location loc = this->location(); - Btype* struct_type = - gogo->backend()->placeholder_struct_type("__go_descriptor", loc); - Btype* ptr_struct_type = gogo->backend()->pointer_type(struct_type); - + if (this->fnbtype_ == NULL) + { Backend::Btyped_identifier breceiver; if (this->receiver_ != NULL) { @@ -3414,8 +3487,8 @@ Function_type::do_get_backend(Gogo* gogo) { bparameters.resize(this->parameters_->size()); size_t i = 0; - for (Typed_identifier_list::const_iterator p = this->parameters_->begin(); - p != this->parameters_->end(); + 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()); @@ -3430,8 +3503,8 @@ Function_type::do_get_backend(Gogo* gogo) { bresults.resize(this->results_->size()); size_t i = 0; - for (Typed_identifier_list::const_iterator p = this->results_->begin(); - p != this->results_->end(); + 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()); @@ -3441,11 +3514,33 @@ Function_type::do_get_backend(Gogo* gogo) go_assert(i == bresults.size()); } - Btype* fntype = gogo->backend()->function_type(breceiver, bparameters, - bresults, loc); + 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 + // is represented as a pointer to a struct whose first field is the + // actual function. So that is what we return as the type of a Go + // function. + + Location loc = this->location(); + Btype* struct_type = + gogo->backend()->placeholder_struct_type("__go_descriptor", loc); + Btype* ptr_struct_type = gogo->backend()->pointer_type(struct_type); + 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(); @@ -3821,6 +3916,32 @@ Function_type::copy_with_receiver(Type* receiver_type) const return ret; } +// Make a copy of a function type with the receiver as the first +// parameter. + +Function_type* +Function_type::copy_with_receiver_as_param(bool want_pointer_receiver) const +{ + go_assert(this->is_method()); + Typed_identifier_list* new_params = new Typed_identifier_list(); + Type* rtype = this->receiver_->type(); + if (want_pointer_receiver) + rtype = Type::make_pointer_type(rtype); + Typed_identifier receiver(this->receiver_->name(), rtype, + this->receiver_->location()); + new_params->push_back(receiver); + const Typed_identifier_list* orig_params = this->parameters_; + if (orig_params != NULL && !orig_params->empty()) + { + for (Typed_identifier_list::const_iterator p = orig_params->begin(); + p != orig_params->end(); + ++p) + new_params->push_back(*p); + } + return Type::make_function_type(NULL, new_params, this->results_, + this->location_); +} + // Make a copy of a function type ignoring any receiver and adding a // closure parameter. @@ -4195,7 +4316,8 @@ Struct_field::is_field_name(const std::string& name) const // This is a horrible hack caused by the fact that we don't pack // the names of builtin types. FIXME. - if (nt != NULL + if (!this->is_imported_ + && nt != NULL && nt->is_builtin() && nt->name() == Gogo::unpack_hidden_name(name)) return true; @@ -4204,6 +4326,36 @@ Struct_field::is_field_name(const std::string& name) const } } +// Return whether this field is an unexported field named NAME. + +bool +Struct_field::is_unexported_field_name(Gogo* gogo, + const std::string& name) const +{ + const std::string& field_name(this->field_name()); + if (Gogo::is_hidden_name(field_name) + && name == Gogo::unpack_hidden_name(field_name) + && gogo->pack_hidden_name(name, false) != field_name) + return true; + + // Check for the name of a builtin type. This is like the test in + // is_field_name, only there we return false if this->is_imported_, + // and here we return true. + if (this->is_imported_ && this->is_anonymous()) + { + Type* t = this->typed_identifier_.type(); + if (t->points_to() != NULL) + t = t->points_to(); + Named_type* nt = t->named_type(); + if (nt != NULL + && nt->is_builtin() + && nt->name() == Gogo::unpack_hidden_name(name)) + return true; + } + + return false; +} + // Return whether this field is an embedded built-in type. bool @@ -4264,12 +4416,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) { @@ -4641,14 +4788,9 @@ Struct_type::is_unexported_local_field(Gogo* gogo, for (Struct_field_list::const_iterator pf = fields->begin(); pf != fields->end(); ++pf) - { - const std::string& field_name(pf->field_name()); - if (Gogo::is_hidden_name(field_name) - && name == Gogo::unpack_hidden_name(field_name) - && gogo->pack_hidden_name(name, false) != field_name) + if (pf->is_unexported_field_name(gogo, name)) return true; } - } return false; } @@ -5250,6 +5392,7 @@ Struct_type::do_import(Import* imp) Type* ftype = imp->read_type(); Struct_field sf(Typed_identifier(name, ftype, imp->location())); + sf.set_is_imported(); if (imp->peek_char() == ' ') { @@ -9022,6 +9165,8 @@ Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods, 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(); } @@ -9289,7 +9434,9 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr, else { bool is_unexported; - if (!Gogo::is_hidden_name(name)) + // The test for 'a' and 'z' is to handle builtin names, + // which are not hidden. + if (!Gogo::is_hidden_name(name) && (name[0] < 'a' || name[0] > 'z')) is_unexported = false; else { diff --git a/gcc-4.8/gcc/go/gofrontend/types.h b/gcc-4.8/gcc/go/gofrontend/types.h index d8a3080f5..0c712aaf5 100644 --- a/gcc-4.8/gcc/go/gofrontend/types.h +++ b/gcc-4.8/gcc/go/gofrontend/types.h @@ -1138,6 +1138,13 @@ class Type Function_type* equal_fntype, Named_object** hash_fn, Named_object** equal_fn); + void + write_named_hash(Gogo*, Named_type*, Function_type* hash_fntype, + Function_type* equal_fntype); + + void + write_named_equal(Gogo*, Named_type*); + // Build a composite literal for the uncommon type information. Expression* uncommon_type_constructor(Gogo*, Type* uncommon_type, @@ -1717,7 +1724,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. @@ -1789,6 +1797,12 @@ class Function_type : public Type Function_type* copy_with_receiver(Type*) const; + // Return a copy of this type with the receiver treated as the first + // parameter. If WANT_POINTER_RECEIVER is true, the receiver is + // forced to be a pointer. + Function_type* + copy_with_receiver_as_param(bool want_pointer_receiver) const; + // Return a copy of this type ignoring any receiver and using dummy // names for all parameters. This is used for thunks for method // values. @@ -1798,6 +1812,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 +1870,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. @@ -1915,7 +1937,7 @@ class Struct_field { public: explicit Struct_field(const Typed_identifier& typed_identifier) - : typed_identifier_(typed_identifier), tag_(NULL) + : typed_identifier_(typed_identifier), tag_(NULL), is_imported_(false) { } // The field name. @@ -1926,6 +1948,10 @@ class Struct_field bool is_field_name(const std::string& name) const; + // Return whether this struct field is an unexported field named NAME. + bool + is_unexported_field_name(Gogo*, const std::string& name) const; + // Return whether this struct field is an embedded built-in type. bool is_embedded_builtin(Gogo*) const; @@ -1963,6 +1989,11 @@ class Struct_field set_tag(const std::string& tag) { this->tag_ = new std::string(tag); } + // Record that this field is defined in an imported struct. + void + set_is_imported() + { this->is_imported_ = true; } + // Set the type. This is only used in error cases. void set_type(Type* type) @@ -1973,6 +2004,8 @@ class Struct_field Typed_identifier typed_identifier_; // The field tag. This is NULL if the field has no tag. std::string* tag_; + // Whether this field is defined in an imported struct. + bool is_imported_; }; // A list of struct fields. |