diff options
Diffstat (limited to 'gcc-4.8/gcc/go/gofrontend/types.cc')
-rw-r--r-- | gcc-4.8/gcc/go/gofrontend/types.cc | 255 |
1 files changed, 201 insertions, 54 deletions
diff --git a/gcc-4.8/gcc/go/gofrontend/types.cc b/gcc-4.8/gcc/go/gofrontend/types.cc index e1d68e743..9bc356a73 100644 --- a/gcc-4.8/gcc/go/gofrontend/types.cc +++ b/gcc-4.8/gcc/go/gofrontend/types.cc @@ -1834,7 +1834,9 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, bloc); gogo->start_block(bloc); - if (this->struct_type() != NULL) + if (name != NULL && name->real_type()->named_type() != NULL) + this->write_named_hash(gogo, name, hash_fntype, equal_fntype); + else if (this->struct_type() != NULL) this->struct_type()->write_hash_function(gogo, name, hash_fntype, equal_fntype); else if (this->array_type() != NULL) @@ -1852,7 +1854,9 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, false, bloc); gogo->start_block(bloc); - if (this->struct_type() != NULL) + if (name != NULL && name->real_type()->named_type() != NULL) + this->write_named_equal(gogo, name); + else if (this->struct_type() != NULL) this->struct_type()->write_equal_function(gogo, name); else if (this->array_type() != NULL) this->array_type()->write_equal_function(gogo, name); @@ -1865,6 +1869,100 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, gogo->finish_function(bloc); } +// Write a hash function that simply calls the hash function for a +// named type. This is used when one named type is defined as +// another. This ensures that this case works when the other named +// type is defined in another package and relies on calling hash +// functions defined only in that package. + +void +Type::write_named_hash(Gogo* gogo, Named_type* name, + Function_type* hash_fntype, Function_type* equal_fntype) +{ + Location bloc = Linemap::predeclared_location(); + + Named_type* base_type = name->real_type()->named_type(); + go_assert(base_type != NULL); + + // The pointer to the type we are going to hash. This is an + // unsafe.Pointer. + Named_object* key_arg = gogo->lookup("key", NULL); + go_assert(key_arg != NULL); + + // The size of the type we are going to hash. + Named_object* keysz_arg = gogo->lookup("key_size", NULL); + go_assert(keysz_arg != NULL); + + Named_object* hash_fn; + Named_object* equal_fn; + name->real_type()->type_functions(gogo, base_type, hash_fntype, equal_fntype, + &hash_fn, &equal_fn); + + // Call the hash function for the base type. + Expression* key_ref = Expression::make_var_reference(key_arg, bloc); + Expression* keysz_ref = Expression::make_var_reference(keysz_arg, bloc); + Expression_list* args = new Expression_list(); + args->push_back(key_ref); + args->push_back(keysz_ref); + Expression* func = Expression::make_func_reference(hash_fn, NULL, bloc); + Expression* call = Expression::make_call(func, args, false, bloc); + + // Return the hash of the base type. + Expression_list* vals = new Expression_list(); + vals->push_back(call); + Statement* s = Statement::make_return_statement(vals, bloc); + gogo->add_statement(s); +} + +// Write an equality function that simply calls the equality function +// for a named type. This is used when one named type is defined as +// another. This ensures that this case works when the other named +// type is defined in another package and relies on calling equality +// functions defined only in that package. + +void +Type::write_named_equal(Gogo* gogo, Named_type* name) +{ + Location bloc = Linemap::predeclared_location(); + + // The pointers to the types we are going to compare. These have + // type unsafe.Pointer. + Named_object* key1_arg = gogo->lookup("key1", NULL); + Named_object* key2_arg = gogo->lookup("key2", NULL); + go_assert(key1_arg != NULL && key2_arg != NULL); + + Named_type* base_type = name->real_type()->named_type(); + go_assert(base_type != NULL); + + // Build temporaries with the base type. + Type* pt = Type::make_pointer_type(base_type); + + Expression* ref = Expression::make_var_reference(key1_arg, bloc); + ref = Expression::make_cast(pt, ref, bloc); + Temporary_statement* p1 = Statement::make_temporary(pt, ref, bloc); + gogo->add_statement(p1); + + ref = Expression::make_var_reference(key2_arg, bloc); + ref = Expression::make_cast(pt, ref, bloc); + Temporary_statement* p2 = Statement::make_temporary(pt, ref, bloc); + gogo->add_statement(p2); + + // Compare the values for equality. + Expression* t1 = Expression::make_temporary_reference(p1, bloc); + t1 = Expression::make_unary(OPERATOR_MULT, t1, bloc); + + Expression* t2 = Expression::make_temporary_reference(p2, bloc); + t2 = Expression::make_unary(OPERATOR_MULT, t2, bloc); + + Expression* cond = Expression::make_binary(OPERATOR_EQEQ, t1, t2, bloc); + + // Return the equality comparison. + Expression_list* vals = new Expression_list(); + vals->push_back(cond); + Statement* s = Statement::make_return_statement(vals, bloc); + gogo->add_statement(s); +} + // Return a composite literal for the type descriptor for a plain type // of kind RUNTIME_TYPE_KIND named NAME. @@ -2164,26 +2262,9 @@ Type::method_constructor(Gogo*, Type* method_type, ++p; go_assert(p->is_field_name("typ")); - if (!only_value_methods && m->is_value_method()) - { - // This is a value method on a pointer type. Change the type of - // the method to use a pointer receiver. The implementation - // always uses a pointer receiver anyhow. - Type* rtype = mtype->receiver()->type(); - Type* prtype = Type::make_pointer_type(rtype); - Typed_identifier* receiver = - new Typed_identifier(mtype->receiver()->name(), prtype, - mtype->receiver()->location()); - mtype = Type::make_function_type(receiver, - (mtype->parameters() == NULL - ? NULL - : mtype->parameters()->copy()), - (mtype->results() == NULL - ? NULL - : mtype->results()->copy()), - mtype->location()); - } - vals->push_back(Expression::make_type_descriptor(mtype, bloc)); + bool want_pointer_receiver = !only_value_methods && m->is_value_method(); + nonmethod_type = mtype->copy_with_receiver_as_param(want_pointer_receiver); + vals->push_back(Expression::make_type_descriptor(nonmethod_type, bloc)); ++p; go_assert(p->is_field_name("tfn")); @@ -3383,18 +3464,10 @@ Function_type::do_hash_for_method(Gogo* gogo) const // Get the backend representation for a function type. Btype* -Function_type::do_get_backend(Gogo* gogo) +Function_type::get_backend_fntype(Gogo* gogo) { - // When we do anything with a function value other than call it, it - // is represented as a pointer to a struct whose first field is the - // actual function. So that is what we return as the type of a Go - // function. - - Location loc = this->location(); - Btype* struct_type = - gogo->backend()->placeholder_struct_type("__go_descriptor", loc); - Btype* ptr_struct_type = gogo->backend()->pointer_type(struct_type); - + if (this->fnbtype_ == NULL) + { Backend::Btyped_identifier breceiver; if (this->receiver_ != NULL) { @@ -3414,8 +3487,8 @@ Function_type::do_get_backend(Gogo* gogo) { bparameters.resize(this->parameters_->size()); size_t i = 0; - for (Typed_identifier_list::const_iterator p = this->parameters_->begin(); - p != this->parameters_->end(); + for (Typed_identifier_list::const_iterator p = + this->parameters_->begin(); p != this->parameters_->end(); ++p, ++i) { bparameters[i].name = Gogo::unpack_hidden_name(p->name()); @@ -3430,8 +3503,8 @@ Function_type::do_get_backend(Gogo* gogo) { bresults.resize(this->results_->size()); size_t i = 0; - for (Typed_identifier_list::const_iterator p = this->results_->begin(); - p != this->results_->end(); + for (Typed_identifier_list::const_iterator p = + this->results_->begin(); p != this->results_->end(); ++p, ++i) { bresults[i].name = Gogo::unpack_hidden_name(p->name()); @@ -3441,11 +3514,33 @@ Function_type::do_get_backend(Gogo* gogo) go_assert(i == bresults.size()); } - Btype* fntype = gogo->backend()->function_type(breceiver, bparameters, - bresults, loc); + this->fnbtype_ = gogo->backend()->function_type(breceiver, bparameters, + bresults, + this->location()); + + } + + return this->fnbtype_; +} + +// Get the backend representation for a Go function type. + +Btype* +Function_type::do_get_backend(Gogo* gogo) +{ + // When we do anything with a function value other than call it, it + // is represented as a pointer to a struct whose first field is the + // actual function. So that is what we return as the type of a Go + // function. + + Location loc = this->location(); + Btype* struct_type = + gogo->backend()->placeholder_struct_type("__go_descriptor", loc); + Btype* ptr_struct_type = gogo->backend()->pointer_type(struct_type); + std::vector<Backend::Btyped_identifier> fields(1); fields[0].name = "code"; - fields[0].btype = fntype; + fields[0].btype = this->get_backend_fntype(gogo); fields[0].location = loc; if (!gogo->backend()->set_placeholder_struct_type(struct_type, fields)) return gogo->backend()->error_type(); @@ -3821,6 +3916,32 @@ Function_type::copy_with_receiver(Type* receiver_type) const return ret; } +// Make a copy of a function type with the receiver as the first +// parameter. + +Function_type* +Function_type::copy_with_receiver_as_param(bool want_pointer_receiver) const +{ + go_assert(this->is_method()); + Typed_identifier_list* new_params = new Typed_identifier_list(); + Type* rtype = this->receiver_->type(); + if (want_pointer_receiver) + rtype = Type::make_pointer_type(rtype); + Typed_identifier receiver(this->receiver_->name(), rtype, + this->receiver_->location()); + new_params->push_back(receiver); + const Typed_identifier_list* orig_params = this->parameters_; + if (orig_params != NULL && !orig_params->empty()) + { + for (Typed_identifier_list::const_iterator p = orig_params->begin(); + p != orig_params->end(); + ++p) + new_params->push_back(*p); + } + return Type::make_function_type(NULL, new_params, this->results_, + this->location_); +} + // Make a copy of a function type ignoring any receiver and adding a // closure parameter. @@ -4195,7 +4316,8 @@ Struct_field::is_field_name(const std::string& name) const // This is a horrible hack caused by the fact that we don't pack // the names of builtin types. FIXME. - if (nt != NULL + if (!this->is_imported_ + && nt != NULL && nt->is_builtin() && nt->name() == Gogo::unpack_hidden_name(name)) return true; @@ -4204,6 +4326,36 @@ Struct_field::is_field_name(const std::string& name) const } } +// Return whether this field is an unexported field named NAME. + +bool +Struct_field::is_unexported_field_name(Gogo* gogo, + const std::string& name) const +{ + const std::string& field_name(this->field_name()); + if (Gogo::is_hidden_name(field_name) + && name == Gogo::unpack_hidden_name(field_name) + && gogo->pack_hidden_name(name, false) != field_name) + return true; + + // Check for the name of a builtin type. This is like the test in + // is_field_name, only there we return false if this->is_imported_, + // and here we return true. + if (this->is_imported_ && this->is_anonymous()) + { + Type* t = this->typed_identifier_.type(); + if (t->points_to() != NULL) + t = t->points_to(); + Named_type* nt = t->named_type(); + if (nt != NULL + && nt->is_builtin() + && nt->name() == Gogo::unpack_hidden_name(name)) + return true; + } + + return false; +} + // Return whether this field is an embedded built-in type. bool @@ -4264,12 +4416,7 @@ Struct_type::do_verify() ++p) { Type* t = p->type(); - if (t->is_undefined()) - { - error_at(p->location(), "struct field type is incomplete"); - p->set_type(Type::make_error_type()); - } - else if (p->is_anonymous()) + if (p->is_anonymous()) { if (t->named_type() != NULL && t->points_to() != NULL) { @@ -4641,14 +4788,9 @@ Struct_type::is_unexported_local_field(Gogo* gogo, for (Struct_field_list::const_iterator pf = fields->begin(); pf != fields->end(); ++pf) - { - const std::string& field_name(pf->field_name()); - if (Gogo::is_hidden_name(field_name) - && name == Gogo::unpack_hidden_name(field_name) - && gogo->pack_hidden_name(name, false) != field_name) + if (pf->is_unexported_field_name(gogo, name)) return true; } - } return false; } @@ -5250,6 +5392,7 @@ Struct_type::do_import(Import* imp) Type* ftype = imp->read_type(); Struct_field sf(Typed_identifier(name, ftype, imp->location())); + sf.set_is_imported(); if (imp->peek_char() == ' ') { @@ -9022,6 +9165,8 @@ Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods, fntype->is_varargs(), location); gogo->finish_function(fntype->location()); + if (type->named_type() == NULL && stub->is_function()) + stub->func_value()->set_is_unnamed_type_stub_method(); if (m->nointerface() && stub->is_function()) stub->func_value()->set_nointerface(); } @@ -9289,7 +9434,9 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr, else { bool is_unexported; - if (!Gogo::is_hidden_name(name)) + // The test for 'a' and 'z' is to handle builtin names, + // which are not hidden. + if (!Gogo::is_hidden_name(name) && (name[0] < 'a' || name[0] > 'z')) is_unexported = false; else { |