compiler, runtime: Implement struct and array comparisons.
From-SVN: r182971
This commit is contained in:
parent
4b6aaa996e
commit
f9f9698753
|
@ -379,9 +379,9 @@ class Backend
|
|||
// must be a pointer to this struct type.
|
||||
//
|
||||
// We must create the named structure before we know its
|
||||
// initializer, because the initializer refer to its own address.
|
||||
// After calling this the frontend will call
|
||||
// set_immutable_struct_initializer.
|
||||
// initializer, because the initializer may refer to its own
|
||||
// address. After calling this the frontend will call
|
||||
// immutable_struct_set_init.
|
||||
virtual Bvariable*
|
||||
immutable_struct(const std::string& name, bool is_common, Btype* type,
|
||||
Location) = 0;
|
||||
|
@ -400,8 +400,8 @@ class Backend
|
|||
|
||||
// Create a reference to a named immutable initialized data
|
||||
// structure defined in some other package. This will be a
|
||||
// structure created by a call to immutable_struct_expression with
|
||||
// the same NAME and TYPE and with IS_COMMON passed as false. This
|
||||
// structure created by a call to immutable_struct with the same
|
||||
// NAME and TYPE and with IS_COMMON passed as false. This
|
||||
// corresponds to an extern const global variable in C.
|
||||
virtual Bvariable*
|
||||
immutable_struct_reference(const std::string& name, Btype* type,
|
||||
|
|
|
@ -1135,6 +1135,63 @@ Expression::make_temporary_reference(Temporary_statement* statement,
|
|||
return new Temporary_reference_expression(statement, location);
|
||||
}
|
||||
|
||||
// Class Set_and_use_temporary_expression.
|
||||
|
||||
// Return the type.
|
||||
|
||||
Type*
|
||||
Set_and_use_temporary_expression::do_type()
|
||||
{
|
||||
return this->statement_->type();
|
||||
}
|
||||
|
||||
// Take the address.
|
||||
|
||||
void
|
||||
Set_and_use_temporary_expression::do_address_taken(bool)
|
||||
{
|
||||
this->statement_->set_is_address_taken();
|
||||
}
|
||||
|
||||
// Return the backend representation.
|
||||
|
||||
tree
|
||||
Set_and_use_temporary_expression::do_get_tree(Translate_context* context)
|
||||
{
|
||||
Bvariable* bvar = this->statement_->get_backend_variable(context);
|
||||
tree var_tree = var_to_tree(bvar);
|
||||
tree expr_tree = this->expr_->get_tree(context);
|
||||
if (var_tree == error_mark_node || expr_tree == error_mark_node)
|
||||
return error_mark_node;
|
||||
Location loc = this->location();
|
||||
return build2_loc(loc.gcc_location(), COMPOUND_EXPR, TREE_TYPE(var_tree),
|
||||
build2_loc(loc.gcc_location(), MODIFY_EXPR, void_type_node,
|
||||
var_tree, expr_tree),
|
||||
var_tree);
|
||||
}
|
||||
|
||||
// Dump.
|
||||
|
||||
void
|
||||
Set_and_use_temporary_expression::do_dump_expression(
|
||||
Ast_dump_context* ast_dump_context) const
|
||||
{
|
||||
ast_dump_context->ostream() << '(';
|
||||
ast_dump_context->dump_temp_variable_name(this->statement_);
|
||||
ast_dump_context->ostream() << " = ";
|
||||
this->expr_->dump_expression(ast_dump_context);
|
||||
ast_dump_context->ostream() << ')';
|
||||
}
|
||||
|
||||
// Make a set-and-use temporary.
|
||||
|
||||
Set_and_use_temporary_expression*
|
||||
Expression::make_set_and_use_temporary(Temporary_statement* statement,
|
||||
Expression* expr, Location location)
|
||||
{
|
||||
return new Set_and_use_temporary_expression(statement, expr, location);
|
||||
}
|
||||
|
||||
// A sink expression--a use of the blank identifier _.
|
||||
|
||||
class Sink_expression : public Expression
|
||||
|
@ -4468,11 +4525,38 @@ Unary_expression::do_check_types(Gogo*)
|
|||
tree
|
||||
Unary_expression::do_get_tree(Translate_context* context)
|
||||
{
|
||||
Location loc = this->location();
|
||||
|
||||
// Taking the address of a set-and-use-temporary expression requires
|
||||
// setting the temporary and then taking the address.
|
||||
if (this->op_ == OPERATOR_AND)
|
||||
{
|
||||
Set_and_use_temporary_expression* sut =
|
||||
this->expr_->set_and_use_temporary_expression();
|
||||
if (sut != NULL)
|
||||
{
|
||||
Temporary_statement* temp = sut->temporary();
|
||||
Bvariable* bvar = temp->get_backend_variable(context);
|
||||
tree var_tree = var_to_tree(bvar);
|
||||
Expression* val = sut->expression();
|
||||
tree val_tree = val->get_tree(context);
|
||||
if (var_tree == error_mark_node || val_tree == error_mark_node)
|
||||
return error_mark_node;
|
||||
tree addr_tree = build_fold_addr_expr_loc(loc.gcc_location(),
|
||||
var_tree);
|
||||
return build2_loc(loc.gcc_location(), COMPOUND_EXPR,
|
||||
TREE_TYPE(addr_tree),
|
||||
build2_loc(sut->location().gcc_location(),
|
||||
MODIFY_EXPR, void_type_node,
|
||||
var_tree, val_tree),
|
||||
addr_tree);
|
||||
}
|
||||
}
|
||||
|
||||
tree expr = this->expr_->get_tree(context);
|
||||
if (expr == error_mark_node)
|
||||
return error_mark_node;
|
||||
|
||||
Location loc = this->location();
|
||||
switch (this->op_)
|
||||
{
|
||||
case OPERATOR_PLUS:
|
||||
|
@ -5398,7 +5482,8 @@ Binary_expression::eval_complex(Operator op, Type* left_type,
|
|||
// constants.
|
||||
|
||||
Expression*
|
||||
Binary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
|
||||
Binary_expression::do_lower(Gogo* gogo, Named_object*,
|
||||
Statement_inserter* inserter, int)
|
||||
{
|
||||
Location location = this->location();
|
||||
Operator op = this->op_;
|
||||
|
@ -5727,9 +5812,183 @@ Binary_expression::do_lower(Gogo*, Named_object*, Statement_inserter*, int)
|
|||
mpz_clear(right_val);
|
||||
}
|
||||
|
||||
// Lower struct and array comparisons.
|
||||
if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ)
|
||||
{
|
||||
if (left->type()->struct_type() != NULL)
|
||||
return this->lower_struct_comparison(gogo, inserter);
|
||||
else if (left->type()->array_type() != NULL
|
||||
&& !left->type()->is_slice_type())
|
||||
return this->lower_array_comparison(gogo, inserter);
|
||||
}
|
||||
|
||||
return this;
|
||||
}
|
||||
|
||||
// Lower a struct comparison.
|
||||
|
||||
Expression*
|
||||
Binary_expression::lower_struct_comparison(Gogo* gogo,
|
||||
Statement_inserter* inserter)
|
||||
{
|
||||
Struct_type* st = this->left_->type()->struct_type();
|
||||
Struct_type* st2 = this->right_->type()->struct_type();
|
||||
if (st2 == NULL)
|
||||
return this;
|
||||
if (st != st2 && !Type::are_identical(st, st2, false, NULL))
|
||||
return this;
|
||||
if (!Type::are_compatible_for_comparison(true, this->left_->type(),
|
||||
this->right_->type(), NULL))
|
||||
return this;
|
||||
|
||||
// See if we can compare using memcmp. As a heuristic, we use
|
||||
// memcmp rather than field references and comparisons if there are
|
||||
// more than two fields.
|
||||
if (st->compare_is_identity() && st->total_field_count() > 2)
|
||||
return this->lower_compare_to_memcmp(gogo, inserter);
|
||||
|
||||
Location loc = this->location();
|
||||
|
||||
Expression* left = this->left_;
|
||||
Temporary_statement* left_temp = NULL;
|
||||
if (left->var_expression() == NULL
|
||||
&& left->temporary_reference_expression() == NULL)
|
||||
{
|
||||
left_temp = Statement::make_temporary(left->type(), NULL, loc);
|
||||
inserter->insert(left_temp);
|
||||
left = Expression::make_set_and_use_temporary(left_temp, left, loc);
|
||||
}
|
||||
|
||||
Expression* right = this->right_;
|
||||
Temporary_statement* right_temp = NULL;
|
||||
if (right->var_expression() == NULL
|
||||
&& right->temporary_reference_expression() == NULL)
|
||||
{
|
||||
right_temp = Statement::make_temporary(right->type(), NULL, loc);
|
||||
inserter->insert(right_temp);
|
||||
right = Expression::make_set_and_use_temporary(right_temp, right, loc);
|
||||
}
|
||||
|
||||
Expression* ret = Expression::make_boolean(true, loc);
|
||||
const Struct_field_list* fields = st->fields();
|
||||
unsigned int field_index = 0;
|
||||
for (Struct_field_list::const_iterator pf = fields->begin();
|
||||
pf != fields->end();
|
||||
++pf, ++field_index)
|
||||
{
|
||||
if (field_index > 0)
|
||||
{
|
||||
if (left_temp == NULL)
|
||||
left = left->copy();
|
||||
else
|
||||
left = Expression::make_temporary_reference(left_temp, loc);
|
||||
if (right_temp == NULL)
|
||||
right = right->copy();
|
||||
else
|
||||
right = Expression::make_temporary_reference(right_temp, loc);
|
||||
}
|
||||
Expression* f1 = Expression::make_field_reference(left, field_index,
|
||||
loc);
|
||||
Expression* f2 = Expression::make_field_reference(right, field_index,
|
||||
loc);
|
||||
Expression* cond = Expression::make_binary(OPERATOR_EQEQ, f1, f2, loc);
|
||||
ret = Expression::make_binary(OPERATOR_ANDAND, ret, cond, loc);
|
||||
}
|
||||
|
||||
if (this->op_ == OPERATOR_NOTEQ)
|
||||
ret = Expression::make_unary(OPERATOR_NOT, ret, loc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Lower an array comparison.
|
||||
|
||||
Expression*
|
||||
Binary_expression::lower_array_comparison(Gogo* gogo,
|
||||
Statement_inserter* inserter)
|
||||
{
|
||||
Array_type* at = this->left_->type()->array_type();
|
||||
Array_type* at2 = this->right_->type()->array_type();
|
||||
if (at2 == NULL)
|
||||
return this;
|
||||
if (at != at2 && !Type::are_identical(at, at2, false, NULL))
|
||||
return this;
|
||||
if (!Type::are_compatible_for_comparison(true, this->left_->type(),
|
||||
this->right_->type(), NULL))
|
||||
return this;
|
||||
|
||||
// Call memcmp directly if possible. This may let the middle-end
|
||||
// optimize the call.
|
||||
if (at->compare_is_identity())
|
||||
return this->lower_compare_to_memcmp(gogo, inserter);
|
||||
|
||||
// Call the array comparison function.
|
||||
Named_object* hash_fn;
|
||||
Named_object* equal_fn;
|
||||
at->type_functions(gogo, this->left_->type()->named_type(), NULL, NULL,
|
||||
&hash_fn, &equal_fn);
|
||||
|
||||
Location loc = this->location();
|
||||
|
||||
Expression* func = Expression::make_func_reference(equal_fn, NULL, loc);
|
||||
|
||||
Expression_list* args = new Expression_list();
|
||||
args->push_back(this->operand_address(inserter, this->left_));
|
||||
args->push_back(this->operand_address(inserter, this->right_));
|
||||
args->push_back(Expression::make_type_info(at, TYPE_INFO_SIZE));
|
||||
|
||||
Expression* ret = Expression::make_call(func, args, false, loc);
|
||||
|
||||
if (this->op_ == OPERATOR_NOTEQ)
|
||||
ret = Expression::make_unary(OPERATOR_NOT, ret, loc);
|
||||
|
||||
return ret;
|
||||
}
|
||||
|
||||
// Lower a struct or array comparison to a call to memcmp.
|
||||
|
||||
Expression*
|
||||
Binary_expression::lower_compare_to_memcmp(Gogo*, Statement_inserter* inserter)
|
||||
{
|
||||
Location loc = this->location();
|
||||
|
||||
Expression* a1 = this->operand_address(inserter, this->left_);
|
||||
Expression* a2 = this->operand_address(inserter, this->right_);
|
||||
Expression* len = Expression::make_type_info(this->left_->type(),
|
||||
TYPE_INFO_SIZE);
|
||||
|
||||
Expression* call = Runtime::make_call(Runtime::MEMCMP, loc, 3, a1, a2, len);
|
||||
|
||||
mpz_t zval;
|
||||
mpz_init_set_ui(zval, 0);
|
||||
Expression* zero = Expression::make_integer(&zval, NULL, loc);
|
||||
mpz_clear(zval);
|
||||
|
||||
return Expression::make_binary(this->op_, call, zero, loc);
|
||||
}
|
||||
|
||||
// Return the address of EXPR, cast to unsafe.Pointer.
|
||||
|
||||
Expression*
|
||||
Binary_expression::operand_address(Statement_inserter* inserter,
|
||||
Expression* expr)
|
||||
{
|
||||
Location loc = this->location();
|
||||
|
||||
if (!expr->is_addressable())
|
||||
{
|
||||
Temporary_statement* temp = Statement::make_temporary(expr->type(), NULL,
|
||||
loc);
|
||||
inserter->insert(temp);
|
||||
expr = Expression::make_set_and_use_temporary(temp, expr, loc);
|
||||
}
|
||||
expr = Expression::make_unary(OPERATOR_AND, expr, loc);
|
||||
static_cast<Unary_expression*>(expr)->set_does_not_escape();
|
||||
Type* void_type = Type::make_void_type();
|
||||
Type* unsafe_pointer_type = Type::make_pointer_type(void_type);
|
||||
return Expression::make_cast(unsafe_pointer_type, expr, loc);
|
||||
}
|
||||
|
||||
// Return the integer constant value, if it has one.
|
||||
|
||||
bool
|
||||
|
@ -6072,49 +6331,28 @@ Binary_expression::check_operator_type(Operator op, Type* type, Type* otype,
|
|||
|
||||
case OPERATOR_EQEQ:
|
||||
case OPERATOR_NOTEQ:
|
||||
if (type->integer_type() == NULL
|
||||
&& type->float_type() == NULL
|
||||
&& type->complex_type() == NULL
|
||||
&& !type->is_string_type()
|
||||
&& type->points_to() == NULL
|
||||
&& !type->is_nil_type()
|
||||
&& !type->is_boolean_type()
|
||||
&& type->interface_type() == NULL
|
||||
&& (type->array_type() == NULL
|
||||
|| type->array_type()->length() != NULL)
|
||||
&& type->map_type() == NULL
|
||||
&& type->channel_type() == NULL
|
||||
&& type->function_type() == NULL)
|
||||
{
|
||||
error_at(location,
|
||||
("expected integer, floating, complex, string, pointer, "
|
||||
"boolean, interface, slice, map, channel, "
|
||||
"or function type"));
|
||||
return false;
|
||||
}
|
||||
if ((type->is_slice_type()
|
||||
|| type->map_type() != NULL
|
||||
|| type->function_type() != NULL)
|
||||
&& !otype->is_nil_type())
|
||||
{
|
||||
error_at(location,
|
||||
("slice, map, and function types may only "
|
||||
"be compared to nil"));
|
||||
return false;
|
||||
}
|
||||
{
|
||||
std::string reason;
|
||||
if (!Type::are_compatible_for_comparison(true, type, otype, &reason))
|
||||
{
|
||||
error_at(location, "%s", reason.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OPERATOR_LT:
|
||||
case OPERATOR_LE:
|
||||
case OPERATOR_GT:
|
||||
case OPERATOR_GE:
|
||||
if (type->integer_type() == NULL
|
||||
&& type->float_type() == NULL
|
||||
&& !type->is_string_type())
|
||||
{
|
||||
error_at(location, "expected integer, floating, or string type");
|
||||
return false;
|
||||
}
|
||||
{
|
||||
std::string reason;
|
||||
if (!Type::are_compatible_for_comparison(false, type, otype, &reason))
|
||||
{
|
||||
error_at(location, "%s", reason.c_str());
|
||||
return false;
|
||||
}
|
||||
}
|
||||
break;
|
||||
|
||||
case OPERATOR_PLUS:
|
||||
|
@ -12740,10 +12978,10 @@ class Composite_literal_expression : public Parser_expression
|
|||
lower_struct(Gogo*, Type*);
|
||||
|
||||
Expression*
|
||||
lower_array(Type*);
|
||||
lower_array(Gogo*, Type*);
|
||||
|
||||
Expression*
|
||||
make_array(Type*, Expression_list*);
|
||||
make_array(Gogo*, Type*, Expression_list*);
|
||||
|
||||
Expression*
|
||||
lower_map(Gogo*, Named_object*, Statement_inserter*, Type*);
|
||||
|
@ -12810,7 +13048,7 @@ Composite_literal_expression::do_lower(Gogo* gogo, Named_object* function,
|
|||
else if (type->struct_type() != NULL)
|
||||
ret = this->lower_struct(gogo, type);
|
||||
else if (type->array_type() != NULL)
|
||||
ret = this->lower_array(type);
|
||||
ret = this->lower_array(gogo, type);
|
||||
else if (type->map_type() != NULL)
|
||||
ret = this->lower_map(gogo, function, inserter, type);
|
||||
else
|
||||
|
@ -13023,11 +13261,11 @@ Composite_literal_expression::lower_struct(Gogo* gogo, Type* type)
|
|||
// Lower an array composite literal.
|
||||
|
||||
Expression*
|
||||
Composite_literal_expression::lower_array(Type* type)
|
||||
Composite_literal_expression::lower_array(Gogo* gogo, Type* type)
|
||||
{
|
||||
Location location = this->location();
|
||||
if (this->vals_ == NULL || !this->has_keys_)
|
||||
return this->make_array(type, this->vals_);
|
||||
return this->make_array(gogo, type, this->vals_);
|
||||
|
||||
std::vector<Expression*> vals;
|
||||
vals.reserve(this->vals_->size());
|
||||
|
@ -13127,14 +13365,15 @@ Composite_literal_expression::lower_array(Type* type)
|
|||
for (size_t i = 0; i < size; ++i)
|
||||
list->push_back(vals[i]);
|
||||
|
||||
return this->make_array(type, list);
|
||||
return this->make_array(gogo, type, list);
|
||||
}
|
||||
|
||||
// Actually build the array composite literal. This handles
|
||||
// [...]{...}.
|
||||
|
||||
Expression*
|
||||
Composite_literal_expression::make_array(Type* type, Expression_list* vals)
|
||||
Composite_literal_expression::make_array(Gogo* gogo, Type* type,
|
||||
Expression_list* vals)
|
||||
{
|
||||
Location location = this->location();
|
||||
Array_type* at = type->array_type();
|
||||
|
@ -13146,6 +13385,10 @@ Composite_literal_expression::make_array(Type* type, Expression_list* vals)
|
|||
Expression* elen = Expression::make_integer(&vlen, NULL, location);
|
||||
mpz_clear(vlen);
|
||||
at = Type::make_array_type(at->element_type(), elen);
|
||||
|
||||
// This is after the finalize_methods pass, so run that now.
|
||||
at->finalize_methods(gogo);
|
||||
|
||||
type = at;
|
||||
}
|
||||
if (at->length() != NULL)
|
||||
|
|
|
@ -25,6 +25,7 @@ class Struct_field;
|
|||
class Expression_list;
|
||||
class Var_expression;
|
||||
class Temporary_reference_expression;
|
||||
class Set_and_use_temporary_expression;
|
||||
class String_expression;
|
||||
class Binary_expression;
|
||||
class Call_expression;
|
||||
|
@ -60,6 +61,7 @@ class Expression
|
|||
EXPRESSION_CONST_REFERENCE,
|
||||
EXPRESSION_VAR_REFERENCE,
|
||||
EXPRESSION_TEMPORARY_REFERENCE,
|
||||
EXPRESSION_SET_AND_USE_TEMPORARY,
|
||||
EXPRESSION_SINK,
|
||||
EXPRESSION_FUNC_REFERENCE,
|
||||
EXPRESSION_UNKNOWN_REFERENCE,
|
||||
|
@ -134,6 +136,13 @@ class Expression
|
|||
static Temporary_reference_expression*
|
||||
make_temporary_reference(Temporary_statement*, Location);
|
||||
|
||||
// Make an expressions which sets a temporary variable and then
|
||||
// evaluates to a reference to that temporary variable. This is
|
||||
// used to set a temporary variable while retaining the order of
|
||||
// evaluation.
|
||||
static Set_and_use_temporary_expression*
|
||||
make_set_and_use_temporary(Temporary_statement*, Expression*, Location);
|
||||
|
||||
// Make a sink expression--a reference to the blank identifier _.
|
||||
static Expression*
|
||||
make_sink(Location);
|
||||
|
@ -396,6 +405,15 @@ class Expression
|
|||
EXPRESSION_TEMPORARY_REFERENCE>();
|
||||
}
|
||||
|
||||
// If this is a set-and-use-temporary, return the
|
||||
// Set_and_use_temporary_expression. Otherwise, return NULL.
|
||||
Set_and_use_temporary_expression*
|
||||
set_and_use_temporary_expression()
|
||||
{
|
||||
return this->convert<Set_and_use_temporary_expression,
|
||||
EXPRESSION_SET_AND_USE_TEMPORARY>();
|
||||
}
|
||||
|
||||
// Return whether this is a sink expression.
|
||||
bool
|
||||
is_sink_expression() const
|
||||
|
@ -1021,6 +1039,62 @@ class Temporary_reference_expression : public Expression
|
|||
bool is_lvalue_;
|
||||
};
|
||||
|
||||
// Set and use a temporary variable.
|
||||
|
||||
class Set_and_use_temporary_expression : public Expression
|
||||
{
|
||||
public:
|
||||
Set_and_use_temporary_expression(Temporary_statement* statement,
|
||||
Expression* expr, Location location)
|
||||
: Expression(EXPRESSION_SET_AND_USE_TEMPORARY, location),
|
||||
statement_(statement), expr_(expr)
|
||||
{ }
|
||||
|
||||
// Return the temporary.
|
||||
Temporary_statement*
|
||||
temporary() const
|
||||
{ return this->statement_; }
|
||||
|
||||
// Return the expression.
|
||||
Expression*
|
||||
expression() const
|
||||
{ return this->expr_; }
|
||||
|
||||
protected:
|
||||
Type*
|
||||
do_type();
|
||||
|
||||
void
|
||||
do_determine_type(const Type_context*)
|
||||
{ }
|
||||
|
||||
Expression*
|
||||
do_copy()
|
||||
{
|
||||
return make_set_and_use_temporary(this->statement_, this->expr_,
|
||||
this->location());
|
||||
}
|
||||
|
||||
bool
|
||||
do_is_addressable() const
|
||||
{ return true; }
|
||||
|
||||
void
|
||||
do_address_taken(bool);
|
||||
|
||||
tree
|
||||
do_get_tree(Translate_context*);
|
||||
|
||||
void
|
||||
do_dump_expression(Ast_dump_context*) const;
|
||||
|
||||
private:
|
||||
// The statement where the temporary variable is defined.
|
||||
Temporary_statement* statement_;
|
||||
// The expression to assign to the temporary.
|
||||
Expression* expr_;
|
||||
};
|
||||
|
||||
// A string expression.
|
||||
|
||||
class String_expression : public Expression
|
||||
|
@ -1200,6 +1274,18 @@ class Binary_expression : public Expression
|
|||
do_dump_expression(Ast_dump_context*) const;
|
||||
|
||||
private:
|
||||
Expression*
|
||||
lower_struct_comparison(Gogo*, Statement_inserter*);
|
||||
|
||||
Expression*
|
||||
lower_array_comparison(Gogo*, Statement_inserter*);
|
||||
|
||||
Expression*
|
||||
lower_compare_to_memcmp(Gogo*, Statement_inserter*);
|
||||
|
||||
Expression*
|
||||
operand_address(Statement_inserter*, Expression*);
|
||||
|
||||
// The binary operator to apply.
|
||||
Operator op_;
|
||||
// The left hand side operand.
|
||||
|
|
|
@ -106,6 +106,9 @@ go_parse_input_files(const char** filenames, unsigned int filename_count,
|
|||
// form which is easier to use.
|
||||
::gogo->lower_parse_tree();
|
||||
|
||||
// Write out queued up functions for hash and comparison of types.
|
||||
::gogo->write_specific_type_functions();
|
||||
|
||||
// Now that we have seen all the names, verify that types are
|
||||
// correct.
|
||||
::gogo->verify_types();
|
||||
|
|
|
@ -116,10 +116,10 @@ Gogo::define_builtin_function_trees()
|
|||
NULL_TREE),
|
||||
true);
|
||||
|
||||
// We use __builtin_memmove for the predeclared copy function.
|
||||
define_builtin(BUILT_IN_MEMMOVE, "__builtin_memmove", "memmove",
|
||||
build_function_type_list(ptr_type_node,
|
||||
ptr_type_node,
|
||||
// We use __builtin_memcmp for struct comparisons.
|
||||
define_builtin(BUILT_IN_MEMCMP, "__builtin_memcmp", "memcmp",
|
||||
build_function_type_list(integer_type_node,
|
||||
const_ptr_type_node,
|
||||
const_ptr_type_node,
|
||||
size_type_node,
|
||||
NULL_TREE),
|
||||
|
@ -647,7 +647,8 @@ Gogo::write_globals()
|
|||
this->build_interface_method_tables();
|
||||
|
||||
Bindings* bindings = this->current_bindings();
|
||||
size_t count = bindings->size_definitions();
|
||||
size_t count_definitions = bindings->size_definitions();
|
||||
size_t count = count_definitions;
|
||||
|
||||
tree* vec = new tree[count];
|
||||
|
||||
|
@ -822,6 +823,10 @@ Gogo::write_globals()
|
|||
|| this->is_main_package())
|
||||
this->write_initialization_function(init_fndecl, init_stmt_list);
|
||||
|
||||
// We should not have seen any new bindings created during the
|
||||
// conversion.
|
||||
go_assert(count_definitions == this->current_bindings()->size_definitions());
|
||||
|
||||
// Pass everything back to the middle-end.
|
||||
|
||||
wrapup_global_declarations(vec, count);
|
||||
|
|
|
@ -38,6 +38,8 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int int_type_size,
|
|||
unique_prefix_(),
|
||||
unique_prefix_specified_(false),
|
||||
interface_types_(),
|
||||
specific_type_functions_(),
|
||||
specific_type_functions_are_written_(false),
|
||||
named_types_are_converted_(false)
|
||||
{
|
||||
const Location loc = Linemap::predeclared_location();
|
||||
|
@ -978,6 +980,16 @@ Gogo::declare_package_type(const std::string& name, Location location)
|
|||
return this->package_->bindings()->add_type_declaration(name, NULL, location);
|
||||
}
|
||||
|
||||
// Declare a function at the package level.
|
||||
|
||||
Named_object*
|
||||
Gogo::declare_package_function(const std::string& name, Function_type* type,
|
||||
Location location)
|
||||
{
|
||||
return this->package_->bindings()->add_function_declaration(name, NULL, type,
|
||||
location);
|
||||
}
|
||||
|
||||
// Define a type which was already declared.
|
||||
|
||||
void
|
||||
|
@ -1116,6 +1128,46 @@ Gogo::clear_file_scope()
|
|||
}
|
||||
}
|
||||
|
||||
// Queue up a type specific function for later writing. These are
|
||||
// written out in write_specific_type_functions, called after the
|
||||
// parse tree is lowered.
|
||||
|
||||
void
|
||||
Gogo::queue_specific_type_function(Type* type, Named_type* name,
|
||||
const std::string& hash_name,
|
||||
Function_type* hash_fntype,
|
||||
const std::string& equal_name,
|
||||
Function_type* equal_fntype)
|
||||
{
|
||||
go_assert(!this->specific_type_functions_are_written_);
|
||||
go_assert(!this->in_global_scope());
|
||||
Specific_type_function* tsf = new Specific_type_function(type, name,
|
||||
hash_name,
|
||||
hash_fntype,
|
||||
equal_name,
|
||||
equal_fntype);
|
||||
this->specific_type_functions_.push_back(tsf);
|
||||
}
|
||||
|
||||
// Write out type specific functions.
|
||||
|
||||
void
|
||||
Gogo::write_specific_type_functions()
|
||||
{
|
||||
while (!this->specific_type_functions_.empty())
|
||||
{
|
||||
Specific_type_function* tsf = this->specific_type_functions_.back();
|
||||
this->specific_type_functions_.pop_back();
|
||||
tsf->type->write_specific_type_functions(this, tsf->name,
|
||||
tsf->hash_name,
|
||||
tsf->hash_fntype,
|
||||
tsf->equal_name,
|
||||
tsf->equal_fntype);
|
||||
delete tsf;
|
||||
}
|
||||
this->specific_type_functions_are_written_ = true;
|
||||
}
|
||||
|
||||
// Traverse the tree.
|
||||
|
||||
void
|
||||
|
@ -1468,6 +1520,10 @@ Finalize_methods::type(Type* t)
|
|||
t->struct_type()->finalize_methods(this->gogo_);
|
||||
break;
|
||||
|
||||
case Type::TYPE_ARRAY:
|
||||
t->array_type()->finalize_methods(this->gogo_);
|
||||
break;
|
||||
|
||||
default:
|
||||
break;
|
||||
}
|
||||
|
|
|
@ -277,6 +277,11 @@ class Gogo
|
|||
Named_object*
|
||||
declare_function(const std::string&, Function_type*, Location);
|
||||
|
||||
// Declare a function at the package level. This is used for
|
||||
// functions generated for a type.
|
||||
Named_object*
|
||||
declare_package_function(const std::string&, Function_type*, Location);
|
||||
|
||||
// Add a label.
|
||||
Label*
|
||||
add_label_definition(const std::string&, Location);
|
||||
|
@ -364,6 +369,20 @@ class Gogo
|
|||
void
|
||||
clear_file_scope();
|
||||
|
||||
// Queue up a type-specific function to be written out. This is
|
||||
// used when a type-specific function is needed when not at the top
|
||||
// level.
|
||||
void
|
||||
queue_specific_type_function(Type* type, Named_type* name,
|
||||
const std::string& hash_name,
|
||||
Function_type* hash_fntype,
|
||||
const std::string& equal_name,
|
||||
Function_type* equal_fntype);
|
||||
|
||||
// Write out queued specific type functions.
|
||||
void
|
||||
write_specific_type_functions();
|
||||
|
||||
// Traverse the tree. See the Traverse class.
|
||||
void
|
||||
traverse(Traverse*);
|
||||
|
@ -603,6 +622,27 @@ class Gogo
|
|||
// Type used to map special names in the sys package.
|
||||
typedef std::map<std::string, std::string> Sys_names;
|
||||
|
||||
// Type used to queue writing a type specific function.
|
||||
struct Specific_type_function
|
||||
{
|
||||
Type* type;
|
||||
Named_type* name;
|
||||
std::string hash_name;
|
||||
Function_type* hash_fntype;
|
||||
std::string equal_name;
|
||||
Function_type* equal_fntype;
|
||||
|
||||
Specific_type_function(Type* atype, Named_type* aname,
|
||||
const std::string& ahash_name,
|
||||
Function_type* ahash_fntype,
|
||||
const std::string& aequal_name,
|
||||
Function_type* aequal_fntype)
|
||||
: type(atype), name(aname), hash_name(ahash_name),
|
||||
hash_fntype(ahash_fntype), equal_name(aequal_name),
|
||||
equal_fntype(aequal_fntype)
|
||||
{ }
|
||||
};
|
||||
|
||||
// The backend generator.
|
||||
Backend* backend_;
|
||||
// The object used to keep track of file names and line numbers.
|
||||
|
@ -635,6 +675,10 @@ class Gogo
|
|||
bool unique_prefix_specified_;
|
||||
// A list of interface types defined while parsing.
|
||||
std::vector<Interface_type*> interface_types_;
|
||||
// Type specific functions to write out.
|
||||
std::vector<Specific_type_function*> specific_type_functions_;
|
||||
// Whether we are done writing out specific type functions.
|
||||
bool specific_type_functions_are_written_;
|
||||
// Whether named types have been converted.
|
||||
bool named_types_are_converted_;
|
||||
};
|
||||
|
|
|
@ -28,6 +28,9 @@
|
|||
// the name. The third is the parameter types and the fourth is the
|
||||
// result types.
|
||||
|
||||
// The standard C memcmp function, used for struct comparisons.
|
||||
DEF_GO_RUNTIME(MEMCMP, "memcmp", P3(POINTER, POINTER, UINTPTR), R1(INT))
|
||||
|
||||
// Range over a string, returning the next index.
|
||||
DEF_GO_RUNTIME(STRINGITER, "runtime.stringiter", P2(STRING, INT), R1(INT))
|
||||
|
||||
|
|
File diff suppressed because it is too large
Load Diff
|
@ -522,6 +522,21 @@ class Type
|
|||
static bool
|
||||
are_compatible_for_binop(const Type* t1, const Type* t2);
|
||||
|
||||
// Return true if two types are compatible for use with the
|
||||
// comparison operator. IS_EQUALITY_OP is true if this is an
|
||||
// equality comparison, false if it is an ordered comparison. This
|
||||
// is an equivalence relation. If this returns false, and REASON is
|
||||
// not NULL, it sets *REASON.
|
||||
static bool
|
||||
are_compatible_for_comparison(bool is_equality_op, const Type *t1,
|
||||
const Type *t2, std::string* reason);
|
||||
|
||||
// Return true if a type is comparable with itself. This is true of
|
||||
// most types, but false for, e.g., function types.
|
||||
bool
|
||||
is_comparable() const
|
||||
{ return Type::are_compatible_for_comparison(true, this, this, NULL); }
|
||||
|
||||
// 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.
|
||||
|
@ -549,6 +564,13 @@ class Type
|
|||
bool
|
||||
has_hidden_fields(const Named_type* within, std::string* reason) const;
|
||||
|
||||
// Return true if values of this type can be compared using an
|
||||
// identity function which gets nothing but a pointer to the value
|
||||
// and a size.
|
||||
bool
|
||||
compare_is_identity() const
|
||||
{ return this->do_compare_is_identity(); }
|
||||
|
||||
// Return a hash code for this type for the method hash table.
|
||||
// Types which are equivalent according to are_identical will have
|
||||
// the same hash code.
|
||||
|
@ -839,6 +861,20 @@ class Type
|
|||
std::string
|
||||
mangled_name(Gogo*) const;
|
||||
|
||||
// Get the hash and equality functions for a type.
|
||||
void
|
||||
type_functions(Gogo*, Named_type* name, Function_type* hash_fntype,
|
||||
Function_type* equal_fntype, Named_object** hash_fn,
|
||||
Named_object** equal_fn);
|
||||
|
||||
// Write the hash and equality type functions.
|
||||
void
|
||||
write_specific_type_functions(Gogo*, Named_type*,
|
||||
const std::string& hash_name,
|
||||
Function_type* hash_fntype,
|
||||
const std::string& equal_name,
|
||||
Function_type* equal_fntype);
|
||||
|
||||
// Export the type.
|
||||
void
|
||||
export_type(Export* exp) const
|
||||
|
@ -866,6 +902,9 @@ class Type
|
|||
do_has_pointer() const
|
||||
{ return false; }
|
||||
|
||||
virtual bool
|
||||
do_compare_is_identity() const = 0;
|
||||
|
||||
virtual unsigned int
|
||||
do_hash_for_method(Gogo*) const;
|
||||
|
||||
|
@ -878,7 +917,6 @@ class Type
|
|||
virtual void
|
||||
do_reflection(Gogo*, std::string*) const = 0;
|
||||
|
||||
|
||||
virtual void
|
||||
do_mangled_name(Gogo*, std::string*) const = 0;
|
||||
|
||||
|
@ -1002,18 +1040,24 @@ class Type
|
|||
void
|
||||
make_type_descriptor_var(Gogo*);
|
||||
|
||||
// Return the name of the type descriptor variable for an unnamed
|
||||
// type.
|
||||
// Return the name of the type descriptor variable. If NAME is not
|
||||
// NULL, it is the name to use.
|
||||
std::string
|
||||
unnamed_type_descriptor_var_name(Gogo*);
|
||||
type_descriptor_var_name(Gogo*, Named_type* name);
|
||||
|
||||
// Return the name of the type descriptor variable for a named type.
|
||||
std::string
|
||||
type_descriptor_var_name(Gogo*);
|
||||
// Return true if the type descriptor for this type should be
|
||||
// defined in some other package. If NAME is not NULL, it is the
|
||||
// name of this type. If this returns true it sets *PACKAGE to the
|
||||
// package where the type descriptor is defined.
|
||||
bool
|
||||
type_descriptor_defined_elsewhere(Named_type* name, const Package** package);
|
||||
|
||||
// Get the hash and equality functions for a type.
|
||||
// Build the hash and equality type functions for a type which needs
|
||||
// specific functions.
|
||||
void
|
||||
type_functions(const char** hash_fn, const char** equal_fn) const;
|
||||
specific_type_functions(Gogo*, Named_type*, Function_type* hash_fntype,
|
||||
Function_type* equal_fntype, Named_object** hash_fn,
|
||||
Named_object** equal_fn);
|
||||
|
||||
// Build a composite literal for the uncommon type information.
|
||||
Expression*
|
||||
|
@ -1097,6 +1141,14 @@ class Type
|
|||
// A list of builtin named types.
|
||||
static std::vector<Named_type*> named_builtin_types;
|
||||
|
||||
// A map from types which need specific type functions to the type
|
||||
// functions themselves.
|
||||
typedef std::pair<Named_object*, Named_object*> Hash_equal_fn;
|
||||
typedef Unordered_map_hash(const Type*, Hash_equal_fn, Type_hash_identical,
|
||||
Type_identical) Type_functions;
|
||||
|
||||
static Type_functions type_functions_table;
|
||||
|
||||
// The type classification.
|
||||
Type_classification classification_;
|
||||
// The backend representation of the type, once it has been
|
||||
|
@ -1314,6 +1366,10 @@ class Integer_type : public Type
|
|||
is_identical(const Integer_type* t) const;
|
||||
|
||||
protected:
|
||||
bool
|
||||
do_compare_is_identity() const
|
||||
{ return true; }
|
||||
|
||||
unsigned int
|
||||
do_hash_for_method(Gogo*) const;
|
||||
|
||||
|
@ -1383,6 +1439,10 @@ class Float_type : public Type
|
|||
is_identical(const Float_type* t) const;
|
||||
|
||||
protected:
|
||||
bool
|
||||
do_compare_is_identity() const
|
||||
{ return false; }
|
||||
|
||||
unsigned int
|
||||
do_hash_for_method(Gogo*) const;
|
||||
|
||||
|
@ -1448,6 +1508,10 @@ class Complex_type : public Type
|
|||
is_identical(const Complex_type* t) const;
|
||||
|
||||
protected:
|
||||
bool
|
||||
do_compare_is_identity() const
|
||||
{ return false; }
|
||||
|
||||
unsigned int
|
||||
do_hash_for_method(Gogo*) const;
|
||||
|
||||
|
@ -1504,6 +1568,10 @@ class String_type : public Type
|
|||
do_has_pointer() const
|
||||
{ return true; }
|
||||
|
||||
bool
|
||||
do_compare_is_identity() const
|
||||
{ return false; }
|
||||
|
||||
Btype*
|
||||
do_get_backend(Gogo*);
|
||||
|
||||
|
@ -1618,6 +1686,10 @@ class Function_type : public Type
|
|||
do_has_pointer() const
|
||||
{ return true; }
|
||||
|
||||
bool
|
||||
do_compare_is_identity() const
|
||||
{ return false; }
|
||||
|
||||
unsigned int
|
||||
do_hash_for_method(Gogo*) const;
|
||||
|
||||
|
@ -1699,6 +1771,10 @@ class Pointer_type : public Type
|
|||
do_has_pointer() const
|
||||
{ return true; }
|
||||
|
||||
bool
|
||||
do_compare_is_identity() const
|
||||
{ return true; }
|
||||
|
||||
unsigned int
|
||||
do_hash_for_method(Gogo*) const;
|
||||
|
||||
|
@ -1944,6 +2020,14 @@ class Struct_type : public Type
|
|||
static Type*
|
||||
make_struct_type_descriptor_type();
|
||||
|
||||
// Write the hash function for this type.
|
||||
void
|
||||
write_hash_function(Gogo*, Named_type*, Function_type*, Function_type*);
|
||||
|
||||
// Write the equality function for this type.
|
||||
void
|
||||
write_equal_function(Gogo*, Named_type*);
|
||||
|
||||
protected:
|
||||
int
|
||||
do_traverse(Traverse*);
|
||||
|
@ -1954,6 +2038,9 @@ class Struct_type : public Type
|
|||
bool
|
||||
do_has_pointer() const;
|
||||
|
||||
bool
|
||||
do_compare_is_identity() const;
|
||||
|
||||
unsigned int
|
||||
do_hash_for_method(Gogo*) const;
|
||||
|
||||
|
@ -2022,6 +2109,10 @@ class Array_type : public Type
|
|||
array_has_hidden_fields(const Named_type* within, std::string* reason) const
|
||||
{ return this->element_type_->has_hidden_fields(within, reason); }
|
||||
|
||||
// Build the hash and equality functions if necessary.
|
||||
void
|
||||
finalize_methods(Gogo*);
|
||||
|
||||
// Return a tree for the pointer to the values in an array.
|
||||
tree
|
||||
value_pointer_tree(Gogo*, tree array) const;
|
||||
|
@ -2052,6 +2143,14 @@ class Array_type : public Type
|
|||
static Type*
|
||||
make_slice_type_descriptor_type();
|
||||
|
||||
// Write the hash function for this type.
|
||||
void
|
||||
write_hash_function(Gogo*, Named_type*, Function_type*, Function_type*);
|
||||
|
||||
// Write the equality function for this type.
|
||||
void
|
||||
write_equal_function(Gogo*, Named_type*);
|
||||
|
||||
protected:
|
||||
int
|
||||
do_traverse(Traverse* traverse);
|
||||
|
@ -2065,6 +2164,13 @@ class Array_type : public Type
|
|||
return this->length_ == NULL || this->element_type_->has_pointer();
|
||||
}
|
||||
|
||||
bool
|
||||
do_compare_is_identity() const
|
||||
{
|
||||
return (this->length_ != NULL
|
||||
&& this->element_type_->compare_is_identity());
|
||||
}
|
||||
|
||||
unsigned int
|
||||
do_hash_for_method(Gogo*) const;
|
||||
|
||||
|
@ -2155,6 +2261,10 @@ class Map_type : public Type
|
|||
do_has_pointer() const
|
||||
{ return true; }
|
||||
|
||||
bool
|
||||
do_compare_is_identity() const
|
||||
{ return false; }
|
||||
|
||||
unsigned int
|
||||
do_hash_for_method(Gogo*) const;
|
||||
|
||||
|
@ -2237,6 +2347,10 @@ class Channel_type : public Type
|
|||
do_has_pointer() const
|
||||
{ return true; }
|
||||
|
||||
bool
|
||||
do_compare_is_identity() const
|
||||
{ return true; }
|
||||
|
||||
unsigned int
|
||||
do_hash_for_method(Gogo*) const;
|
||||
|
||||
|
@ -2348,6 +2462,10 @@ class Interface_type : public Type
|
|||
do_has_pointer() const
|
||||
{ return true; }
|
||||
|
||||
bool
|
||||
do_compare_is_identity() const
|
||||
{ return false; }
|
||||
|
||||
unsigned int
|
||||
do_hash_for_method(Gogo*) const;
|
||||
|
||||
|
@ -2480,6 +2598,11 @@ class Named_type : public Type
|
|||
bool
|
||||
is_named_error_type() const;
|
||||
|
||||
// Return whether this type is comparable. If REASON is not NULL,
|
||||
// set *REASON when returning false.
|
||||
bool
|
||||
named_type_is_comparable(std::string* reason) const;
|
||||
|
||||
// Add a method to this type.
|
||||
Named_object*
|
||||
add_method(const std::string& name, Function*);
|
||||
|
@ -2572,6 +2695,9 @@ class Named_type : public Type
|
|||
bool
|
||||
do_has_pointer() const;
|
||||
|
||||
bool
|
||||
do_compare_is_identity() const;
|
||||
|
||||
unsigned int
|
||||
do_hash_for_method(Gogo*) const;
|
||||
|
||||
|
@ -2704,6 +2830,10 @@ class Forward_declaration_type : public Type
|
|||
do_has_pointer() const
|
||||
{ return this->real_type()->has_pointer(); }
|
||||
|
||||
bool
|
||||
do_compare_is_identity() const
|
||||
{ return this->real_type()->compare_is_identity(); }
|
||||
|
||||
unsigned int
|
||||
do_hash_for_method(Gogo* gogo) const
|
||||
{ return this->real_type()->hash_for_method(gogo); }
|
||||
|
|
|
@ -11,7 +11,7 @@ func use(bool) {}
|
|||
type T1 *int
|
||||
type T2 *int
|
||||
|
||||
type T3 struct {}
|
||||
type T3 struct{ z []int }
|
||||
|
||||
var t3 T3
|
||||
|
||||
|
@ -21,12 +21,12 @@ func main() {
|
|||
// so chan int can be compared against
|
||||
// directional channels but channel of different
|
||||
// direction cannot be compared against each other.
|
||||
var c1 chan <-int
|
||||
var c1 chan<- int
|
||||
var c2 <-chan int
|
||||
var c3 chan int
|
||||
|
||||
use(c1 == c2) // ERROR "invalid operation|incompatible"
|
||||
use(c2 == c1) // ERROR "invalid operation|incompatible"
|
||||
|
||||
use(c1 == c2) // ERROR "invalid operation|incompatible"
|
||||
use(c2 == c1) // ERROR "invalid operation|incompatible"
|
||||
use(c1 == c3)
|
||||
use(c2 == c2)
|
||||
use(c3 == c1)
|
||||
|
@ -36,14 +36,32 @@ func main() {
|
|||
var p1 T1
|
||||
var p2 T2
|
||||
var p3 *int
|
||||
|
||||
use(p1 == p2) // ERROR "invalid operation|incompatible"
|
||||
use(p2 == p1) // ERROR "invalid operation|incompatible"
|
||||
|
||||
use(p1 == p2) // ERROR "invalid operation|incompatible"
|
||||
use(p2 == p1) // ERROR "invalid operation|incompatible"
|
||||
use(p1 == p3)
|
||||
use(p2 == p2)
|
||||
use(p3 == p1)
|
||||
use(p3 == p2)
|
||||
|
||||
|
||||
// Comparison of structs should have a good message
|
||||
use(t3 == t3) // ERROR "struct|expected"
|
||||
use(t3 == t3) // ERROR "struct|expected"
|
||||
|
||||
// Slices, functions, and maps too.
|
||||
var x []int
|
||||
var f func()
|
||||
var m map[int]int
|
||||
use(x == x) // ERROR "slice can only be compared to nil"
|
||||
use(f == f) // ERROR "func can only be compared to nil"
|
||||
use(m == m) // ERROR "map can only be compared to nil"
|
||||
|
||||
// Comparison with interface that cannot return true
|
||||
// (would panic).
|
||||
var i interface{}
|
||||
use(i == x) // ERROR "invalid operation"
|
||||
use(x == i) // ERROR "invalid operation"
|
||||
use(i == f) // ERROR "invalid operation"
|
||||
use(f == i) // ERROR "invalid operation"
|
||||
use(i == m) // ERROR "invalid operation"
|
||||
use(m == i) // ERROR "invalid operation"
|
||||
}
|
||||
|
|
|
@ -60,6 +60,7 @@ func test4() {
|
|||
|
||||
type T struct {
|
||||
a, b int
|
||||
c []int
|
||||
}
|
||||
|
||||
func test5() {
|
||||
|
|
|
@ -460,8 +460,10 @@ runtime_files = \
|
|||
runtime/go-strplus.c \
|
||||
runtime/go-strslice.c \
|
||||
runtime/go-trampoline.c \
|
||||
runtime/go-type-complex.c \
|
||||
runtime/go-type-eface.c \
|
||||
runtime/go-type-error.c \
|
||||
runtime/go-type-float.c \
|
||||
runtime/go-type-identity.c \
|
||||
runtime/go-type-interface.c \
|
||||
runtime/go-type-string.c \
|
||||
|
|
|
@ -208,7 +208,8 @@ am__libgo_la_SOURCES_DIST = runtime/go-append.c runtime/go-assert.c \
|
|||
runtime/go-string-to-byte-array.c \
|
||||
runtime/go-string-to-int-array.c runtime/go-strplus.c \
|
||||
runtime/go-strslice.c runtime/go-trampoline.c \
|
||||
runtime/go-type-eface.c runtime/go-type-error.c \
|
||||
runtime/go-type-complex.c runtime/go-type-eface.c \
|
||||
runtime/go-type-error.c runtime/go-type-float.c \
|
||||
runtime/go-type-identity.c runtime/go-type-interface.c \
|
||||
runtime/go-type-string.c runtime/go-typedesc-equal.c \
|
||||
runtime/go-typestring.c runtime/go-unreflect.c \
|
||||
|
@ -242,13 +243,14 @@ am__objects_4 = go-append.lo go-assert.lo go-assert-interface.lo \
|
|||
go-reflect-map.lo go-rune.lo go-runtime-error.lo go-setenv.lo \
|
||||
go-signal.lo go-strcmp.lo go-string-to-byte-array.lo \
|
||||
go-string-to-int-array.lo go-strplus.lo go-strslice.lo \
|
||||
go-trampoline.lo go-type-eface.lo go-type-error.lo \
|
||||
go-type-identity.lo go-type-interface.lo go-type-string.lo \
|
||||
go-typedesc-equal.lo go-typestring.lo go-unreflect.lo \
|
||||
go-unsafe-new.lo go-unsafe-newarray.lo go-unsafe-pointer.lo \
|
||||
go-unwind.lo chan.lo cpuprof.lo $(am__objects_1) mcache.lo \
|
||||
mcentral.lo $(am__objects_2) mfinal.lo mfixalloc.lo mgc0.lo \
|
||||
mheap.lo msize.lo proc.lo runtime.lo thread.lo yield.lo \
|
||||
go-trampoline.lo go-type-complex.lo go-type-eface.lo \
|
||||
go-type-error.lo go-type-float.lo go-type-identity.lo \
|
||||
go-type-interface.lo go-type-string.lo go-typedesc-equal.lo \
|
||||
go-typestring.lo go-unreflect.lo go-unsafe-new.lo \
|
||||
go-unsafe-newarray.lo go-unsafe-pointer.lo go-unwind.lo \
|
||||
chan.lo cpuprof.lo $(am__objects_1) mcache.lo mcentral.lo \
|
||||
$(am__objects_2) mfinal.lo mfixalloc.lo mgc0.lo mheap.lo \
|
||||
msize.lo proc.lo runtime.lo thread.lo yield.lo \
|
||||
$(am__objects_3) iface.lo malloc.lo map.lo mprof.lo reflect.lo \
|
||||
runtime1.lo sema.lo sigqueue.lo string.lo time.lo
|
||||
am_libgo_la_OBJECTS = $(am__objects_4)
|
||||
|
@ -881,8 +883,10 @@ runtime_files = \
|
|||
runtime/go-strplus.c \
|
||||
runtime/go-strslice.c \
|
||||
runtime/go-trampoline.c \
|
||||
runtime/go-type-complex.c \
|
||||
runtime/go-type-eface.c \
|
||||
runtime/go-type-error.c \
|
||||
runtime/go-type-float.c \
|
||||
runtime/go-type-identity.c \
|
||||
runtime/go-type-interface.c \
|
||||
runtime/go-type-string.c \
|
||||
|
@ -2523,8 +2527,10 @@ distclean-compile:
|
|||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strplus.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-strslice.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-trampoline.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-complex.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-eface.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-error.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-float.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-identity.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-interface.Plo@am__quote@
|
||||
@AMDEP_TRUE@@am__include@ @am__quote@./$(DEPDIR)/go-type-string.Plo@am__quote@
|
||||
|
@ -2928,6 +2934,13 @@ go-trampoline.lo: runtime/go-trampoline.c
|
|||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-trampoline.lo `test -f 'runtime/go-trampoline.c' || echo '$(srcdir)/'`runtime/go-trampoline.c
|
||||
|
||||
go-type-complex.lo: runtime/go-type-complex.c
|
||||
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-complex.lo -MD -MP -MF $(DEPDIR)/go-type-complex.Tpo -c -o go-type-complex.lo `test -f 'runtime/go-type-complex.c' || echo '$(srcdir)/'`runtime/go-type-complex.c
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-complex.Tpo $(DEPDIR)/go-type-complex.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-complex.c' object='go-type-complex.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-complex.lo `test -f 'runtime/go-type-complex.c' || echo '$(srcdir)/'`runtime/go-type-complex.c
|
||||
|
||||
go-type-eface.lo: runtime/go-type-eface.c
|
||||
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-eface.lo -MD -MP -MF $(DEPDIR)/go-type-eface.Tpo -c -o go-type-eface.lo `test -f 'runtime/go-type-eface.c' || echo '$(srcdir)/'`runtime/go-type-eface.c
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-eface.Tpo $(DEPDIR)/go-type-eface.Plo
|
||||
|
@ -2942,6 +2955,13 @@ go-type-error.lo: runtime/go-type-error.c
|
|||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-error.lo `test -f 'runtime/go-type-error.c' || echo '$(srcdir)/'`runtime/go-type-error.c
|
||||
|
||||
go-type-float.lo: runtime/go-type-float.c
|
||||
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-float.lo -MD -MP -MF $(DEPDIR)/go-type-float.Tpo -c -o go-type-float.lo `test -f 'runtime/go-type-float.c' || echo '$(srcdir)/'`runtime/go-type-float.c
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-float.Tpo $(DEPDIR)/go-type-float.Plo
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ source='runtime/go-type-float.c' object='go-type-float.lo' libtool=yes @AMDEPBACKSLASH@
|
||||
@AMDEP_TRUE@@am__fastdepCC_FALSE@ DEPDIR=$(DEPDIR) $(CCDEPMODE) $(depcomp) @AMDEPBACKSLASH@
|
||||
@am__fastdepCC_FALSE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -c -o go-type-float.lo `test -f 'runtime/go-type-float.c' || echo '$(srcdir)/'`runtime/go-type-float.c
|
||||
|
||||
go-type-identity.lo: runtime/go-type-identity.c
|
||||
@am__fastdepCC_TRUE@ $(LIBTOOL) --tag=CC $(AM_LIBTOOLFLAGS) $(LIBTOOLFLAGS) --mode=compile $(CC) $(DEFS) $(DEFAULT_INCLUDES) $(INCLUDES) $(AM_CPPFLAGS) $(CPPFLAGS) $(AM_CFLAGS) $(CFLAGS) -MT go-type-identity.lo -MD -MP -MF $(DEPDIR)/go-type-identity.Tpo -c -o go-type-identity.lo `test -f 'runtime/go-type-identity.c' || echo '$(srcdir)/'`runtime/go-type-identity.c
|
||||
@am__fastdepCC_TRUE@ $(am__mv) $(DEPDIR)/go-type-identity.Tpo $(DEPDIR)/go-type-identity.Plo
|
||||
|
|
|
@ -0,0 +1,122 @@
|
|||
/* go-type-complex.c -- hash and equality complex functions.
|
||||
|
||||
Copyright 2012 The Go Authors. All rights reserved.
|
||||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the LICENSE file. */
|
||||
|
||||
#include "runtime.h"
|
||||
#include "go-type.h"
|
||||
|
||||
/* The 64-bit type. */
|
||||
|
||||
typedef unsigned int DItype __attribute__ ((mode (DI)));
|
||||
|
||||
/* Hash function for float types. */
|
||||
|
||||
uintptr_t
|
||||
__go_type_hash_complex (const void *vkey, uintptr_t key_size)
|
||||
{
|
||||
if (key_size == 8)
|
||||
{
|
||||
union
|
||||
{
|
||||
unsigned char a[8];
|
||||
__complex float cf;
|
||||
DItype di;
|
||||
} ucf;
|
||||
__complex float cf;
|
||||
float cfr;
|
||||
float cfi;
|
||||
|
||||
__builtin_memcpy (ucf.a, vkey, 8);
|
||||
cf = ucf.cf;
|
||||
cfr = __builtin_crealf (cf);
|
||||
cfi = __builtin_cimagf (cf);
|
||||
if (__builtin_isinff (cfr) || __builtin_isinff (cfi)
|
||||
|| __builtin_isnanf (cfr) || __builtin_isnanf (cfi))
|
||||
return 0;
|
||||
|
||||
/* Avoid negative zero. */
|
||||
if (cfr == 0 && cfi == 0)
|
||||
return 0;
|
||||
else if (cfr == 0)
|
||||
ucf.cf = cfi * 1.0iF;
|
||||
else if (cfi == 0)
|
||||
ucf.cf = cfr;
|
||||
|
||||
return ucf.di;
|
||||
}
|
||||
else if (key_size == 16)
|
||||
{
|
||||
union
|
||||
{
|
||||
unsigned char a[16];
|
||||
__complex double cd;
|
||||
DItype adi[2];
|
||||
} ucd;
|
||||
__complex double cd;
|
||||
double cdr;
|
||||
double cdi;
|
||||
|
||||
__builtin_memcpy (ucd.a, vkey, 16);
|
||||
cd = ucd.cd;
|
||||
cdr = __builtin_crealf (cd);
|
||||
cdi = __builtin_cimagf (cd);
|
||||
if (__builtin_isinf (cdr) || __builtin_isinf (cdi)
|
||||
|| __builtin_isnan (cdr) || __builtin_isnan (cdi))
|
||||
return 0;
|
||||
|
||||
/* Avoid negative zero. */
|
||||
if (cdr == 0 && cdi == 0)
|
||||
return 0;
|
||||
else if (cdr == 0)
|
||||
ucd.cd = cdi * 1.0i;
|
||||
else if (cdi == 0)
|
||||
ucd.cd = cdr;
|
||||
|
||||
return ucd.adi[0] ^ ucd.adi[1];
|
||||
}
|
||||
else
|
||||
runtime_throw ("__go_type_hash_complex: invalid complex size");
|
||||
}
|
||||
|
||||
/* Equality function for complex types. */
|
||||
|
||||
_Bool
|
||||
__go_type_equal_complex (const void *vk1, const void *vk2, uintptr_t key_size)
|
||||
{
|
||||
if (key_size == 8)
|
||||
{
|
||||
union
|
||||
{
|
||||
unsigned char a[8];
|
||||
__complex float cf;
|
||||
} ucf;
|
||||
__complex float cf1;
|
||||
__complex float cf2;
|
||||
|
||||
__builtin_memcpy (ucf.a, vk1, 8);
|
||||
cf1 = ucf.cf;
|
||||
__builtin_memcpy (ucf.a, vk2, 8);
|
||||
cf2 = ucf.cf;
|
||||
return cf1 == cf2;
|
||||
}
|
||||
else if (key_size == 16)
|
||||
{
|
||||
union
|
||||
{
|
||||
unsigned char a[16];
|
||||
__complex double cd;
|
||||
} ucd;
|
||||
__complex double cd1;
|
||||
__complex double cd2;
|
||||
|
||||
__builtin_memcpy (ucd.a, vk1, 16);
|
||||
cd1 = ucd.cd;
|
||||
__builtin_memcpy (ucd.a, vk2, 16);
|
||||
cd2 = ucd.cd;
|
||||
return cd1 == cd2;
|
||||
}
|
||||
else
|
||||
runtime_throw ("__go_type_equal_complex: invalid complex size");
|
||||
}
|
|
@ -10,13 +10,13 @@
|
|||
|
||||
/* A hash function for an empty interface. */
|
||||
|
||||
size_t
|
||||
uintptr_t
|
||||
__go_type_hash_empty_interface (const void *vval,
|
||||
size_t key_size __attribute__ ((unused)))
|
||||
uintptr_t key_size __attribute__ ((unused)))
|
||||
{
|
||||
const struct __go_empty_interface *val;
|
||||
const struct __go_type_descriptor *descriptor;
|
||||
size_t size;
|
||||
uintptr_t size;
|
||||
|
||||
val = (const struct __go_empty_interface *) vval;
|
||||
descriptor = val->__type_descriptor;
|
||||
|
@ -33,7 +33,7 @@ __go_type_hash_empty_interface (const void *vval,
|
|||
|
||||
_Bool
|
||||
__go_type_equal_empty_interface (const void *vv1, const void *vv2,
|
||||
size_t key_size __attribute__ ((unused)))
|
||||
uintptr_t key_size __attribute__ ((unused)))
|
||||
{
|
||||
const struct __go_empty_interface *v1;
|
||||
const struct __go_empty_interface *v2;
|
||||
|
|
|
@ -10,9 +10,9 @@
|
|||
/* A hash function used for a type which does not support hash
|
||||
functions. */
|
||||
|
||||
size_t
|
||||
uintptr_t
|
||||
__go_type_hash_error (const void *val __attribute__ ((unused)),
|
||||
size_t key_size __attribute__ ((unused)))
|
||||
uintptr_t key_size __attribute__ ((unused)))
|
||||
{
|
||||
runtime_panicstring ("hash of unhashable type");
|
||||
}
|
||||
|
@ -22,7 +22,7 @@ __go_type_hash_error (const void *val __attribute__ ((unused)),
|
|||
_Bool
|
||||
__go_type_equal_error (const void *v1 __attribute__ ((unused)),
|
||||
const void *v2 __attribute__ ((unused)),
|
||||
size_t key_size __attribute__ ((unused)))
|
||||
uintptr_t key_size __attribute__ ((unused)))
|
||||
{
|
||||
runtime_panicstring ("comparing uncomparable types");
|
||||
}
|
||||
|
|
|
@ -0,0 +1,96 @@
|
|||
/* go-type-float.c -- hash and equality float functions.
|
||||
|
||||
Copyright 2012 The Go Authors. All rights reserved.
|
||||
Use of this source code is governed by a BSD-style
|
||||
license that can be found in the LICENSE file. */
|
||||
|
||||
#include "runtime.h"
|
||||
#include "go-type.h"
|
||||
|
||||
/* The 32-bit and 64-bit types. */
|
||||
|
||||
typedef unsigned int SItype __attribute__ ((mode (SI)));
|
||||
typedef unsigned int DItype __attribute__ ((mode (DI)));
|
||||
|
||||
/* Hash function for float types. */
|
||||
|
||||
uintptr_t
|
||||
__go_type_hash_float (const void *vkey, uintptr_t key_size)
|
||||
{
|
||||
if (key_size == 4)
|
||||
{
|
||||
union
|
||||
{
|
||||
unsigned char a[4];
|
||||
float f;
|
||||
SItype si;
|
||||
} uf;
|
||||
float f;
|
||||
|
||||
__builtin_memcpy (uf.a, vkey, 4);
|
||||
f = uf.f;
|
||||
if (__builtin_isinff (f) || __builtin_isnanf (f) || f == 0)
|
||||
return 0;
|
||||
return (uintptr_t) uf.si;
|
||||
}
|
||||
else if (key_size == 8)
|
||||
{
|
||||
union
|
||||
{
|
||||
unsigned char a[8];
|
||||
double d;
|
||||
DItype di;
|
||||
} ud;
|
||||
double d;
|
||||
|
||||
__builtin_memcpy (ud.a, vkey, 8);
|
||||
d = ud.d;
|
||||
if (__builtin_isinf (d) || __builtin_isnan (d) || d == 0)
|
||||
return 0;
|
||||
return (uintptr_t) ud.di;
|
||||
}
|
||||
else
|
||||
runtime_throw ("__go_type_hash_float: invalid float size");
|
||||
}
|
||||
|
||||
/* Equality function for float types. */
|
||||
|
||||
_Bool
|
||||
__go_type_equal_float (const void *vk1, const void *vk2, uintptr_t key_size)
|
||||
{
|
||||
if (key_size == 4)
|
||||
{
|
||||
union
|
||||
{
|
||||
unsigned char a[4];
|
||||
float f;
|
||||
} uf;
|
||||
float f1;
|
||||
float f2;
|
||||
|
||||
__builtin_memcpy (uf.a, vk1, 4);
|
||||
f1 = uf.f;
|
||||
__builtin_memcpy (uf.a, vk2, 4);
|
||||
f2 = uf.f;
|
||||
return f1 == f2;
|
||||
}
|
||||
else if (key_size == 8)
|
||||
{
|
||||
union
|
||||
{
|
||||
unsigned char a[8];
|
||||
double d;
|
||||
DItype di;
|
||||
} ud;
|
||||
double d1;
|
||||
double d2;
|
||||
|
||||
__builtin_memcpy (ud.a, vk1, 8);
|
||||
d1 = ud.d;
|
||||
__builtin_memcpy (ud.a, vk2, 8);
|
||||
d2 = ud.d;
|
||||
return d1 == d2;
|
||||
}
|
||||
else
|
||||
runtime_throw ("__go_type_equal_float: invalid float size");
|
||||
}
|
|
@ -8,35 +8,37 @@
|
|||
|
||||
#include "go-type.h"
|
||||
|
||||
/* Typedefs for accesses of different sizes. */
|
||||
/* The 64-bit type. */
|
||||
|
||||
typedef int QItype __attribute__ ((mode (QI)));
|
||||
typedef int HItype __attribute__ ((mode (HI)));
|
||||
typedef int SItype __attribute__ ((mode (SI)));
|
||||
typedef int DItype __attribute__ ((mode (DI)));
|
||||
typedef unsigned int DItype __attribute__ ((mode (DI)));
|
||||
|
||||
/* An identity hash function for a type. This is used for types where
|
||||
we can simply use the type value itself as a hash code. This is
|
||||
true of, e.g., integers and pointers. */
|
||||
|
||||
size_t
|
||||
__go_type_hash_identity (const void *key, size_t key_size)
|
||||
uintptr_t
|
||||
__go_type_hash_identity (const void *key, uintptr_t key_size)
|
||||
{
|
||||
switch (key_size)
|
||||
uintptr_t ret;
|
||||
uintptr_t i;
|
||||
const unsigned char *p;
|
||||
|
||||
if (key_size <= 8)
|
||||
{
|
||||
case 1:
|
||||
return *(const QItype *) key;
|
||||
case 2:
|
||||
return *(const HItype *) key;
|
||||
case 3:
|
||||
case 4:
|
||||
case 5:
|
||||
case 6:
|
||||
case 7:
|
||||
return *(const SItype *) key;
|
||||
default:
|
||||
return *(const DItype *) key;
|
||||
union
|
||||
{
|
||||
DItype v;
|
||||
unsigned char a[8];
|
||||
} u;
|
||||
u.v = 0;
|
||||
__builtin_memcpy (&u.a, key, key_size);
|
||||
return (uintptr_t) u.v;
|
||||
}
|
||||
|
||||
ret = 5381;
|
||||
for (i = 0, p = (const unsigned char *) key; i < key_size; i++, p++)
|
||||
ret = ret * 33 + *p;
|
||||
return ret;
|
||||
}
|
||||
|
||||
/* An identity equality function for a type. This is used for types
|
||||
|
@ -44,7 +46,7 @@ __go_type_hash_identity (const void *key, size_t key_size)
|
|||
the same bits. */
|
||||
|
||||
_Bool
|
||||
__go_type_equal_identity (const void *k1, const void *k2, size_t key_size)
|
||||
__go_type_equal_identity (const void *k1, const void *k2, uintptr_t key_size)
|
||||
{
|
||||
return __builtin_memcmp (k1, k2, key_size) == 0;
|
||||
}
|
||||
|
|
|
@ -9,13 +9,13 @@
|
|||
|
||||
/* A hash function for an interface. */
|
||||
|
||||
size_t
|
||||
uintptr_t
|
||||
__go_type_hash_interface (const void *vval,
|
||||
size_t key_size __attribute__ ((unused)))
|
||||
uintptr_t key_size __attribute__ ((unused)))
|
||||
{
|
||||
const struct __go_interface *val;
|
||||
const struct __go_type_descriptor *descriptor;
|
||||
size_t size;
|
||||
uintptr_t size;
|
||||
|
||||
val = (const struct __go_interface *) vval;
|
||||
if (val->__methods == NULL)
|
||||
|
@ -32,7 +32,7 @@ __go_type_hash_interface (const void *vval,
|
|||
|
||||
_Bool
|
||||
__go_type_equal_interface (const void *vv1, const void *vv2,
|
||||
size_t key_size __attribute__ ((unused)))
|
||||
uintptr_t key_size __attribute__ ((unused)))
|
||||
{
|
||||
const struct __go_interface *v1;
|
||||
const struct __go_interface *v2;
|
||||
|
|
|
@ -11,14 +11,14 @@
|
|||
|
||||
/* A string hash function for a map. */
|
||||
|
||||
size_t
|
||||
uintptr_t
|
||||
__go_type_hash_string (const void *vkey,
|
||||
size_t key_size __attribute__ ((unused)))
|
||||
uintptr_t key_size __attribute__ ((unused)))
|
||||
{
|
||||
size_t ret;
|
||||
uintptr_t ret;
|
||||
const struct __go_string *key;
|
||||
size_t len;
|
||||
size_t i;
|
||||
int len;
|
||||
int i;
|
||||
const unsigned char *p;
|
||||
|
||||
ret = 5381;
|
||||
|
@ -33,7 +33,7 @@ __go_type_hash_string (const void *vkey,
|
|||
|
||||
_Bool
|
||||
__go_type_equal_string (const void *vk1, const void *vk2,
|
||||
size_t key_size __attribute__ ((unused)))
|
||||
uintptr_t key_size __attribute__ ((unused)))
|
||||
{
|
||||
const struct __go_string *k1;
|
||||
const struct __go_string *k2;
|
||||
|
|
|
@ -86,11 +86,11 @@ struct __go_type_descriptor
|
|||
size of this type, and returns a hash code. We pass the size
|
||||
explicitly becaues it means that we can share a single instance
|
||||
of this function for various different types. */
|
||||
size_t (*__hashfn) (const void *, size_t);
|
||||
uintptr_t (*__hashfn) (const void *, uintptr_t);
|
||||
|
||||
/* This function takes two pointers to values of this type, and the
|
||||
size of this type, and returns whether the values are equal. */
|
||||
_Bool (*__equalfn) (const void *, const void *, size_t);
|
||||
_Bool (*__equalfn) (const void *, const void *, uintptr_t);
|
||||
|
||||
/* A string describing this type. This is only used for
|
||||
debugging. */
|
||||
|
@ -317,13 +317,17 @@ extern _Bool
|
|||
__go_type_descriptors_equal(const struct __go_type_descriptor*,
|
||||
const struct __go_type_descriptor*);
|
||||
|
||||
extern size_t __go_type_hash_identity (const void *, size_t);
|
||||
extern _Bool __go_type_equal_identity (const void *, const void *, size_t);
|
||||
extern size_t __go_type_hash_string (const void *, size_t);
|
||||
extern _Bool __go_type_equal_string (const void *, const void *, size_t);
|
||||
extern size_t __go_type_hash_interface (const void *, size_t);
|
||||
extern _Bool __go_type_equal_interface (const void *, const void *, size_t);
|
||||
extern size_t __go_type_hash_error (const void *, size_t);
|
||||
extern _Bool __go_type_equal_error (const void *, const void *, size_t);
|
||||
extern uintptr_t __go_type_hash_identity (const void *, uintptr_t);
|
||||
extern _Bool __go_type_equal_identity (const void *, const void *, uintptr_t);
|
||||
extern uintptr_t __go_type_hash_string (const void *, uintptr_t);
|
||||
extern _Bool __go_type_equal_string (const void *, const void *, uintptr_t);
|
||||
extern uintptr_t __go_type_hash_float (const void *, uintptr_t);
|
||||
extern _Bool __go_type_equal_float (const void *, const void *, uintptr_t);
|
||||
extern uintptr_t __go_type_hash_complex (const void *, uintptr_t);
|
||||
extern _Bool __go_type_equal_complex (const void *, const void *, uintptr_t);
|
||||
extern uintptr_t __go_type_hash_interface (const void *, uintptr_t);
|
||||
extern _Bool __go_type_equal_interface (const void *, const void *, uintptr_t);
|
||||
extern uintptr_t __go_type_hash_error (const void *, uintptr_t);
|
||||
extern _Bool __go_type_equal_error (const void *, const void *, uintptr_t);
|
||||
|
||||
#endif /* !defined(LIBGO_GO_TYPE_H) */
|
||||
|
|
|
@ -322,18 +322,18 @@ localname() {
|
|||
pattern='Test([^a-z].*)?'
|
||||
# The -p option tells GNU nm not to sort.
|
||||
# The -v option tells Solaris nm to sort by value.
|
||||
tests=$($NM -p -v _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/')
|
||||
tests=$($NM -p -v _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | fgrep -v '$' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/')
|
||||
if [ "x$tests" = x ]; then
|
||||
echo 'gotest: warning: no tests matching '$pattern in _gotest_.o $xofile 1>&2
|
||||
exit 2
|
||||
fi
|
||||
# benchmarks are named BenchmarkFoo.
|
||||
pattern='Benchmark([^a-z].*)?'
|
||||
benchmarks=$($NM -p -v _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/')
|
||||
benchmarks=$($NM -p -v _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | fgrep -v '$' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/')
|
||||
|
||||
# examples are named ExampleFoo
|
||||
pattern='Example([^a-z].*)?'
|
||||
examples=$($NM -p -v _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/')
|
||||
examples=$($NM -p -v _gotest_.o $xofile | egrep ' T .*\.'$pattern'$' | grep -v '\..*\..*\.' | fgrep -v '$' | sed 's/.* //' | sed 's/.*\.\(.*\.\)/\1/')
|
||||
|
||||
# package spec
|
||||
echo 'package main'
|
||||
|
|
Loading…
Reference in New Issue