@@ -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<int>(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<int>(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;
@@ -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.
@@ -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");
@@ -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(),
@@ -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
@@ -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_;
};
@@ -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 {
@@ -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)
@@ -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
}
@@ -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;
@@ -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();