From patchwork Tue Aug 31 17:10:00 2010 Content-Type: text/plain; charset="utf-8" MIME-Version: 1.0 Content-Transfer-Encoding: 7bit X-Patchwork-Submitter: Ian Lance Taylor X-Patchwork-Id: 63296 Return-Path: X-Original-To: incoming@patchwork.ozlabs.org Delivered-To: patchwork-incoming@bilbo.ozlabs.org Received: from sourceware.org (server1.sourceware.org [209.132.180.131]) by ozlabs.org (Postfix) with SMTP id 964A8B714D for ; Wed, 1 Sep 2010 03:10:28 +1000 (EST) Received: (qmail 24074 invoked by alias); 31 Aug 2010 17:10:25 -0000 Received: (qmail 24044 invoked by uid 22791); 31 Aug 2010 17:10:17 -0000 X-SWARE-Spam-Status: No, hits=0.6 required=5.0 tests=AWL, BAYES_50, DKIM_SIGNED, DKIM_VALID, DKIM_VALID_AU, POKER_BODY, SPF_HELO_PASS, TW_CC, T_RP_MATCHES_RCVD, T_TVD_MIME_NO_HEADERS X-Spam-Check-By: sourceware.org Received: from smtp-out.google.com (HELO smtp-out.google.com) (216.239.44.51) by sourceware.org (qpsmtpd/0.43rc1) with ESMTP; Tue, 31 Aug 2010 17:10:07 +0000 Received: from wpaz9.hot.corp.google.com (wpaz9.hot.corp.google.com [172.24.198.73]) by smtp-out.google.com with ESMTP id o7VHA41a017605 for ; Tue, 31 Aug 2010 10:10:04 -0700 Received: from pzk33 (pzk33.prod.google.com [10.243.19.161]) by wpaz9.hot.corp.google.com with ESMTP id o7VH9VkT008787 for ; Tue, 31 Aug 2010 10:10:03 -0700 Received: by pzk33 with SMTP id 33so5199729pzk.0 for ; Tue, 31 Aug 2010 10:10:03 -0700 (PDT) Received: by 10.114.111.5 with SMTP id j5mr3001121wac.28.1283274603087; Tue, 31 Aug 2010 10:10:03 -0700 (PDT) Received: from coign.google.com (dhcp-172-22-124-178.mtv.corp.google.com [172.22.124.178]) by mx.google.com with ESMTPS id r3sm8991220ibk.1.2010.08.31.10.10.01 (version=TLSv1/SSLv3 cipher=RC4-MD5); Tue, 31 Aug 2010 10:10:01 -0700 (PDT) From: Ian Lance Taylor To: gcc-patches@gcc.gnu.org, gofrontend-dev@googlegroups.com Subject: [gccgo] Update gccgo to current type rules Date: Tue, 31 Aug 2010 10:10:00 -0700 Message-ID: User-Agent: Gnus/5.13 (Gnus v5.13) Emacs/23.1 (gnu/linux) MIME-Version: 1.0 X-System-Of-Record: true X-IsSubscribed: yes Mailing-List: contact gcc-patches-help@gcc.gnu.org; run by ezmlm Precedence: bulk List-Id: List-Unsubscribe: List-Archive: List-Post: List-Help: Sender: gcc-patches-owner@gcc.gnu.org Delivered-To: mailing list gcc-patches@gcc.gnu.org The Go rules for type assignability and convertibility were simplified a couple of months ago. This patch updates gccgo to use the new rules. It also includes a few library changes to correspond to the new rules, in that the address of an array may no longer be assigned to a slice. Committed to gccgo branch. Ian diff -r b0b47113eebd go/expressions.cc --- a/go/expressions.cc Fri Aug 27 19:29:10 2010 -0700 +++ b/go/expressions.cc Tue Aug 31 10:02:07 2010 -0700 @@ -1356,7 +1356,7 @@ public: Boolean_expression(bool val, source_location location) : Expression(EXPRESSION_BOOLEAN, location), - val_(val) + val_(val), type_(NULL) { } static Expression* @@ -1368,12 +1368,10 @@ { return true; } Type* - do_type() - { return Type::make_boolean_type(); } + do_type(); void - do_determine_type(const Type_context*) - { } + do_determine_type(const Type_context*); Expression* do_copy() @@ -1388,9 +1386,35 @@ { exp->write_c_string(this->val_ ? "true" : "false"); } private: + // The constant. bool val_; + // The type as determined by context. + Type* type_; }; +// Get the type. + +Type* +Boolean_expression::do_type() +{ + if (this->type_ == NULL) + this->type_ = Type::make_boolean_type(); + return this->type_; +} + +// Set the type from the context. + +void +Boolean_expression::do_determine_type(const Type_context* context) +{ + if (this->type_ != NULL && !this->type_->is_abstract()) + ; + else if (context->type != NULL && context->type->is_boolean_type()) + this->type_ = context->type; + else if (!context->may_be_abstract) + this->type_ = Type::lookup_bool_type(); +} + // Import a boolean constant. Expression* @@ -1418,12 +1442,27 @@ // Class String_expression. -// The type of a string expression. +// Get the type. Type* String_expression::do_type() { - return Type::make_string_type(); + if (this->type_ == NULL) + this->type_ = Type::make_string_type(); + return this->type_; +} + +// Set the type from the context. + +void +String_expression::do_determine_type(const Type_context* context) +{ + if (this->type_ != NULL && !this->type_->is_abstract()) + ; + else if (context->type != NULL && context->type->is_string_type()) + this->type_ = context->type; + else if (!context->may_be_abstract) + this->type_ = Type::lookup_string_type(); } // Build a string constant. @@ -2502,20 +2541,32 @@ Const_expression::do_determine_type(const Type_context* context) { Type* ctype = this->constant_->const_value()->type(); + Type* cetype = (ctype != NULL + ? ctype + : this->constant_->const_value()->expr()->type()); if (ctype != NULL && !ctype->is_abstract()) ; else if (context->type != NULL && (context->type->integer_type() != NULL || context->type->float_type() != NULL - || context->type->complex_type() != NULL)) + || context->type->complex_type() != NULL) + && (cetype->integer_type() != NULL + || cetype->float_type() != NULL + || cetype->complex_type() != NULL)) + this->type_ = context->type; + else if (context->type != NULL + && context->type->is_string_type() + && cetype->is_string_type()) + this->type_ = context->type; + else if (context->type != NULL + && context->type->is_boolean_type() + && cetype->is_boolean_type()) this->type_ = context->type; else if (!context->may_be_abstract) { - if (ctype == NULL) - ctype = this->constant_->const_value()->expr()->type(); - if (ctype->is_abstract()) - ctype = ctype->make_non_abstract_type(); - this->type_ = ctype; + if (cetype->is_abstract()) + cetype = cetype->make_non_abstract_type(); + this->type_ = cetype; } } @@ -3120,73 +3171,11 @@ Type* expr_type = this->expr_->type(); std::string reason; - if (Type::are_compatible_for_conversion(type, expr_type, &reason)) + if (Type::are_convertible(type, expr_type, &reason)) return; - bool ok = false; - if ((type->integer_type() != NULL || type->float_type() != NULL) - && (expr_type->integer_type() != NULL - || expr_type->float_type() != NULL)) - ok = true; - else if (type->complex_type() != NULL - && expr_type->complex_type() != NULL) - ok = true; - else if (type->is_string_type()) - { - if (expr_type->integer_type() != NULL) - ok = true; - else - { - Type* t = expr_type->deref(); - if (t->array_type() != NULL) - { - Type* e = t->array_type()->element_type()->forwarded(); - if (e->integer_type() != NULL - && (e == Type::lookup_integer_type("uint8") - || e == Type::lookup_integer_type("int"))) - ok = true; - } - } - } - else if (type->is_open_array_type() && expr_type->is_string_type()) - { - Type* e = type->array_type()->element_type()->forwarded(); - if (e->integer_type() != NULL - && (e == Type::lookup_integer_type("uint8") - || e == Type::lookup_integer_type("int"))) - ok = true; - } - else if ((type->is_unsafe_pointer_type() - && (expr_type->points_to() != NULL - || (expr_type->integer_type() != NULL - && (expr_type->integer_type()->bits() - == static_cast(POINTER_SIZE)) - && expr_type->integer_type()->is_unsigned()))) - || (expr_type->is_unsafe_pointer_type() - && (type->points_to() != NULL - || (type->integer_type() != NULL - && (type->integer_type()->bits() - == static_cast(POINTER_SIZE)) - && type->integer_type()->is_unsigned())))) - { - // Conversions between unsafe pointers and other pointers or - // integers of appropriate size are permitted. - ok = true; - } - - // FIXME: Conversions between interfaces and pointers are supported. - - if (!ok) - { - if (reason.empty()) - this->report_error(_("invalid type conversion")); - else - { - error_at(this->location(), "invalid type conversion (%s)", - reason.c_str()); - this->set_is_error(); - } - } + error_at(this->location(), reason.c_str()); + this->set_is_error(); } // Get a tree for a type conversion. @@ -6081,7 +6070,7 @@ ? this->expr_type_ : this->expr_->type()); etype = etype->deref(); - if (!Type::are_identical(rtype, etype)) + if (!Type::are_identical(rtype, etype, NULL)) this->report_error(_("method type does not match object type")); } } @@ -6703,7 +6692,7 @@ bool ret = false; Type* itype; if (args->back()->float_constant_value(i, &itype) - && Type::are_identical(rtype, itype)) + && Type::are_identical(rtype, itype, NULL)) { mpfr_set(real, r, GMP_RNDN); mpfr_set(imag, i, GMP_RNDN); @@ -6865,6 +6854,10 @@ want_type = Type::lookup_float_type("float64"); else if (atype->complex_type() != NULL) want_type = Type::lookup_complex_type("complex128"); + else if (atype->is_abstract_string_type()) + want_type = Type::lookup_string_type(); + else if (atype->is_abstract_boolean_type()) + want_type = Type::lookup_bool_type(); else gcc_unreachable(); subcontext.type = want_type; @@ -7062,7 +7055,7 @@ break; } - if (!Type::are_identical(e1, e2)) + if (!Type::are_identical(e1, e2, NULL)) this->report_error(_("element types must be the same")); } break; @@ -7089,7 +7082,7 @@ || args->back()->type()->is_error_type()) this->set_is_error(); else if (!Type::are_identical(args->front()->type(), - args->back()->type())) + args->back()->type(), NULL)) this->report_error(_("arguments must have identical types")); else if (args->front()->type()->float_type() == NULL) this->report_error(_("arguments must have floating-point type")); @@ -7911,7 +7904,7 @@ Array_type* param_at = param_type->array_type(); if (param_at != NULL && Type::are_identical(var_at->element_type(), - param_at->element_type())) + param_at->element_type(), NULL)) return true; error_at(arg->location(), "... mismatch: passing ...T as ..."); return false; @@ -8036,7 +8029,7 @@ source_location argument_location) { std::string reason; - if (!Type::are_compatible_for_assign(parameter_type, argument_type, &reason)) + if (!Type::are_assignable(parameter_type, argument_type, &reason)) { if (reason.empty()) error_at(argument_location, "argument %d has incompatible type", i); @@ -8078,8 +8071,8 @@ // When passing a value, we need to check that we are // permitted to copy it. std::string reason; - if (!Type::are_compatible_for_assign(fntype->receiver()->type(), - first_arg_type, &reason)) + if (!Type::are_assignable(fntype->receiver()->type(), + first_arg_type, &reason)) { if (reason.empty()) this->report_error("incompatible type for receiver"); @@ -9208,9 +9201,8 @@ Map_index_expression::do_check_types(Gogo*) { std::string reason; - if (!Type::are_compatible_for_assign(this->get_map_type()->key_type(), - this->index_->type(), - &reason)) + if (!Type::are_assignable(this->get_map_type()->key_type(), + this->index_->type(), &reason)) { if (reason.empty()) this->report_error(_("incompatible type for map index")); @@ -10072,8 +10064,7 @@ continue; std::string reason; - if (!Type::are_compatible_for_assign(pf->type(), (*pv)->type(), - &reason)) + if (!Type::are_assignable(pf->type(), (*pv)->type(), &reason)) { if (reason.empty()) error_at((*pv)->location(), @@ -10311,8 +10302,7 @@ ++pv, ++i) { if (*pv != NULL - && !Type::are_compatible_for_assign(element_type, (*pv)->type(), - NULL)) + && !Type::are_assignable(element_type, (*pv)->type(), NULL)) { error_at((*pv)->location(), "incompatible type for element %d in composite literal", @@ -10688,7 +10678,7 @@ pv != this->vals_->end(); ++pv, ++i) { - if (!Type::are_compatible_for_assign(key_type, (*pv)->type(), NULL)) + if (!Type::are_assignable(key_type, (*pv)->type(), NULL)) { error_at((*pv)->location(), "incompatible type for element %d key in map construction", @@ -10696,7 +10686,7 @@ this->set_is_error(); } ++pv; - if (!Type::are_compatible_for_assign(val_type, (*pv)->type(), NULL)) + if (!Type::are_assignable(val_type, (*pv)->type(), NULL)) { error_at((*pv)->location(), ("incompatible type for element %d value " @@ -11583,8 +11573,7 @@ } Type* element_type = channel_type->element_type(); if (element_type != NULL - && !Type::are_compatible_for_assign(element_type, this->val_->type(), - NULL)) + && !Type::are_assignable(element_type, this->val_->type(), NULL)) { this->report_error(_("incompatible types in send")); return; diff -r b0b47113eebd go/expressions.h --- a/go/expressions.h Fri Aug 27 19:29:10 2010 -0700 +++ b/go/expressions.h Tue Aug 31 10:02:07 2010 -0700 @@ -958,7 +958,7 @@ public: String_expression(const std::string& val, source_location location) : Expression(EXPRESSION_STRING, location), - val_(val) + val_(val), type_(NULL) { } const std::string& @@ -984,8 +984,7 @@ do_type(); void - do_determine_type(const Type_context*) - { } + do_determine_type(const Type_context*); Expression* do_copy() @@ -1000,6 +999,8 @@ private: // The string value. This is immutable. const std::string val_; + // The type as determined by context. + Type* type_; }; // A binary expression. diff -r b0b47113eebd go/gogo.cc --- a/go/gogo.cc Fri Aug 27 19:29:10 2010 -0700 +++ b/go/gogo.cc Tue Aug 31 10:02:07 2010 -0700 @@ -1402,8 +1402,7 @@ Expression* init = var->init(); std::string reason; if (init != NULL - && !Type::are_compatible_for_assign(var->type(), init->type(), - &reason)) + && !Type::are_assignable(var->type(), init->type(), &reason)) { if (reason.empty()) error_at(var->location(), "incompatible type in initialization"); @@ -1438,8 +1437,8 @@ error_at(constant->expr()->location(), "expression is not constant"); constant->set_error(); } - else if (!Type::are_compatible_for_assign(constant->type(), - constant->expr()->type(), NULL)) + else if (!Type::are_assignable(constant->type(), constant->expr()->type(), + NULL)) { error_at(constant->location(), "initialization expression has wrong type"); diff -r b0b47113eebd go/statements.cc --- a/go/statements.cc Fri Aug 27 19:29:10 2010 -0700 +++ b/go/statements.cc Tue Aug 31 10:02:07 2010 -0700 @@ -345,9 +345,7 @@ Temporary_statement::do_check_types(Gogo*) { if (this->type_ != NULL && this->init_ != NULL) - gcc_assert(Type::are_compatible_for_assign(this->type_, - this->init_->type(), - NULL)); + gcc_assert(Type::are_assignable(this->type_, this->init_->type(), NULL)); } // Return a tree. @@ -485,7 +483,7 @@ Type* lhs_type = this->lhs_->type(); Type* rhs_type = this->rhs_->type(); std::string reason; - if (!Type::are_compatible_for_assign(lhs_type, rhs_type, &reason)) + if (!Type::are_assignable(lhs_type, rhs_type, &reason)) { if (reason.empty()) error_at(this->location(), "incompatible types in assignment"); @@ -2412,7 +2410,7 @@ e->determine_type(&type_context); std::string reason; - if (Type::are_compatible_for_assign(rvtype, e->type(), &reason)) + if (Type::are_assignable(rvtype, e->type(), &reason)) { Expression* ve = Expression::make_var_reference(rv, e->location()); lhs->push_back(ve); @@ -2503,7 +2501,7 @@ return; } std::string reason; - if (!Type::are_compatible_for_assign(pt->type(), (*pe)->type(), &reason)) + if (!Type::are_assignable(pt->type(), (*pe)->type(), &reason)) { if (reason.empty()) error_at(this->location(), diff -r b0b47113eebd go/types.cc --- a/go/types.cc Fri Aug 27 19:29:10 2010 -0700 +++ b/go/types.cc Tue Aug 31 10:02:07 2010 -0700 @@ -172,6 +172,10 @@ return this->float_type()->is_abstract(); case TYPE_COMPLEX: return this->complex_type()->is_abstract(); + case TYPE_STRING: + return this->is_abstract_string_type(); + case TYPE_BOOLEAN: + return this->is_abstract_boolean_type(); default: return false; } @@ -191,6 +195,10 @@ return Type::lookup_float_type("float"); case TYPE_COMPLEX: return Type::lookup_complex_type("complex"); + case TYPE_STRING: + return Type::lookup_string_type(); + case TYPE_BOOLEAN: + return Type::lookup_bool_type(); default: gcc_unreachable(); } @@ -291,13 +299,11 @@ return TRAVERSE_CONTINUE; } -// Return true if two types are compatible according to COMPATIBLE. -// If REASON is not NULL, optionally set *REASON to the reason the -// types are incompatible. +// Return whether two types are identical. If REASON is not NULL, +// optionally set *REASON to the reason the types are not identical. bool -Type::are_compatible_for(const Type* t1, const Type* t2, - Type_compatible compatible, std::string* reason) +Type::are_identical(const Type* t1, const Type* t2, std::string* reason) { if (t1 == NULL || t2 == NULL) { @@ -323,8 +329,7 @@ return true; // Get a good reason for the sink type. Note that the sink type on - // the left hand side of an assignment is handled in - // are_compatible_for_assign. + // the left hand side of an assignment is handled in are_assignable. if (t1->is_sink_type() || t2->is_sink_type()) { if (reason != NULL) @@ -332,76 +337,78 @@ return false; } - // Cut off infinite recursion by using a flag on a named type. - const Named_type* nt1 = t1->named_type(); - if (nt1 != NULL) - return nt1->is_compatible(t2, compatible, reason); - - const Type* t1base = t1->base(); - const Type* t2base = t2->base(); - - if (t1base->classification_ != t2base->classification_) + // A named type is only identical to itself. + if (t1->named_type() != NULL || t2->named_type() != NULL) return false; - switch (t1base->classification_) + // Check type shapes. + if (t1->classification() != t2->classification()) + return false; + + switch (t1->classification()) { case TYPE_VOID: case TYPE_BOOLEAN: case TYPE_STRING: case TYPE_NIL: - // These types are always compatible with themselves. + // These types are always identical. return true; case TYPE_INTEGER: - return t1base->integer_type()->is_compatible(t2base->integer_type()); + return t1->integer_type()->is_identical(t2->integer_type()); case TYPE_FLOAT: - return t1base->float_type()->is_compatible(t2base->float_type()); + return t1->float_type()->is_identical(t2->float_type()); case TYPE_COMPLEX: - return t1base->complex_type()->is_compatible(t2base->complex_type()); + return t1->complex_type()->is_identical(t2->complex_type()); case TYPE_FUNCTION: - return t1base->function_type()->is_compatible(t2base->function_type(), - compatible, - false, - reason); + return t1->function_type()->is_identical(t2->function_type(), + false, + reason); case TYPE_POINTER: - return Type::are_compatible_for(t1base->points_to(), t2base->points_to(), - compatible, reason); + return Type::are_identical(t1->points_to(), t2->points_to(), reason); case TYPE_STRUCT: - return t1base->struct_type()->is_compatible(t2base->struct_type(), - compatible); + return t1->struct_type()->is_identical(t2->struct_type()); case TYPE_ARRAY: - return t1base->array_type()->is_compatible(t2base->array_type(), - compatible); + return t1->array_type()->is_identical(t2->array_type()); case TYPE_MAP: - return t1base->map_type()->is_compatible(t2base->map_type(), - compatible); + return t1->map_type()->is_identical(t2->map_type()); case TYPE_CHANNEL: - return t1base->channel_type()->is_compatible(t2base->channel_type(), - compatible); + return t1->channel_type()->is_identical(t2->channel_type()); case TYPE_INTERFACE: - return t1base->interface_type()->is_compatible(t2base->interface_type(), - compatible); + return t1->interface_type()->is_identical(t2->interface_type()); default: gcc_unreachable(); } } -// Return true if it's OK to have a binary operation with types LHS and RHS. +// Return true if it's OK to have a binary operation with types LHS +// and RHS. This is not used for shifts. bool Type::are_compatible_for_binop(const Type* lhs, const Type* rhs) { - if (Type::are_compatible(lhs, rhs)) + if (Type::are_identical(lhs, rhs, NULL)) + return true; + + // A constant of abstract bool type may be mixed with any bool type. + if ((rhs->is_abstract_boolean_type() && lhs->is_boolean_type()) + || (lhs->is_abstract_boolean_type() && rhs->is_boolean_type())) + return true; + + // A constant of abstract string type may be mixed with any string + // type. + if ((rhs->is_abstract_string_type() && lhs->is_string_type()) + || (lhs->is_abstract_string_type() && rhs->is_string_type())) return true; lhs = lhs->base(); @@ -410,10 +417,16 @@ // A constant of abstract integer, float, or complex type may be // mixed with an integer, float, or complex type. if ((rhs->is_abstract() + && (rhs->integer_type() != NULL + || rhs->float_type() != NULL + || rhs->complex_type() != NULL) && (lhs->integer_type() != NULL || lhs->float_type() != NULL || lhs->complex_type() != NULL)) || (lhs->is_abstract() + && (lhs->integer_type() != NULL + || lhs->float_type() != NULL + || lhs->complex_type() != NULL) && (rhs->integer_type() != NULL || rhs->float_type() != NULL || rhs->complex_type() != NULL))) @@ -441,23 +454,22 @@ return false; } - -// Return true if a value with type RHS may be assigned to a value -// with type LHS. IS_CONVERSION is true to check for conversion -// compatibility rather than assignment compatibility. +// Return true if a value with type RHS may be assigned to a variable +// with type LHS. If REASON is not NULL, set *REASON to the reason +// the types are not assignable. bool -Type::are_assignment_compatible(const Type* lhs, const Type* rhs, - bool is_conversion, std::string* reason) -{ - // Any value may be assigned to the blank identifier. Make sure - // that types are reasonable before calling base(). +Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason) +{ + // Do some checks first. Make sure the types are defined. if (lhs != NULL && lhs->forwarded()->forward_declaration_type() == NULL) { - if (!is_conversion && lhs->is_sink_type()) + // Any value may be assigned to the blank identifier. + if (lhs->is_sink_type()) return true; - // Check for hidden fields before checking for compatibility. + // All fields of a struct must be exported, or the assignment + // must be in the same package. if (rhs != NULL && rhs->forwarded()->forward_declaration_type() == NULL) { if (lhs->has_hidden_fields(NULL, reason) @@ -466,89 +478,63 @@ } } - if (Type::are_compatible_for(lhs, rhs, - (is_conversion - ? COMPATIBLE_FOR_CONVERSION - : COMPATIBLE_COMPATIBLE), - reason)) + // Identical types are assignable. + if (Type::are_identical(lhs, rhs, reason)) return true; - const Type* orig_lhs = lhs; - lhs = lhs->base(); - const Type* orig_rhs = rhs; - rhs = rhs->base(); - - // Any type may be assigned to an interface type if it implements - // the required methods. Note that we must pass ORIG_RHS here, not - // RHS, since the methods will be attached to ORIG_RHS. - if (lhs->interface_type() != NULL - && lhs->interface_type()->implements_interface(orig_rhs, reason)) + // The types are assignable if they have identical underlying types + // and either LHS or RHS is not a named type. + if (((lhs->named_type() != NULL && rhs->named_type() == NULL) + || (rhs->named_type() != NULL && lhs->named_type() == NULL)) + && Type::are_identical(lhs->base(), rhs->base(), reason)) return true; - // Interface assignment is permitted if RHS is known to implement - // all the methods in LHS. - if (lhs->interface_type() != NULL - && rhs->interface_type() != NULL - && lhs->interface_type()->is_compatible_for_assign(rhs->interface_type(), - reason)) - return true; - - // Other than the cases checked above, two different named types may - // be compatible for conversion, but are never compatible for - // assignment. - if (!is_conversion - && orig_lhs->named_type() != NULL - && orig_rhs->named_type() != NULL) - return false; - - // The compatibility level to check for when checking subtypes. - Type_compatible pass = (is_conversion - ? COMPATIBLE_FOR_CONVERSION - : COMPATIBLE_COMPATIBLE); - - // A pointer to an array may be assigned to a slice of the - // same element type. - if (lhs->is_open_array_type() - && rhs->points_to() != NULL - && rhs->points_to()->array_type() != NULL - && !rhs->is_open_array_type()) - { - Type* e1 = lhs->array_type()->element_type(); - Type* e2 = rhs->points_to()->array_type()->element_type(); - if (Type::are_compatible_for(e1, e2, pass, reason)) + // The types are assignable if LHS is an interface type and RHS + // implements the required methods. + const Interface_type* lhs_interface_type = lhs->interface_type(); + if (lhs_interface_type != NULL) + { + if (lhs_interface_type->implements_interface(rhs, reason)) return true; - } - - // We can assign a bidirectional channel to a uni-directional - // channel. + const Interface_type* rhs_interface_type = rhs->interface_type(); + if (rhs_interface_type != NULL + && lhs_interface_type->is_compatible_for_assign(rhs_interface_type, + reason)) + return true; + } + + // The type are assignable if RHS is a bidirectional channel type, + // LHS is a channel type, they have identical element types, and + // either LHS or RHS is not a named type. if (lhs->channel_type() != NULL && rhs->channel_type() != NULL && rhs->channel_type()->may_send() && rhs->channel_type()->may_receive() - && Type::are_compatible_for(lhs->channel_type()->element_type(), - rhs->channel_type()->element_type(), - pass, reason)) + && (lhs->named_type() == NULL || rhs->named_type() == NULL) + && Type::are_identical(lhs->channel_type()->element_type(), + rhs->channel_type()->element_type(), + reason)) return true; - // A constant of abstract integer or float type may be assigned to - // integer, float, or complex type. + // The nil type may be assigned to a pointer, function, slice, map, + // channel, or interface type. + if (rhs->is_nil_type() + && (lhs->points_to() != NULL + || lhs->function_type() != NULL + || lhs->is_open_array_type() + || lhs->map_type() != NULL + || lhs->channel_type() != NULL + || lhs->interface_type() != NULL)) + return true; + + // An untyped constant may be assigned to a numeric type if it is + // representable in that type. if (rhs->is_abstract() && (lhs->integer_type() != NULL || lhs->float_type() != NULL || lhs->complex_type() != NULL)) return true; - // The nil type may be assigned to a pointer type, an interface - // type, a slice type, a map type, a channel type, or a function - // type. - if (rhs->is_nil_type() - && (lhs->points_to() != NULL - || lhs->interface_type() != NULL - || lhs->is_open_array_type() - || lhs->map_type() != NULL - || lhs->channel_type() != NULL - || lhs->function_type() != NULL)) - return true; // Give some better error messages. if (reason != NULL && reason->empty()) @@ -558,6 +544,112 @@ else if (rhs->is_call_multiple_result_type()) reason->assign(_("multiple value function call in " "single value context")); + else if (lhs->named_type() != NULL && rhs->named_type() != NULL) + { + size_t len = (lhs->named_type()->name().length() + + rhs->named_type()->name().length() + + 100); + char* buf = new char[len]; + snprintf(buf, len, _("cannot use type %s as type %s"), + rhs->named_type()->message_name().c_str(), + lhs->named_type()->message_name().c_str()); + reason->assign(buf); + delete[] buf; + } + } + + return false; +} + +// Return true if a value with type RHS may be converted to type LHS. +// If REASON is not NULL, set *REASON to the reason the types are not +// convertible. + +bool +Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) +{ + // The types are convertible if they are assignable. + if (Type::are_assignable(lhs, rhs, reason)) + return true; + + // The types are convertible if they have identical underlying + // types. + if ((lhs->named_type() != NULL || rhs->named_type() != NULL) + && Type::are_identical(lhs->base(), rhs->base(), reason)) + return true; + + // The types are convertible if they are both unnamed pointer types + // and their pointer base types have identical underlying types. + if (lhs->named_type() == NULL + && rhs->named_type() == NULL + && lhs->points_to() != NULL + && rhs->points_to() != NULL + && (lhs->points_to()->named_type() != NULL + || rhs->points_to()->named_type() != NULL) + && Type::are_identical(lhs->points_to()->base(), + rhs->points_to()->base(), + reason)) + return true; + + // Integer and floating point types are convertible to each other. + if ((lhs->integer_type() != NULL || lhs->float_type() != NULL) + && (rhs->integer_type() != NULL || rhs->float_type() != NULL)) + return true; + + // Complex types are convertible to each other. + if (lhs->complex_type() != NULL && rhs->complex_type() != NULL) + return true; + + // An integer, or []byte, or []int, may be converted to a string. + if (lhs->is_string_type()) + { + if (rhs->integer_type() != NULL) + return true; + if (rhs->is_open_array_type()) + { + const Type* e = rhs->array_type()->element_type()->forwarded(); + if (e->integer_type() != NULL + && (e == Type::lookup_integer_type("uint8") + || e == Type::lookup_integer_type("int"))) + return true; + } + } + + // A string may be converted to []byte or []int. + if (rhs->is_string_type() && lhs->is_open_array_type()) + { + const Type* e = lhs->array_type()->element_type()->forwarded(); + if (e->integer_type() != NULL + && (e == Type::lookup_integer_type("uint8") + || e == Type::lookup_integer_type("int"))) + return true; + } + + // An unsafe.Pointer type may be converted to any pointer type or to + // uintptr, and vice-versa. + if (lhs->is_unsafe_pointer_type() + && (rhs->points_to() != NULL + || (rhs->integer_type() != NULL + && rhs->forwarded() == Type::lookup_integer_type("uintptr")))) + return true; + if (rhs->is_unsafe_pointer_type() + && (lhs->points_to() != NULL + || (lhs->integer_type() != NULL + && lhs->forwarded() == Type::lookup_integer_type("uintptr")))) + return true; + + // Give a better error message. + if (reason != NULL) + { + if (reason->empty()) + *reason = "invalid type conversion"; + else + { + std::string s = "invalid type conversion ("; + s += *reason; + s += ')'; + *reason = s; + } } return false; @@ -1016,7 +1108,7 @@ // Integer type compatibility. bool -Integer_type::is_compatible(const Integer_type* t) const +Integer_type::is_identical(const Integer_type* t) const { if (this->is_unsigned_ != t->is_unsigned_ || this->bits_ != t->bits_) return false; @@ -1179,10 +1271,10 @@ return abstract_type; } -// Whether this type is compatible with T. +// Whether this type is identical with T. bool -Float_type::is_compatible(const Float_type* t) const +Float_type::is_identical(const Float_type* t) const { if (this->bits_ != t->bits_) return false; @@ -1337,10 +1429,10 @@ return abstract_type; } -// Whether this type is compatible with T. +// Whether this type is identical with T. bool -Complex_type::is_compatible(const Complex_type *t) const +Complex_type::is_identical(const Complex_type *t) const { if (this->bits_ != t->bits_) return false; @@ -1657,7 +1749,7 @@ Function_type::is_valid_redeclaration(const Function_type* t, std::string* reason) const { - if (!this->is_compatible(t, COMPATIBLE_IDENTICAL, false, reason)) + if (!this->is_identical(t, false, reason)) return false; // A redeclaration of a function is required to use the same names @@ -1691,8 +1783,7 @@ } // This is called at parse time, so we may have unknown - // types. They will appear compatible according to - // Type::is_compatible. + // types. Type* t1 = p1->type()->forwarded(); Type* t2 = p2->type()->forwarded(); if (t1 != t2 @@ -1723,8 +1814,7 @@ } // This is called at parse time, so we may have unknown - // types. They will appear compatible according to - // Type::is_compatible. + // types. Type* t1 = res1->type()->forwarded(); Type* t2 = res2->type()->forwarded(); if (t1 != t2 @@ -1742,10 +1832,8 @@ // Check whether T is the same as this type. bool -Function_type::is_compatible(const Function_type* t, - Type_compatible compatible, - bool ignore_receiver, - std::string* reason) const +Function_type::is_identical(const Function_type* t, bool ignore_receiver, + std::string* reason) const { if (!ignore_receiver) { @@ -1759,8 +1847,7 @@ } if (r1 != NULL) { - if (!Type::are_compatible_for(r1->type(), r2->type(), compatible, - reason)) + if (!Type::are_identical(r1->type(), r2->type(), reason)) { if (reason != NULL && !reason->empty()) *reason = "receiver: " + *reason; @@ -1791,8 +1878,7 @@ return false; } - if (!Type::are_compatible_for(p1->type(), p2->type(), compatible, - NULL)) + if (!Type::are_identical(p1->type(), p2->type(), NULL)) { if (reason != NULL) *reason = _("different parameter types"); @@ -1836,8 +1922,7 @@ return false; } - if (!Type::are_compatible_for(res1->type(), res2->type(), compatible, - NULL)) + if (!Type::are_identical(res1->type(), res2->type(), NULL)) { if (reason != NULL) *reason = _("different result types"); @@ -2643,11 +2728,10 @@ return false; } -// Whether this type is compatible with T. +// Whether this type is identical to T. bool -Struct_type::is_compatible(const Struct_type* t, - Type_compatible compatible) const +Struct_type::is_identical(const Struct_type* t) const { const Struct_field_list* fields1 = this->fields(); const Struct_field_list* fields2 = t->fields(); @@ -2660,27 +2744,22 @@ { if (pf2 == fields2->end()) return false; - if (compatible == COMPATIBLE_IDENTICAL - && pf1->field_name() != pf2->field_name()) + if (pf1->field_name() != pf2->field_name()) return false; if (pf1->is_anonymous() != pf2->is_anonymous() - || !Type::are_compatible_for(pf1->type(), pf2->type(), compatible, - NULL)) + || !Type::are_identical(pf1->type(), pf2->type(), NULL)) return false; - if (compatible == COMPATIBLE_IDENTICAL) + if (!pf1->has_tag()) { - if (!pf1->has_tag()) - { - if (pf2->has_tag()) - return false; - } - else - { - if (!pf2->has_tag()) - return false; - if (pf1->tag() != pf2->tag()) - return false; - } + if (pf2->has_tag()) + return false; + } + else + { + if (!pf2->has_tag()) + return false; + if (pf1->tag() != pf2->tag()) + return false; } } if (pf2 != fields2->end()) @@ -3225,25 +3304,23 @@ Array_type::Array_trees Array_type::array_trees; -// Whether two array types are compatible. +// Whether two array types are identical. bool -Array_type::is_compatible(const Array_type* t, - Type_compatible compatible) const -{ - if (!Type::are_compatible_for(this->element_type(), t->element_type(), - compatible, NULL)) +Array_type::is_identical(const Array_type* t) const +{ + if (!Type::are_identical(this->element_type(), t->element_type(), NULL)) return false; Expression* l1 = this->length(); Expression* l2 = t->length(); - // Open arrays of the same element type are identical. + // Slices of the same element type are identical. if (l1 == NULL && l2 == NULL) return true; - // Fixed arrays of the same element type are identical if they have - // the same length. + // Arrays of the same element type are identical if they have the + // same length. if (l1 != NULL && l2 != NULL) { if (l1 == l2) @@ -3793,15 +3870,13 @@ return true; } -// Whether two map types are compatible. +// Whether two map types are identical. bool -Map_type::is_compatible(const Map_type* t, Type_compatible compatible) const -{ - return (Type::are_compatible_for(this->key_type(), t->key_type(), - compatible, NULL) - && Type::are_compatible_for(this->val_type(), t->val_type(), - compatible, NULL)); +Map_type::is_identical(const Map_type* t) const +{ + return (Type::are_identical(this->key_type(), t->key_type(), NULL) + && Type::are_identical(this->val_type(), t->val_type(), NULL)); } // Hash code. @@ -4016,11 +4091,9 @@ // Whether this type is the same as T. bool -Channel_type::is_compatible(const Channel_type* t, - Type_compatible compatible) const -{ - if (!Type::are_compatible_for(this->element_type(), t->element_type(), - compatible, NULL)) +Channel_type::is_identical(const Channel_type* t) const +{ + if (!Type::are_identical(this->element_type(), t->element_type(), NULL)) return false; return (this->may_send_ == t->may_send_ && this->may_receive_ == t->may_receive_); @@ -4334,11 +4407,10 @@ return false; } -// Whether this type is compatible with T. +// Whether this type is identical with T. bool -Interface_type::is_compatible(const Interface_type* t, - Type_compatible compatible) const +Interface_type::is_identical(const Interface_type* t) const { // We require the same methods with the same types. The methods // have already been sorted. @@ -4353,8 +4425,7 @@ if (p1 == this->methods()->end()) return false; if (p1->name() != p2->name() - || !Type::are_compatible_for(p1->type(), p2->type(), compatible, - NULL)) + || !Type::are_identical(p1->type(), p2->type(), NULL)) return false; } if (p1 != this->methods()->end()) @@ -4363,7 +4434,7 @@ } // Whether we can assign the interface type T to this type. The types -// are known to not be compatible. An interface assignment is only +// are known to not be identical. An interface assignment is only // permitted if T is known to implement all methods in THIS. // Otherwise a type guard is required. @@ -4394,8 +4465,7 @@ } std::string subreason; - if (!Type::are_compatible_for(p->type(), m->type(), COMPATIBLE_COMPATIBLE, - &subreason)) + if (!Type::are_identical(p->type(), m->type(), &subreason)) { if (reason != NULL) { @@ -4522,8 +4592,7 @@ Function_type* m_fn_type = m->type()->function_type(); gcc_assert(p_fn_type != NULL && m_fn_type != NULL); std::string subreason; - if (!p_fn_type->is_compatible(m_fn_type, COMPATIBLE_COMPATIBLE, true, - &subreason)) + if (!p_fn_type->is_identical(m_fn_type, true, &subreason)) { if (reason != NULL) { @@ -5255,44 +5324,6 @@ return build_fold_addr_expr(decl); } -// Whether this type is compatible with T. - -bool -Named_type::is_compatible(const Type* t, Type_compatible compatible, - std::string* reason) const -{ - if (compatible == COMPATIBLE_IDENTICAL) - return this == t; - - // In general, different named types are not compatible other than - // for type conversion. An exception is assigning to an variable - // with interface type. - if (t->named_type() != NULL && compatible != COMPATIBLE_FOR_CONVERSION) - { - if (reason != NULL) - { - size_t len = (this->name().length() - + t->named_type()->name().length() - + 100); - char* buf = new char[len]; - snprintf(buf, len, _("cannot use type %s as type %s"), - t->named_type()->message_name().c_str(), - this->message_name().c_str()); - reason->assign(buf); - delete[] buf; - } - return false; - } - - // We use the seen_ flag to cut off recursion. - if (this->seen_) - return this->type_->base() == t->base(); - this->seen_ = true; - bool ret = Type::are_compatible_for(this->type_, t, compatible, reason); - this->seen_ = false; - return ret; -} - // Return whether a named type has any hidden fields. bool diff -r b0b47113eebd go/types.h --- a/go/types.h Fri Aug 27 19:29:10 2010 -0700 +++ b/go/types.h Tue Aug 31 10:02:07 2010 -0700 @@ -495,40 +495,27 @@ verify() { return this->do_verify(); } + // Return true if two types are identical. If this returns false, + // and REASON is not NULL, it may set *REASON. + static bool + are_identical(const Type* lhs, const Type* rhs, std::string* reason); + // Return true if two types are compatible for use in a binary // operation. This is an equivalence relation. static bool are_compatible_for_binop(const Type* t1, const Type* t2); - // Return true if a value with type RHS may be assigned to a value - // with type LHS. This also controls whether a value with type RHS - // may be passed to a function which expects type LHS, and whether a - // value with type RHS may be returned from a function which returns - // type LHS. This is not an equivalence relation. If this returns - // false, and REASON is not NULL, it sets *REASON to an optional - // reason. + // Return true if a value with type RHS is assignable to a variable + // with type LHS. This is not an equivalence relation. If this + // returns false, and REASON is not NULL, it sets *REASON. static bool - are_compatible_for_assign(const Type* lhs, const Type* rhs, - std::string* reason) - { return Type::are_assignment_compatible(lhs, rhs, false, reason); } - - // Return true if a value with type RHS may be converted to a - // valuewith type LHS. If this returns false, and REASON is not - // NULL, it sets *REASON to an optional reason. + are_assignable(const Type* lhs, const Type* rhs, std::string* reason); + + // Return true if a value with type RHS may be converted to type + // LHS. If this returns false, and REASON is not NULL, it sets + // *REASON. static bool - are_compatible_for_conversion(const Type* lhs, const Type* rhs, - std::string* reason) - { return Type::are_assignment_compatible(lhs, rhs, true, reason); } - - // Return true if two types are compatible. - static bool - are_compatible(const Type* lhs, const Type* rhs) - { return Type::are_compatible_for(lhs, rhs, COMPATIBLE_COMPATIBLE, NULL); } - - // Return true if two types are identical. - static bool - are_identical(const Type* lhs, const Type* rhs) - { return Type::are_compatible_for(lhs, rhs, COMPATIBLE_IDENTICAL, NULL); } + are_convertible(const Type* lhs, const Type* rhs, std::string* reason); // Whether this type has any hidden fields which are not visible in // the current compilation, such as a field whose name begins with a @@ -538,8 +525,8 @@ has_hidden_fields(const Named_type* within, std::string* reason) const; // Return a hash code for this type for the method hash table. - // Types which are equivalent according to are_compatible_for_method - // will have the same hash code. + // Types which are equivalent according to are_identical will have + // the same hash code. unsigned int hash_for_method(Gogo*) const; @@ -635,11 +622,21 @@ is_boolean_type() const { return this->base()->classification_ == TYPE_BOOLEAN; } + // Return true if this is an abstract boolean type. + bool + is_abstract_boolean_type() const + { return this->classification_ == TYPE_BOOLEAN; } + // Return true if this is a string type. bool is_string_type() const { return this->base()->classification_ == TYPE_STRING; } + // Return true if this is an abstract string type. + bool + is_abstract_string_type() const + { return this->classification_ == TYPE_STRING; } + // Return true if this is the sink type. This is the type of the // blank identifier _. bool @@ -818,8 +815,8 @@ reflection(Gogo*) const; // Return a mangled name for the type. This is a name which can be - // used in assembler code. Types which compare as equal according - // to COMPATIBLE_SAME should have the same manged name. + // used in assembler code. Identical types should have the same + // manged name. std::string mangled_name(Gogo*) const; @@ -835,27 +832,6 @@ protected: Type(Type_classification); - // Different sorts of type compatibility. - enum Type_compatible - { - // Identical types. - COMPATIBLE_IDENTICAL, - // Compatible types. - COMPATIBLE_COMPATIBLE, - // Compatible for conversion. - COMPATIBLE_FOR_CONVERSION - }; - - // Return whether types are compatible. - static bool - are_compatible_for(const Type*, const Type*, Type_compatible, - std::string* reason); - - // Return whether types are assignment compatible. - static bool - are_assignment_compatible(const Type*, const Type*, bool is_conversion, - std::string* reason); - // Functions implemented by the child class. // Traverse the subtypes. @@ -1058,7 +1034,7 @@ public: bool operator()(const Type* t1, const Type* t2) const - { return Type::are_identical(t1, t2); } + { return Type::are_identical(t1, t2, NULL); } }; // An identifier with a type. @@ -1246,7 +1222,7 @@ // Whether this type is the same as T. bool - is_compatible(const Integer_type* t) const; + is_identical(const Integer_type* t) const; protected: unsigned int @@ -1318,7 +1294,7 @@ // Whether this type is the same as T. bool - is_compatible(const Float_type* t) const; + is_identical(const Float_type* t) const; // Return a tree for this type without using a Gogo*. tree @@ -1390,7 +1366,7 @@ // Whether this type is the same as T. bool - is_compatible(const Complex_type* t) const; + is_identical(const Complex_type* t) const; // Return a tree for this type without using a Gogo*. tree @@ -1530,8 +1506,8 @@ // Whether this type is the same as T. bool - is_compatible(const Function_type* t, Type_compatible, - bool ignore_receiver, std::string*) const; + is_identical(const Function_type* t, bool ignore_receiver, + std::string*) const; // Record that this is a varargs function. void @@ -1826,9 +1802,9 @@ unsigned int total_field_count() const; - // Whether this type is compatible with T. + // Whether this type is identical with T. bool - is_compatible(const Struct_type* t, Type_compatible) const; + is_identical(const Struct_type* t) const; // Whether this struct type has any hidden fields. This returns // true if any fields have hidden names, or if any non-pointer @@ -1938,9 +1914,9 @@ length() const { return this->length_; } - // Whether this type is compatible with T. + // Whether this type is identical with T. bool - is_compatible(const Array_type* t, Type_compatible) const; + is_identical(const Array_type* t) const; // Whether this type has any hidden fields. bool @@ -2040,9 +2016,9 @@ val_type() const { return this->val_type_; } - // Whether this type is compatible with T. + // Whether this type is identical with T. bool - is_compatible(const Map_type* t, Type_compatible) const; + is_identical(const Map_type* t) const; // Import a map type. static Map_type* @@ -2123,9 +2099,9 @@ element_type() const { return this->element_type_; } - // Whether this type is compatible with T. + // Whether this type is identical with T. bool - is_compatible(const Channel_type* t, Type_compatible) const; + is_identical(const Channel_type* t) const; // Import a channel type. static Channel_type* @@ -2222,12 +2198,12 @@ bool implements_interface(const Type* t, std::string* reason) const; - // Whether this type is compatible with T. REASON is as in + // Whether this type is identical with T. REASON is as in // implements_interface. bool - is_compatible(const Interface_type* t, Type_compatible) const; - - // Whether we can assign T to this type. is_compatible is known to + is_identical(const Interface_type* t) const; + + // Whether we can assign T to this type. is_identical is known to // be false. bool is_compatible_for_assign(const Interface_type*, std::string* reason) const; @@ -2424,10 +2400,6 @@ interface_method_table(Gogo*, const Interface_type* interface, bool is_pointer); - // Whether this type is compatible with T. - bool - is_compatible(const Type* t, Type_compatible, std::string* reason) const; - // Whether this type has any hidden fields. bool named_type_has_hidden_fields(std::string* reason) const; @@ -2518,10 +2490,10 @@ bool is_visible_; // Whether this type is erroneous. bool is_error_; - // In a recursive operation such as is_compatible, this flag is used - // to prevent infinite recursion when a type refers to itself. This - // is mutable because it is always reset to false when the function - // exits. + // In a recursive operation such as has_hidden_fields, this flag is + // used to prevent infinite recursion when a type refers to itself. + // This is mutable because it is always reset to false when the + // function exits. mutable bool seen_; }; diff -r b0b47113eebd libgo/go/debug/proc/regs_linux_amd64.go --- a/libgo/go/debug/proc/regs_linux_amd64.go Fri Aug 27 19:29:10 2010 -0700 +++ b/libgo/go/debug/proc/regs_linux_amd64.go Tue Aug 31 10:02:07 2010 -0700 @@ -71,7 +71,7 @@ return r.setter(&r.PtraceRegs) } -func (r *amd64Regs) Names() []string { return &names } +func (r *amd64Regs) Names() []string { return names[0:] } func (r *amd64Regs) Get(i int) Word { switch i { diff -r b0b47113eebd libgo/go/exp/eval/eval_test.go --- a/libgo/go/exp/eval/eval_test.go Fri Aug 27 19:29:10 2010 -0700 +++ b/libgo/go/exp/eval/eval_test.go Tue Aug 31 10:02:07 2010 -0700 @@ -205,7 +205,7 @@ type testFunc struct{} -func (*testFunc) NewFrame() *Frame { return &Frame{nil, &[2]Value{}} } +func (*testFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} } func (*testFunc) Call(t *Thread) { n := t.f.Vars[0].(IntValue).Get(t) @@ -217,7 +217,7 @@ type oneTwoFunc struct{} -func (*oneTwoFunc) NewFrame() *Frame { return &Frame{nil, &[2]Value{}} } +func (*oneTwoFunc) NewFrame() *Frame { return &Frame{nil, make([]Value, 2)} } func (*oneTwoFunc) Call(t *Thread) { t.f.Vars[0].(IntValue).Set(t, 1) diff -r b0b47113eebd libgo/go/os/dir.go --- a/libgo/go/os/dir.go Fri Aug 27 19:29:10 2010 -0700 +++ b/libgo/go/os/dir.go Tue Aug 31 10:02:07 2010 -0700 @@ -62,7 +62,7 @@ if result == nil { break } - var name = string(result.Name[0:clen(&result.Name)]) + var name = string(result.Name[0:clen(result.Name[0:])]) if name == "." || name == ".." { // Useless names continue } diff -r b0b47113eebd libgo/syscalls/exec.go --- a/libgo/syscalls/exec.go Fri Aug 27 19:29:10 2010 -0700 +++ b/libgo/syscalls/exec.go Tue Aug 31 10:02:07 2010 -0700 @@ -162,7 +162,7 @@ ForkLock.Lock(); // Allocate child status pipe close on exec. - if err = Pipe(&p); err != 0 { + if err = Pipe(p[0:]); err != 0 { goto error; } var val int; diff -r b0b47113eebd libgo/syscalls/syscall_linux.go --- a/libgo/syscalls/syscall_linux.go Fri Aug 27 19:29:10 2010 -0700 +++ b/libgo/syscalls/syscall_linux.go Tue Aug 31 10:02:07 2010 -0700 @@ -13,17 +13,6 @@ var dummy *byte const sizeofPtr uintptr = uintptr(unsafe.Sizeof(dummy)) -// See bytes.Copy. -func bytesCopy(dst, src []byte) int { - if len(src) > len(dst) { - src = src[0:len(dst)]; - } - for i, x := range src { - dst[i] = x - } - return len(src) -} - func ptracePeek(req int, pid int, addr uintptr, out []byte) (count int, errno int) { // The peek requests are machine-size oriented, so we wrap it // to retrieve arbitrary-length data. @@ -43,8 +32,8 @@ return 0, errno; } *(*_C_long)(unsafe.Pointer(&buf[0])) = val; - n += bytesCopy(out, buf[addr%sizeofPtr:len(buf)]); - out = out[n:len(out)]; + n += copy(out, buf[addr%sizeofPtr:]); + out = out[n:]; } // Remainder. @@ -57,9 +46,9 @@ return n, errno; } *(*_C_long)(unsafe.Pointer(&buf[0])) = val; - copied := bytesCopy(out, &buf); + copied := copy(out, buf[0:]); n += copied; - out = out[copied:len(out)]; + out = out[copied:]; } return n, 0; @@ -84,7 +73,7 @@ if libc_ptrace(peekReq, Pid_t(pid), addr - addr%sizeofPtr, &buf[0]) < 0 { return 0, GetErrno(); } - n += bytesCopy(buf[addr%sizeofPtr:len(buf)], data); + n += copy(buf[addr%sizeofPtr:], data); word := (*byte)(unsafe.Pointer(*((*uintptr)(unsafe.Pointer(&buf[0]))))); if libc_ptrace(pokeReq, Pid_t(pid), addr - addr%sizeofPtr, word) < 0 { return 0, GetErrno(); @@ -108,7 +97,7 @@ if libc_ptrace(peekReq, Pid_t(pid), addr+uintptr(n), &buf[0]) < 0 { return n, GetErrno(); } - bytesCopy(&buf, data); + copy(buf[0:], data); word := (*byte)(unsafe.Pointer(*((*uintptr)(unsafe.Pointer(&buf[0]))))); if libc_ptrace(pokeReq, Pid_t(pid), addr+uintptr(n), word) < 0 { return n, GetErrno();