X-Git-Url: http://git.sourceforge.jp/view?p=pf3gnuchains%2Fgcc-fork.git;a=blobdiff_plain;f=gcc%2Fgo%2Fgofrontend%2Ftypes.cc;h=fed83b31b9a7dd15d6279a747df748cd5052a3b0;hp=806226f6f424253d19adba22981925c25c7501b8;hb=07daa4e7f7f8600c19e4d3cecd04f5b37c63e704;hpb=aad35e893e6b53cd901daf5a8516c0cded8c21f6 diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 806226f6f42..fed83b31b9a 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -31,13 +31,13 @@ extern "C" #include "statements.h" #include "export.h" #include "import.h" +#include "backend.h" #include "types.h" // Class Type. Type::Type(Type_classification classification) - : classification_(classification), tree_(NULL_TREE), - type_descriptor_decl_(NULL_TREE) + : classification_(classification), btype_(NULL), type_descriptor_var_(NULL) { } @@ -157,7 +157,7 @@ Type::is_basic_type() const return this->base()->is_basic_type(); default: - gcc_unreachable(); + go_unreachable(); } } @@ -188,7 +188,7 @@ Type::is_abstract() const Type* Type::make_non_abstract_type() { - gcc_assert(this->is_abstract()); + go_assert(this->is_abstract()); switch (this->classification()) { case TYPE_INTEGER: @@ -202,7 +202,7 @@ Type::make_non_abstract_type() case TYPE_BOOLEAN: return Type::lookup_bool_type(); default: - gcc_unreachable(); + go_unreachable(); } } @@ -240,7 +240,7 @@ Type::points_to() const // Return whether this is an open array type. bool -Type::is_open_array_type() const +Type::is_slice_type() const { return this->array_type() != NULL && this->array_type()->length() == NULL; } @@ -270,7 +270,7 @@ Type::is_nil_constant_as_type() const int Type::traverse(Type* type, Traverse* traverse) { - gcc_assert((traverse->traverse_mask() & Traverse::traverse_types) != 0 + go_assert((traverse->traverse_mask() & Traverse::traverse_types) != 0 || (traverse->traverse_mask() & Traverse::traverse_expressions) != 0); if (traverse->remember_type(type)) @@ -407,7 +407,7 @@ Type::are_identical(const Type* t1, const Type* t2, bool errors_are_identical, return false; default: - gcc_unreachable(); + go_unreachable(); } } @@ -457,7 +457,7 @@ Type::are_compatible_for_binop(const Type* lhs, const Type* rhs) if (lhs->is_nil_type() && (rhs->points_to() != NULL || rhs->interface_type() != NULL - || rhs->is_open_array_type() + || rhs->is_slice_type() || rhs->map_type() != NULL || rhs->channel_type() != NULL || rhs->function_type() != NULL)) @@ -465,7 +465,7 @@ Type::are_compatible_for_binop(const Type* lhs, const Type* rhs) if (rhs->is_nil_type() && (lhs->points_to() != NULL || lhs->interface_type() != NULL - || lhs->is_open_array_type() + || lhs->is_slice_type() || lhs->map_type() != NULL || lhs->channel_type() != NULL || lhs->function_type() != NULL)) @@ -475,11 +475,14 @@ Type::are_compatible_for_binop(const Type* lhs, const Type* rhs) } // 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. +// with type LHS. If CHECK_HIDDEN_FIELDS is true, check whether any +// hidden fields are modified. If REASON is not NULL, set *REASON to +// the reason the types are not assignable. bool -Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason) +Type::are_assignable_check_hidden(const Type* lhs, const Type* rhs, + bool check_hidden_fields, + std::string* reason) { // Do some checks first. Make sure the types are defined. if (rhs != NULL @@ -499,7 +502,9 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason) // 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 (check_hidden_fields + && rhs != NULL + && rhs->forwarded()->forward_declaration_type() == NULL) { if (lhs->has_hidden_fields(NULL, reason) || rhs->has_hidden_fields(NULL, reason)) @@ -551,7 +556,7 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason) if (rhs->is_nil_type() && (lhs->points_to() != NULL || lhs->function_type() != NULL - || lhs->is_open_array_type() + || lhs->is_slice_type() || lhs->map_type() != NULL || lhs->channel_type() != NULL || lhs->interface_type() != NULL)) @@ -593,6 +598,25 @@ Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason) return false; } +// 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_assignable(const Type* lhs, const Type* rhs, std::string* reason) +{ + return Type::are_assignable_check_hidden(lhs, rhs, false, reason); +} + +// Like are_assignable but don't check for hidden fields. + +bool +Type::are_assignable_hidden_ok(const Type* lhs, const Type* rhs, + std::string* reason) +{ + return Type::are_assignable_check_hidden(lhs, rhs, false, reason); +} + // 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. @@ -638,7 +662,7 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) { if (rhs->integer_type() != NULL) return true; - if (rhs->is_open_array_type() && rhs->named_type() == NULL) + if (rhs->is_slice_type() && rhs->named_type() == NULL) { const Type* e = rhs->array_type()->element_type()->forwarded(); if (e->integer_type() != NULL @@ -650,7 +674,7 @@ Type::are_convertible(const Type* lhs, const Type* rhs, std::string* reason) // A string may be converted to []byte or []int. if (rhs->is_string_type() - && lhs->is_open_array_type() + && lhs->is_slice_type() && lhs->named_type() == NULL) { const Type* e = lhs->array_type()->element_type()->forwarded(); @@ -744,181 +768,264 @@ Type::hash_string(const std::string& s, unsigned int h) return h; } -// Default check for the expression passed to make. Any type which -// may be used with make implements its own version of this. +// A hash table mapping unnamed types to the backend representation of +// those types. -bool -Type::do_check_make_expression(Expression_list*, source_location) -{ - gcc_unreachable(); -} +Type::Type_btypes Type::type_btypes; -// Return whether an expression has an integer value. Report an error -// if not. This is used when handling calls to the predeclared make -// function. +// Return a tree representing this type. -bool -Type::check_int_value(Expression* e, const char* errmsg, - source_location location) +Btype* +Type::get_backend(Gogo* gogo) { - if (e->type()->integer_type() != NULL) - return true; - - // Check for a floating point constant with integer value. - mpfr_t fval; - mpfr_init(fval); + if (this->btype_ != NULL) + return this->btype_; - Type* dummy; - if (e->float_constant_value(fval, &dummy)) - { - mpz_t ival; - mpz_init(ival); + if (this->forward_declaration_type() != NULL + || this->named_type() != NULL) + return this->get_btype_without_hash(gogo); - bool ok = false; + if (this->is_error_type()) + return gogo->backend()->error_type(); - mpfr_clear_overflow(); - mpfr_clear_erangeflag(); - mpfr_get_z(ival, fval, GMP_RNDN); - if (!mpfr_overflow_p() - && !mpfr_erangeflag_p() - && mpz_sgn(ival) >= 0) - { - Named_type* ntype = Type::lookup_integer_type("int"); - Integer_type* inttype = ntype->integer_type(); - mpz_t max; - mpz_init_set_ui(max, 1); - mpz_mul_2exp(max, max, inttype->bits() - 1); - ok = mpz_cmp(ival, max) < 0; - mpz_clear(max); - } - mpz_clear(ival); + // To avoid confusing the backend, translate all identical Go types + // to the same backend representation. We use a hash table to do + // that. There is no need to use the hash table for named types, as + // named types are only identical to themselves. - if (ok) - { - mpfr_clear(fval); - return true; - } + std::pair val(this, NULL); + std::pair ins = + Type::type_btypes.insert(val); + if (!ins.second && ins.first->second != NULL) + { + if (gogo != NULL && gogo->named_types_are_converted()) + this->btype_ = ins.first->second; + return ins.first->second; } - mpfr_clear(fval); + Btype* bt = this->get_btype_without_hash(gogo); - error_at(location, "%s", errmsg); - return false; + if (ins.first->second == NULL) + ins.first->second = bt; + else + { + // We have already created a backend representation for this + // type. This can happen when an unnamed type is defined using + // a named type which in turns uses an identical unnamed type. + // Use the tree we created earlier and ignore the one we just + // built. + bt = ins.first->second; + if (gogo == NULL || !gogo->named_types_are_converted()) + return bt; + this->btype_ = bt; + } + + return bt; } -// A hash table mapping unnamed types to trees. +// Return the backend representation for a type without looking in the +// hash table for identical types. This is used for named types, +// since a named type is never identical to any other type. -Type::Type_trees Type::type_trees; +Btype* +Type::get_btype_without_hash(Gogo* gogo) +{ + if (this->btype_ == NULL) + { + Btype* bt = this->do_get_backend(gogo); -// Return a tree representing this type. + // For a recursive function or pointer type, we will temporarily + // return a circular pointer type during the recursion. We + // don't want to record that for a forwarding type, as it may + // confuse us later. + if (this->forward_declaration_type() != NULL + && gogo->backend()->is_circular_pointer_type(bt)) + return bt; + + if (gogo == NULL || !gogo->named_types_are_converted()) + return bt; + + this->btype_ = bt; + } + return this->btype_; +} + +// Return a pointer to the type descriptor for this type. tree -Type::get_tree(Gogo* gogo) +Type::type_descriptor_pointer(Gogo* gogo, Location location) { - if (this->tree_ != NULL) - return this->tree_; + Type* t = this->forwarded(); + if (t->type_descriptor_var_ == NULL) + { + t->make_type_descriptor_var(gogo); + go_assert(t->type_descriptor_var_ != NULL); + } + tree var_tree = var_to_tree(t->type_descriptor_var_); + if (var_tree == error_mark_node) + return error_mark_node; + return build_fold_addr_expr_loc(location.gcc_location(), var_tree); +} - if (this->forward_declaration_type() != NULL - || this->named_type() != NULL) - return this->get_tree_without_hash(gogo); +// A mapping from unnamed types to type descriptor variables. - if (this->is_error_type()) - return error_mark_node; +Type::Type_descriptor_vars Type::type_descriptor_vars; + +// Build the type descriptor for this type. - // To avoid confusing GIMPLE, we need to translate all identical Go - // types to the same GIMPLE type. We use a hash table to do that. - // There is no need to use the hash table for named types, as named - // types are only identical to themselves. +void +Type::make_type_descriptor_var(Gogo* gogo) +{ + go_assert(this->type_descriptor_var_ == NULL); - std::pair val(this, NULL); - std::pair ins = - Type::type_trees.insert(val); - if (!ins.second && ins.first->second != NULL_TREE) + Named_type* nt = this->named_type(); + + // We can have multiple instances of unnamed types, but we only want + // to emit the type descriptor once. We use a hash table. This is + // not necessary for named types, as they are unique, and we store + // the type descriptor in the type itself. + Bvariable** phash = NULL; + if (nt == NULL) { - this->tree_ = ins.first->second; - return this->tree_; + Bvariable* bvnull = NULL; + std::pair ins = + Type::type_descriptor_vars.insert(std::make_pair(this, bvnull)); + if (!ins.second) + { + // We've already build a type descriptor for this type. + this->type_descriptor_var_ = ins.first->second; + return; + } + phash = &ins.first->second; } - tree t = this->get_tree_without_hash(gogo); + std::string var_name; + if (nt == NULL) + var_name = this->unnamed_type_descriptor_var_name(gogo); + else + var_name = this->type_descriptor_var_name(gogo); + + // Build the contents of the type descriptor. + Expression* initializer = this->do_type_descriptor(gogo, NULL); - if (ins.first->second == NULL_TREE) - ins.first->second = t; + Btype* initializer_btype = initializer->type()->get_backend(gogo); + + // See if this type descriptor is defined in a different package. + bool is_defined_elsewhere = false; + if (nt != NULL) + { + if (nt->named_object()->package() != NULL) + { + // This is a named type defined in a different package. The + // type descriptor should be defined in that package. + is_defined_elsewhere = true; + } + } else { - // We have already created a tree for this type. This can - // happen when an unnamed type is defined using a named type - // which in turns uses an identical unnamed type. Use the tree - // we created earlier and ignore the one we just built. - t = ins.first->second; - this->tree_ = t; + if (this->points_to() != NULL + && this->points_to()->named_type() != NULL + && this->points_to()->named_type()->named_object()->package() != NULL) + { + // This is an unnamed pointer to a named type defined in a + // different package. The descriptor should be defined in + // that package. + is_defined_elsewhere = true; + } } - return t; -} - -// Return a tree for a type without looking in the hash table for -// identical types. This is used for named types, since there is no -// point to looking in the hash table for them. + Location loc = nt == NULL ? Linemap::predeclared_location() : nt->location(); -tree -Type::get_tree_without_hash(Gogo* gogo) -{ - if (this->tree_ == NULL_TREE) + if (is_defined_elsewhere) { - tree t = this->do_get_tree(gogo); - - // For a recursive function or pointer type, we will temporarily - // return ptr_type_node during the recursion. We don't want to - // record that for a forwarding type, as it may confuse us - // later. - if (t == ptr_type_node && this->forward_declaration_type() != NULL) - return t; + this->type_descriptor_var_ = + gogo->backend()->immutable_struct_reference(var_name, + initializer_btype, + loc); + if (phash != NULL) + *phash = this->type_descriptor_var_; + return; + } - this->tree_ = t; - go_preserve_from_gc(t); + // See if this type descriptor can appear in multiple packages. + bool is_common = false; + if (nt != NULL) + { + // We create the descriptor for a builtin type whenever we need + // it. + is_common = nt->is_builtin(); + } + else + { + // This is an unnamed type. The descriptor could be defined in + // any package where it is needed, and the linker will pick one + // descriptor to keep. + is_common = true; } - return this->tree_; -} + // We are going to build the type descriptor in this package. We + // must create the variable before we convert the initializer to the + // backend representation, because the initializer may refer to the + // type descriptor of this type. By setting type_descriptor_var_ we + // ensure that type_descriptor_pointer will work if called while + // converting INITIALIZER. -// Return a tree representing a zero initialization for this type. + this->type_descriptor_var_ = + gogo->backend()->immutable_struct(var_name, is_common, initializer_btype, + loc); + if (phash != NULL) + *phash = this->type_descriptor_var_; -tree -Type::get_init_tree(Gogo* gogo, bool is_clear) -{ - tree type_tree = this->get_tree(gogo); - if (type_tree == error_mark_node) - return error_mark_node; - return this->do_get_init_tree(gogo, type_tree, is_clear); + Translate_context context(gogo, NULL, NULL, NULL); + context.set_is_const(); + Bexpression* binitializer = tree_to_expr(initializer->get_tree(&context)); + + gogo->backend()->immutable_struct_set_init(this->type_descriptor_var_, + var_name, is_common, + initializer_btype, loc, + binitializer); } -// Any type which supports the builtin make function must implement -// this. +// Return the name of the type descriptor variable for an unnamed +// type. -tree -Type::do_make_expression_tree(Translate_context*, Expression_list*, - source_location) +std::string +Type::unnamed_type_descriptor_var_name(Gogo* gogo) { - gcc_unreachable(); + return "__go_td_" + this->mangled_name(gogo); } -// Return a pointer to the type descriptor for this type. +// Return the name of the type descriptor variable for a named type. -tree -Type::type_descriptor_pointer(Gogo* gogo) -{ - Type* t = this->forwarded(); - if (t->type_descriptor_decl_ == NULL_TREE) +std::string +Type::type_descriptor_var_name(Gogo* gogo) +{ + Named_type* nt = this->named_type(); + Named_object* no = nt->named_object(); + const Named_object* in_function = nt->in_function(); + std::string ret = "__go_tdn_"; + if (nt->is_builtin()) + go_assert(in_function == NULL); + else { - Expression* e = t->do_type_descriptor(gogo, NULL); - gogo->build_type_descriptor_decl(t, e, &t->type_descriptor_decl_); - gcc_assert(t->type_descriptor_decl_ != NULL_TREE - && (t->type_descriptor_decl_ == error_mark_node - || DECL_P(t->type_descriptor_decl_))); + const std::string& unique_prefix(no->package() == NULL + ? gogo->unique_prefix() + : no->package()->unique_prefix()); + const std::string& package_name(no->package() == NULL + ? gogo->package_name() + : no->package()->name()); + ret.append(unique_prefix); + ret.append(1, '.'); + ret.append(package_name); + ret.append(1, '.'); + if (in_function != NULL) + { + ret.append(Gogo::unpack_hidden_name(in_function->name())); + ret.append(1, '.'); + } } - if (t->type_descriptor_decl_ == error_mark_node) - return error_mark_node; - return build_fold_addr_expr(t->type_descriptor_decl_); + ret.append(no->name()); + return ret; } // Return a composite literal for a type descriptor. @@ -934,7 +1041,7 @@ Type::type_descriptor(Gogo* gogo, Type* type) Expression* Type::named_type_descriptor(Gogo* gogo, Type* type, Named_type* name) { - gcc_assert(name != NULL && type->named_type() != name); + go_assert(name != NULL && type->named_type() != name); return type->do_type_descriptor(gogo, name); } @@ -947,7 +1054,7 @@ Type::make_builtin_struct_type(int nfields, ...) va_list ap; va_start(ap, nfields); - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); Struct_field_list* sfl = new Struct_field_list(); for (int i = 0; i < nfields; i++) { @@ -961,14 +1068,36 @@ Type::make_builtin_struct_type(int nfields, ...) return Type::make_struct_type(sfl, bloc); } +// A list of builtin named types. + +std::vector Type::named_builtin_types; + // Make a builtin named type. Named_type* Type::make_builtin_named_type(const char* name, Type* type) { - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); Named_object* no = Named_object::make_type(name, NULL, type, bloc); - return no->type_value(); + Named_type* ret = no->type_value(); + Type::named_builtin_types.push_back(ret); + return ret; +} + +// Convert the named builtin types. + +void +Type::convert_builtin_named_types(Gogo* gogo) +{ + for (std::vector::const_iterator p = + Type::named_builtin_types.begin(); + p != Type::named_builtin_types.end(); + ++p) + { + bool r = (*p)->verify(); + go_assert(r); + (*p)->convert(gogo); + } } // Return the type of a type descriptor. We should really tie this to @@ -981,7 +1110,7 @@ Type::make_type_descriptor_type() static Type* ret; if (ret == NULL) { - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); Type* uint8_type = Type::lookup_integer_type("uint8"); Type* uint32_type = Type::lookup_integer_type("uint32"); @@ -1050,7 +1179,7 @@ Type::make_type_descriptor_type() bloc); Struct_type* type_descriptor_type = - Type::make_builtin_struct_type(9, + Type::make_builtin_struct_type(10, "Kind", uint8_type, "align", uint8_type, "fieldAlign", uint8_type, @@ -1059,7 +1188,9 @@ Type::make_type_descriptor_type() "hashfn", hashfn_type, "equalfn", equalfn_type, "string", pointer_string_type, - "", pointer_uncommon_type); + "", pointer_uncommon_type, + "ptrToThis", + pointer_type_descriptor_type); Named_type* named = Type::make_builtin_named_type("commonType", type_descriptor_type); @@ -1140,10 +1271,10 @@ Type::type_functions(const char** hash_fn, const char** equal_fn) const case Type::TYPE_NAMED: case Type::TYPE_FORWARD: - gcc_unreachable(); + go_unreachable(); default: - gcc_unreachable(); + go_unreachable(); } } @@ -1155,7 +1286,7 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind, Named_type* name, const Methods* methods, bool only_value_methods) { - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); Type* td_type = Type::make_type_descriptor_type(); const Struct_field_list* fields = td_type->struct_type()->fields(); @@ -1163,29 +1294,31 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind, Expression_list* vals = new Expression_list(); vals->reserve(9); + if (!this->has_pointer()) + runtime_type_kind |= RUNTIME_TYPE_KIND_NO_POINTERS; Struct_field_list::const_iterator p = fields->begin(); - gcc_assert(p->field_name() == "Kind"); + go_assert(p->is_field_name("Kind")); mpz_t iv; mpz_init_set_ui(iv, runtime_type_kind); vals->push_back(Expression::make_integer(&iv, p->type(), bloc)); ++p; - gcc_assert(p->field_name() == "align"); + go_assert(p->is_field_name("align")); Expression::Type_info type_info = Expression::TYPE_INFO_ALIGNMENT; vals->push_back(Expression::make_type_info(this, type_info)); ++p; - gcc_assert(p->field_name() == "fieldAlign"); + go_assert(p->is_field_name("fieldAlign")); type_info = Expression::TYPE_INFO_FIELD_ALIGNMENT; vals->push_back(Expression::make_type_info(this, type_info)); ++p; - gcc_assert(p->field_name() == "size"); + go_assert(p->is_field_name("size")); type_info = Expression::TYPE_INFO_SIZE; vals->push_back(Expression::make_type_info(this, type_info)); ++p; - gcc_assert(p->field_name() == "hash"); + go_assert(p->is_field_name("hash")); mpz_set_ui(iv, this->hash_for_method(gogo)); vals->push_back(Expression::make_integer(&iv, p->type(), bloc)); @@ -1194,7 +1327,7 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind, this->type_functions(&hash_fn, &equal_fn); ++p; - gcc_assert(p->field_name() == "hashfn"); + go_assert(p->is_field_name("hashfn")); Function_type* fntype = p->type()->function_type(); Named_object* no = Named_object::make_function_declaration(hash_fn, NULL, fntype, @@ -1203,14 +1336,14 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind, vals->push_back(Expression::make_func_reference(no, NULL, bloc)); ++p; - gcc_assert(p->field_name() == "equalfn"); + go_assert(p->is_field_name("equalfn")); fntype = p->type()->function_type(); no = Named_object::make_function_declaration(equal_fn, NULL, fntype, bloc); no->func_declaration_value()->set_asm_name(equal_fn); vals->push_back(Expression::make_func_reference(no, NULL, bloc)); ++p; - gcc_assert(p->field_name() == "string"); + go_assert(p->is_field_name("string")); Expression* s = Expression::make_string((name != NULL ? name->reflection(gogo) : this->reflection(gogo)), @@ -1218,7 +1351,7 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind, vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); ++p; - gcc_assert(p->field_name() == "uncommonType"); + go_assert(p->is_field_name("uncommonType")); if (name == NULL && methods == NULL) vals->push_back(Expression::make_nil(bloc)); else @@ -1232,7 +1365,17 @@ Type::type_descriptor_constructor(Gogo* gogo, int runtime_type_kind, } ++p; - gcc_assert(p == fields->end()); + go_assert(p->is_field_name("ptrToThis")); + if (name == NULL) + vals->push_back(Expression::make_nil(bloc)); + else + { + Type* pt = Type::make_pointer_type(name); + vals->push_back(Expression::make_type_descriptor(pt, bloc)); + } + + ++p; + go_assert(p == fields->end()); mpz_clear(iv); @@ -1251,7 +1394,7 @@ Type::uncommon_type_constructor(Gogo* gogo, Type* uncommon_type, Named_type* name, const Methods* methods, bool only_value_methods) const { - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); const Struct_field_list* fields = uncommon_type->struct_type()->fields(); @@ -1259,10 +1402,10 @@ Type::uncommon_type_constructor(Gogo* gogo, Type* uncommon_type, vals->reserve(3); Struct_field_list::const_iterator p = fields->begin(); - gcc_assert(p->field_name() == "name"); + go_assert(p->is_field_name("name")); ++p; - gcc_assert(p->field_name() == "pkgPath"); + go_assert(p->is_field_name("pkgPath")); if (name == NULL) { @@ -1301,12 +1444,12 @@ Type::uncommon_type_constructor(Gogo* gogo, Type* uncommon_type, } ++p; - gcc_assert(p->field_name() == "methods"); + go_assert(p->is_field_name("methods")); vals->push_back(this->methods_constructor(gogo, p->type(), methods, only_value_methods)); ++p; - gcc_assert(p == fields->end()); + go_assert(p == fields->end()); Expression* r = Expression::make_struct_composite_literal(uncommon_type, vals, bloc); @@ -1334,7 +1477,7 @@ Type::methods_constructor(Gogo* gogo, Type* methods_type, const Methods* methods, bool only_value_methods) const { - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); std::vector > smethods; if (methods != NULL) @@ -1366,7 +1509,7 @@ Type::methods_constructor(Gogo* gogo, Type* methods_type, p != smethods.end(); ++p) vals->push_back(this->method_constructor(gogo, method_type, p->first, - p->second)); + p->second, only_value_methods)); return Expression::make_slice_composite_literal(methods_type, vals, bloc); } @@ -1378,9 +1521,10 @@ Type::methods_constructor(Gogo* gogo, Type* methods_type, Expression* Type::method_constructor(Gogo*, Type* method_type, const std::string& method_name, - const Method* m) const + const Method* m, + bool only_value_methods) const { - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); const Struct_field_list* fields = method_type->struct_type()->fields(); @@ -1388,13 +1532,13 @@ Type::method_constructor(Gogo*, Type* method_type, vals->reserve(5); Struct_field_list::const_iterator p = fields->begin(); - gcc_assert(p->field_name() == "name"); + go_assert(p->is_field_name("name")); const std::string n = Gogo::unpack_hidden_name(method_name); Expression* s = Expression::make_string(n, bloc); vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc)); ++p; - gcc_assert(p->field_name() == "pkgPath"); + go_assert(p->is_field_name("pkgPath")); if (!Gogo::is_hidden_name(method_name)) vals->push_back(Expression::make_nil(bloc)); else @@ -1412,23 +1556,42 @@ Type::method_constructor(Gogo*, Type* method_type, mtype = no->func_value()->type(); else mtype = no->func_declaration_value()->type(); - gcc_assert(mtype->is_method()); + go_assert(mtype->is_method()); Type* nonmethod_type = mtype->copy_without_receiver(); ++p; - gcc_assert(p->field_name() == "mtyp"); + go_assert(p->is_field_name("mtyp")); vals->push_back(Expression::make_type_descriptor(nonmethod_type, bloc)); ++p; - gcc_assert(p->field_name() == "typ"); + 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)); ++p; - gcc_assert(p->field_name() == "tfn"); + go_assert(p->is_field_name("tfn")); vals->push_back(Expression::make_func_reference(no, NULL, bloc)); ++p; - gcc_assert(p == fields->end()); + go_assert(p == fields->end()); return Expression::make_struct_composite_literal(method_type, vals, bloc); } @@ -1479,7 +1642,7 @@ Type::mangled_name(Gogo* gogo) const void Type::do_export(Export*) const { - gcc_unreachable(); + go_unreachable(); } // Import a type. @@ -1519,21 +1682,17 @@ class Error_type : public Type { } protected: - tree - do_get_tree(Gogo*) - { return error_mark_node; } - - tree - do_get_init_tree(Gogo*, tree, bool) - { return error_mark_node; } + Btype* + do_get_backend(Gogo* gogo) + { return gogo->backend()->error_type(); } Expression* do_type_descriptor(Gogo*, Named_type*) - { return Expression::make_error(BUILTINS_LOCATION); } + { return Expression::make_error(Linemap::predeclared_location()); } void do_reflection(Gogo*, std::string*) const - { gcc_assert(saw_errors()); } + { go_assert(saw_errors()); } void do_mangled_name(Gogo*, std::string* ret) const @@ -1557,17 +1716,13 @@ class Void_type : public Type { } protected: - tree - do_get_tree(Gogo*) - { return void_type_node; } - - tree - do_get_init_tree(Gogo*, tree, bool) - { gcc_unreachable(); } + Btype* + do_get_backend(Gogo* gogo) + { return gogo->backend()->void_type(); } Expression* do_type_descriptor(Gogo*, Named_type*) - { gcc_unreachable(); } + { go_unreachable(); } void do_reflection(Gogo*, std::string*) const @@ -1595,13 +1750,9 @@ class Boolean_type : public Type { } protected: - tree - do_get_tree(Gogo*) - { return boolean_type_node; } - - tree - do_get_init_tree(Gogo*, tree type_tree, bool is_clear) - { return is_clear ? NULL : fold_convert(type_tree, boolean_false_node); } + Btype* + do_get_backend(Gogo* gogo) + { return gogo->backend()->bool_type(); } Expression* do_type_descriptor(Gogo*, Named_type* name); @@ -1626,7 +1777,7 @@ Boolean_type::do_type_descriptor(Gogo* gogo, Named_type* name) else { Named_object* no = gogo->lookup_global("bool"); - gcc_assert(no != NULL); + go_assert(no != NULL); return Type::type_descriptor(gogo, no->type_value()); } } @@ -1656,9 +1807,9 @@ Named_type* Type::make_named_bool_type() { Type* bool_type = Type::make_boolean_type(); - Named_object* named_object = Named_object::make_type("bool", NULL, - bool_type, - BUILTINS_LOCATION); + Named_object* named_object = + Named_object::make_type("bool", NULL, bool_type, + Linemap::predeclared_location()); Named_type* named_type = named_object->type_value(); named_bool_type = named_type; return named_type; @@ -1678,13 +1829,13 @@ Integer_type::create_integer_type(const char* name, bool is_unsigned, Integer_type* integer_type = new Integer_type(false, is_unsigned, bits, runtime_type_kind); std::string sname(name); - Named_object* named_object = Named_object::make_type(sname, NULL, - integer_type, - BUILTINS_LOCATION); + Named_object* named_object = + Named_object::make_type(sname, NULL, integer_type, + Linemap::predeclared_location()); Named_type* named_type = named_object->type_value(); std::pair ins = Integer_type::named_integer_types.insert(std::make_pair(sname, named_type)); - gcc_assert(ins.second); + go_assert(ins.second); return named_type; } @@ -1695,7 +1846,7 @@ Integer_type::lookup_integer_type(const char* name) { Named_integer_types::const_iterator p = Integer_type::named_integer_types.find(name); - gcc_assert(p != Integer_type::named_integer_types.end()); + go_assert(p != Integer_type::named_integer_types.end()); return p->second; } @@ -1731,48 +1882,17 @@ Integer_type::do_hash_for_method(Gogo*) const + ((this->is_abstract_ ? 1 : 0) << 9)); } -// Get the tree for an Integer_type. +// Convert an Integer_type to the backend representation. -tree -Integer_type::do_get_tree(Gogo*) -{ - gcc_assert(!this->is_abstract_); - if (this->is_unsigned_) - { - if (this->bits_ == INT_TYPE_SIZE) - return unsigned_type_node; - else if (this->bits_ == CHAR_TYPE_SIZE) - return unsigned_char_type_node; - else if (this->bits_ == SHORT_TYPE_SIZE) - return short_unsigned_type_node; - else if (this->bits_ == LONG_TYPE_SIZE) - return long_unsigned_type_node; - else if (this->bits_ == LONG_LONG_TYPE_SIZE) - return long_long_unsigned_type_node; - else - return make_unsigned_type(this->bits_); - } - else +Btype* +Integer_type::do_get_backend(Gogo* gogo) +{ + if (this->is_abstract_) { - if (this->bits_ == INT_TYPE_SIZE) - return integer_type_node; - else if (this->bits_ == CHAR_TYPE_SIZE) - return signed_char_type_node; - else if (this->bits_ == SHORT_TYPE_SIZE) - return short_integer_type_node; - else if (this->bits_ == LONG_TYPE_SIZE) - return long_integer_type_node; - else if (this->bits_ == LONG_LONG_TYPE_SIZE) - return long_long_integer_type_node; - else - return make_signed_type(this->bits_); + go_assert(saw_errors()); + return gogo->backend()->error_type(); } -} - -tree -Integer_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear) -{ - return is_clear ? NULL : build_int_cst(type_tree, 0); + return gogo->backend()->integer_type(this->is_unsigned_, this->bits_); } // The type descriptor for an integer type. Integer types are always @@ -1781,7 +1901,7 @@ Integer_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear) Expression* Integer_type::do_type_descriptor(Gogo* gogo, Named_type* name) { - gcc_assert(name != NULL); + go_assert(name != NULL); return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name); } @@ -1790,7 +1910,7 @@ Integer_type::do_type_descriptor(Gogo* gogo, Named_type* name) void Integer_type::do_reflection(Gogo*, std::string*) const { - gcc_unreachable(); + go_assert(saw_errors()); } // Mangled name. @@ -1845,12 +1965,13 @@ Float_type::create_float_type(const char* name, int bits, { Float_type* float_type = new Float_type(false, bits, runtime_type_kind); std::string sname(name); - Named_object* named_object = Named_object::make_type(sname, NULL, float_type, - BUILTINS_LOCATION); + Named_object* named_object = + Named_object::make_type(sname, NULL, float_type, + Linemap::predeclared_location()); Named_type* named_type = named_object->type_value(); std::pair ins = Float_type::named_float_types.insert(std::make_pair(sname, named_type)); - gcc_assert(ins.second); + go_assert(ins.second); return named_type; } @@ -1861,7 +1982,7 @@ Float_type::lookup_float_type(const char* name) { Named_float_types::const_iterator p = Float_type::named_float_types.find(name); - gcc_assert(p != Float_type::named_float_types.end()); + go_assert(p != Float_type::named_float_types.end()); return p->second; } @@ -1894,42 +2015,12 @@ Float_type::do_hash_for_method(Gogo*) const return (this->bits_ << 4) + ((this->is_abstract_ ? 1 : 0) << 8); } -// Get a tree without using a Gogo*. - -tree -Float_type::type_tree() const -{ - if (this->bits_ == FLOAT_TYPE_SIZE) - return float_type_node; - else if (this->bits_ == DOUBLE_TYPE_SIZE) - return double_type_node; - else if (this->bits_ == LONG_DOUBLE_TYPE_SIZE) - return long_double_type_node; - else - { - tree ret = make_node(REAL_TYPE); - TYPE_PRECISION(ret) = this->bits_; - layout_type(ret); - return ret; - } -} - -// Get a tree. - -tree -Float_type::do_get_tree(Gogo*) -{ - return this->type_tree(); -} +// Convert to the backend representation. -tree -Float_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear) +Btype* +Float_type::do_get_backend(Gogo* gogo) { - if (is_clear) - return NULL; - REAL_VALUE_TYPE r; - real_from_integer(&r, TYPE_MODE(type_tree), 0, 0, 0); - return build_real(type_tree, r); + return gogo->backend()->float_type(this->bits_); } // The type descriptor for a float type. Float types are always named. @@ -1937,7 +2028,7 @@ Float_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear) Expression* Float_type::do_type_descriptor(Gogo* gogo, Named_type* name) { - gcc_assert(name != NULL); + go_assert(name != NULL); return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name); } @@ -1946,7 +2037,7 @@ Float_type::do_type_descriptor(Gogo* gogo, Named_type* name) void Float_type::do_reflection(Gogo*, std::string*) const { - gcc_unreachable(); + go_assert(saw_errors()); } // Mangled name. @@ -1999,14 +2090,14 @@ Complex_type::create_complex_type(const char* name, int bits, Complex_type* complex_type = new Complex_type(false, bits, runtime_type_kind); std::string sname(name); - Named_object* named_object = Named_object::make_type(sname, NULL, - complex_type, - BUILTINS_LOCATION); + Named_object* named_object = + Named_object::make_type(sname, NULL, complex_type, + Linemap::predeclared_location()); Named_type* named_type = named_object->type_value(); std::pair ins = Complex_type::named_complex_types.insert(std::make_pair(sname, named_type)); - gcc_assert(ins.second); + go_assert(ins.second); return named_type; } @@ -2017,7 +2108,7 @@ Complex_type::lookup_complex_type(const char* name) { Named_complex_types::const_iterator p = Complex_type::named_complex_types.find(name); - gcc_assert(p != Complex_type::named_complex_types.end()); + go_assert(p != Complex_type::named_complex_types.end()); return p->second; } @@ -2050,45 +2141,12 @@ Complex_type::do_hash_for_method(Gogo*) const return (this->bits_ << 4) + ((this->is_abstract_ ? 1 : 0) << 8); } -// Get a tree without using a Gogo*. - -tree -Complex_type::type_tree() const -{ - if (this->bits_ == FLOAT_TYPE_SIZE * 2) - return complex_float_type_node; - else if (this->bits_ == DOUBLE_TYPE_SIZE * 2) - return complex_double_type_node; - else if (this->bits_ == LONG_DOUBLE_TYPE_SIZE * 2) - return complex_long_double_type_node; - else - { - tree ret = make_node(REAL_TYPE); - TYPE_PRECISION(ret) = this->bits_ / 2; - layout_type(ret); - return build_complex_type(ret); - } -} - -// Get a tree. - -tree -Complex_type::do_get_tree(Gogo*) -{ - return this->type_tree(); -} - -// Zero initializer. +// Convert to the backend representation. -tree -Complex_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear) +Btype* +Complex_type::do_get_backend(Gogo* gogo) { - if (is_clear) - return NULL; - REAL_VALUE_TYPE r; - real_from_integer(&r, TYPE_MODE(TREE_TYPE(type_tree)), 0, 0, 0); - return build_complex(type_tree, build_real(TREE_TYPE(type_tree), r), - build_real(TREE_TYPE(type_tree), r)); + return gogo->backend()->complex_type(this->bits_); } // The type descriptor for a complex type. Complex types are always @@ -2097,7 +2155,7 @@ Complex_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear) Expression* Complex_type::do_type_descriptor(Gogo* gogo, Named_type* name) { - gcc_assert(name != NULL); + go_assert(name != NULL); return this->plain_type_descriptor(gogo, this->runtime_type_kind_, name); } @@ -2106,7 +2164,7 @@ Complex_type::do_type_descriptor(Gogo* gogo, Named_type* name) void Complex_type::do_reflection(Gogo*, std::string*) const { - gcc_unreachable(); + go_assert(saw_errors()); } // Mangled name. @@ -2147,18 +2205,31 @@ Type::lookup_complex_type(const char* name) // Class String_type. -// Return the tree for String_type. A string is a struct with two -// fields: a pointer to the characters and a length. +// Convert String_type to the backend representation. A string is a +// struct with two fields: a pointer to the characters and a length. -tree -String_type::do_get_tree(Gogo*) +Btype* +String_type::do_get_backend(Gogo* gogo) { - static tree struct_type; - return Gogo::builtin_struct(&struct_type, "__go_string", NULL_TREE, 2, - "__data", - build_pointer_type(unsigned_char_type_node), - "__length", - integer_type_node); + static Btype* backend_string_type; + if (backend_string_type == NULL) + { + std::vector fields(2); + + Type* b = gogo->lookup_global("byte")->type_value(); + Type* pb = Type::make_pointer_type(b); + fields[0].name = "__data"; + fields[0].btype = pb->get_backend(gogo); + fields[0].location = Linemap::predeclared_location(); + + Type* int_type = Type::lookup_integer_type("int"); + fields[1].name = "__length"; + fields[1].btype = int_type->get_backend(gogo); + fields[1].location = fields[0].location; + + backend_string_type = gogo->backend()->struct_type(fields); + } + return backend_string_type; } // Return a tree for the length of STRING. @@ -2167,9 +2238,9 @@ tree String_type::length_tree(Gogo*, tree string) { tree string_type = TREE_TYPE(string); - gcc_assert(TREE_CODE(string_type) == RECORD_TYPE); + go_assert(TREE_CODE(string_type) == RECORD_TYPE); tree length_field = DECL_CHAIN(TYPE_FIELDS(string_type)); - gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(length_field)), + go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(length_field)), "__length") == 0); return fold_build3(COMPONENT_REF, integer_type_node, string, length_field, NULL_TREE); @@ -2181,40 +2252,14 @@ tree String_type::bytes_tree(Gogo*, tree string) { tree string_type = TREE_TYPE(string); - gcc_assert(TREE_CODE(string_type) == RECORD_TYPE); + go_assert(TREE_CODE(string_type) == RECORD_TYPE); tree bytes_field = TYPE_FIELDS(string_type); - gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(bytes_field)), + go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(bytes_field)), "__data") == 0); return fold_build3(COMPONENT_REF, TREE_TYPE(bytes_field), string, bytes_field, NULL_TREE); } -// We initialize a string to { NULL, 0 }. - -tree -String_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear) -{ - if (is_clear) - return NULL_TREE; - - gcc_assert(TREE_CODE(type_tree) == RECORD_TYPE); - - VEC(constructor_elt, gc)* init = VEC_alloc(constructor_elt, gc, 2); - - for (tree field = TYPE_FIELDS(type_tree); - field != NULL_TREE; - field = DECL_CHAIN(field)) - { - constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), size_zero_node); - } - - tree ret = build_constructor(type_tree, init); - TREE_CONSTANT(ret) = 1; - return ret; -} - // The type descriptor for the string type. Expression* @@ -2225,7 +2270,7 @@ String_type::do_type_descriptor(Gogo* gogo, Named_type* name) else { Named_object* no = gogo->lookup_global("string"); - gcc_assert(no != NULL); + go_assert(no != NULL); return Type::type_descriptor(gogo, no->type_value()); } } @@ -2273,9 +2318,9 @@ Named_type* Type::make_named_string_type() { Type* string_type = Type::make_string_type(); - Named_object* named_object = Named_object::make_type("string", NULL, - string_type, - BUILTINS_LOCATION); + Named_object* named_object = + Named_object::make_type("string", NULL, string_type, + Linemap::predeclared_location()); Named_type* named_type = named_object->type_value(); named_string_type = named_type; return named_type; @@ -2292,25 +2337,21 @@ class Sink_type : public Type { } protected: - tree - do_get_tree(Gogo*) - { gcc_unreachable(); } - - tree - do_get_init_tree(Gogo*, tree, bool) - { gcc_unreachable(); } + Btype* + do_get_backend(Gogo*) + { go_unreachable(); } Expression* do_type_descriptor(Gogo*, Named_type*) - { gcc_unreachable(); } + { go_unreachable(); } void do_reflection(Gogo*, std::string*) const - { gcc_unreachable(); } + { go_unreachable(); } void do_mangled_name(Gogo*, std::string*) const - { gcc_unreachable(); } + { go_unreachable(); } }; // Make the sink type. @@ -2575,98 +2616,99 @@ Function_type::do_hash_for_method(Gogo* gogo) const return ret; } -// Get the tree for a function type. +// Get the backend representation for a function type. -tree -Function_type::do_get_tree(Gogo* gogo) +Btype* +Function_type::get_function_backend(Gogo* gogo) { - tree args = NULL_TREE; - tree* pp = &args; - + Backend::Btyped_identifier breceiver; if (this->receiver_ != NULL) { - Type* rtype = this->receiver_->type(); - tree ptype = rtype->get_tree(gogo); - if (ptype == error_mark_node) - return error_mark_node; + breceiver.name = Gogo::unpack_hidden_name(this->receiver_->name()); // We always pass the address of the receiver parameter, in // order to make interface calls work with unknown types. + Type* rtype = this->receiver_->type(); if (rtype->points_to() == NULL) - ptype = build_pointer_type(ptype); - - *pp = tree_cons (NULL_TREE, ptype, NULL_TREE); - pp = &TREE_CHAIN (*pp); + rtype = Type::make_pointer_type(rtype); + breceiver.btype = rtype->get_backend(gogo); + breceiver.location = this->receiver_->location(); } + std::vector bparameters; if (this->parameters_ != NULL) { + bparameters.resize(this->parameters_->size()); + size_t i = 0; for (Typed_identifier_list::const_iterator p = this->parameters_->begin(); p != this->parameters_->end(); - ++p) + ++p, ++i) { - tree ptype = p->type()->get_tree(gogo); - if (ptype == error_mark_node) - return error_mark_node; - *pp = tree_cons (NULL_TREE, ptype, NULL_TREE); - pp = &TREE_CHAIN (*pp); + bparameters[i].name = Gogo::unpack_hidden_name(p->name()); + bparameters[i].btype = p->type()->get_backend(gogo); + bparameters[i].location = p->location(); } + go_assert(i == bparameters.size()); } - // Varargs is handled entirely at the Go level. At the tree level, - // functions are not varargs. - *pp = void_list_node; - - tree result; - if (this->results_ == NULL) - result = void_type_node; - else if (this->results_->size() == 1) - result = this->results_->begin()->type()->get_tree(gogo); - else + std::vector bresults; + if (this->results_ != NULL) { - result = make_node(RECORD_TYPE); - tree field_trees = NULL_TREE; - tree* pp = &field_trees; + bresults.resize(this->results_->size()); + size_t i = 0; for (Typed_identifier_list::const_iterator p = this->results_->begin(); p != this->results_->end(); - ++p) + ++p, ++i) { - const std::string name = (p->name().empty() - ? "UNNAMED" - : Gogo::unpack_hidden_name(p->name())); - tree name_tree = get_identifier_with_length(name.data(), - name.length()); - tree field_type_tree = p->type()->get_tree(gogo); - if (field_type_tree == error_mark_node) - return error_mark_node; - tree field = build_decl(this->location_, FIELD_DECL, name_tree, - field_type_tree); - DECL_CONTEXT(field) = result; - *pp = field; - pp = &DECL_CHAIN(field); + bresults[i].name = Gogo::unpack_hidden_name(p->name()); + bresults[i].btype = p->type()->get_backend(gogo); + bresults[i].location = p->location(); } - TYPE_FIELDS(result) = field_trees; - layout_type(result); + go_assert(i == bresults.size()); } - if (result == error_mark_node) - return error_mark_node; + return gogo->backend()->function_type(breceiver, bparameters, bresults, + this->location()); +} - tree fntype = build_function_type(result, args); - if (fntype == error_mark_node) - return fntype; +// A hash table mapping function types to their backend placeholders. - return build_pointer_type(fntype); +Function_type::Placeholders Function_type::placeholders; + +// Get the backend representation for a function type. If we are +// still converting types, and this types has multiple results, return +// a placeholder instead. We do this because for multiple results we +// build a struct, and we need to make sure that all the types in the +// struct are valid before we create the struct. + +Btype* +Function_type::do_get_backend(Gogo* gogo) +{ + if (!gogo->named_types_are_converted() + && this->results_ != NULL + && this->results_->size() > 1) + { + Btype* placeholder = + gogo->backend()->placeholder_pointer_type("", this->location(), true); + Function_type::placeholders.push_back(std::make_pair(this, placeholder)); + return placeholder; + } + return this->get_function_backend(gogo); } -// Functions are initialized to NULL. +// Convert function types after all named types are converted. -tree -Function_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear) +void +Function_type::convert_types(Gogo* gogo) { - if (is_clear) - return NULL; - return fold_convert(type_tree, null_pointer_node); + for (Placeholders::const_iterator p = Function_type::placeholders.begin(); + p != Function_type::placeholders.end(); + ++p) + { + Btype* bt = p->first->get_function_backend(gogo); + if (!gogo->backend()->set_placeholder_function_type(p->second, bt)) + go_assert(saw_errors()); + } } // The type of a function type descriptor. @@ -2701,7 +2743,7 @@ Function_type::make_function_type_descriptor_type() Expression* Function_type::do_type_descriptor(Gogo* gogo, Named_type* name) { - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); Type* ftdt = Function_type::make_function_type_descriptor_type(); @@ -2711,27 +2753,27 @@ Function_type::do_type_descriptor(Gogo* gogo, Named_type* name) vals->reserve(4); Struct_field_list::const_iterator p = fields->begin(); - gcc_assert(p->field_name() == "commonType"); + go_assert(p->is_field_name("commonType")); vals->push_back(this->type_descriptor_constructor(gogo, RUNTIME_TYPE_KIND_FUNC, name, NULL, true)); ++p; - gcc_assert(p->field_name() == "dotdotdot"); + go_assert(p->is_field_name("dotdotdot")); vals->push_back(Expression::make_boolean(this->is_varargs(), bloc)); ++p; - gcc_assert(p->field_name() == "in"); + go_assert(p->is_field_name("in")); vals->push_back(this->type_descriptor_params(p->type(), this->receiver(), this->parameters())); ++p; - gcc_assert(p->field_name() == "out"); + go_assert(p->is_field_name("out")); vals->push_back(this->type_descriptor_params(p->type(), NULL, this->results())); ++p; - gcc_assert(p == fields->end()); + go_assert(p == fields->end()); return Expression::make_struct_composite_literal(ftdt, vals, bloc); } @@ -2744,7 +2786,7 @@ Function_type::type_descriptor_params(Type* params_type, const Typed_identifier* receiver, const Typed_identifier_list* params) { - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); if (receiver == NULL && params == NULL) return Expression::make_slice_composite_literal(params_type, NULL, bloc); @@ -2754,14 +2796,7 @@ Function_type::type_descriptor_params(Type* params_type, + (receiver != NULL ? 1 : 0)); if (receiver != NULL) - { - Type* rtype = receiver->type(); - // The receiver is always passed as a pointer. FIXME: Is this - // right? Should that fact affect the type descriptor? - if (rtype->points_to() == NULL) - rtype = Type::make_pointer_type(rtype); - vals->push_back(Expression::make_type_descriptor(rtype, bloc)); - } + vals->push_back(Expression::make_type_descriptor(receiver->type(), bloc)); if (params != NULL) { @@ -2781,7 +2816,7 @@ Function_type::do_reflection(Gogo* gogo, std::string* ret) const { // FIXME: Turn this off until we straighten out the type of the // struct field used in a go statement which calls a method. - // gcc_assert(this->receiver_ == NULL); + // go_assert(this->receiver_ == NULL); ret->append("func"); @@ -2963,7 +2998,7 @@ Function_type::do_import(Import* imp) ptype, imp->location())); if (imp->peek_char() != ',') break; - gcc_assert(!is_varargs); + go_assert(!is_varargs); imp->require_c_string(", "); } } @@ -3010,7 +3045,7 @@ Function_type::do_import(Import* imp) Function_type* Function_type::copy_without_receiver() const { - gcc_assert(this->is_method()); + go_assert(this->is_method()); Function_type *ret = Type::make_function_type(NULL, this->parameters_, this->results_, this->location_); @@ -3026,7 +3061,7 @@ Function_type::copy_without_receiver() const Function_type* Function_type::copy_with_receiver(Type* receiver_type) const { - gcc_assert(!this->is_method()); + go_assert(!this->is_method()); Typed_identifier* receiver = new Typed_identifier("", receiver_type, this->location_); return Type::make_function_type(receiver, this->parameters_, @@ -3039,7 +3074,7 @@ Function_type* Type::make_function_type(Typed_identifier* receiver, Typed_identifier_list* parameters, Typed_identifier_list* results, - source_location location) + Location location) { return new Function_type(receiver, parameters, results, location); } @@ -3064,20 +3099,11 @@ Pointer_type::do_hash_for_method(Gogo* gogo) const // The tree for a pointer type. -tree -Pointer_type::do_get_tree(Gogo* gogo) -{ - return build_pointer_type(this->to_type_->get_tree(gogo)); -} - -// Initialize a pointer type. - -tree -Pointer_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear) +Btype* +Pointer_type::do_get_backend(Gogo* gogo) { - if (is_clear) - return NULL; - return fold_convert(type_tree, null_pointer_node); + Btype* to_btype = this->to_type_->get_backend(gogo); + return gogo->backend()->pointer_type(to_btype); } // The type of a pointer type descriptor. @@ -3108,14 +3134,14 @@ Pointer_type::do_type_descriptor(Gogo* gogo, Named_type* name) { if (this->is_unsafe_pointer_type()) { - gcc_assert(name != NULL); + go_assert(name != NULL); return this->plain_type_descriptor(gogo, RUNTIME_TYPE_KIND_UNSAFE_POINTER, name); } else { - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); const Methods* methods; Type* deref = this->points_to(); @@ -3134,13 +3160,13 @@ Pointer_type::do_type_descriptor(Gogo* gogo, Named_type* name) vals->reserve(2); Struct_field_list::const_iterator p = fields->begin(); - gcc_assert(p->field_name() == "commonType"); + go_assert(p->is_field_name("commonType")); vals->push_back(this->type_descriptor_constructor(gogo, RUNTIME_TYPE_KIND_PTR, name, methods, false)); ++p; - gcc_assert(p->field_name() == "elem"); + go_assert(p->is_field_name("elem")); vals->push_back(Expression::make_type_descriptor(deref, bloc)); return Expression::make_struct_composite_literal(ptr_tdt, vals, bloc); @@ -3219,21 +3245,17 @@ class Nil_type : public Type { } protected: - tree - do_get_tree(Gogo*) - { return ptr_type_node; } - - tree - do_get_init_tree(Gogo*, tree type_tree, bool is_clear) - { return is_clear ? NULL : fold_convert(type_tree, null_pointer_node); } + Btype* + do_get_backend(Gogo* gogo) + { return gogo->backend()->pointer_type(gogo->backend()->void_type()); } Expression* do_type_descriptor(Gogo*, Named_type*) - { gcc_unreachable(); } + { go_unreachable(); } void do_reflection(Gogo*, std::string*) const - { gcc_unreachable(); } + { go_unreachable(); } void do_mangled_name(Gogo*, std::string* ret) const @@ -3266,65 +3288,37 @@ class Call_multiple_result_type : public Type bool do_has_pointer() const { - gcc_assert(saw_errors()); + go_assert(saw_errors()); return false; } - tree - do_get_tree(Gogo*); - - tree - do_get_init_tree(Gogo*, tree, bool) + Btype* + do_get_backend(Gogo* gogo) { - gcc_assert(saw_errors()); - return error_mark_node; + go_assert(saw_errors()); + return gogo->backend()->error_type(); } Expression* do_type_descriptor(Gogo*, Named_type*) { - gcc_assert(saw_errors()); - return Expression::make_error(UNKNOWN_LOCATION); + go_assert(saw_errors()); + return Expression::make_error(Linemap::unknown_location()); } void do_reflection(Gogo*, std::string*) const - { gcc_assert(saw_errors()); } + { go_assert(saw_errors()); } void do_mangled_name(Gogo*, std::string*) const - { gcc_assert(saw_errors()); } + { go_assert(saw_errors()); } private: // The expression being called. Call_expression* call_; }; -// Return the tree for a call result. - -tree -Call_multiple_result_type::do_get_tree(Gogo* gogo) -{ - Function_type* fntype = this->call_->get_function_type(); - gcc_assert(fntype != NULL); - const Typed_identifier_list* results = fntype->results(); - gcc_assert(results != NULL && results->size() > 1); - - Struct_field_list* sfl = new Struct_field_list; - for (Typed_identifier_list::const_iterator p = results->begin(); - p != results->end(); - ++p) - { - const std::string name = ((p->name().empty() - || p->name() == Import::import_marker) - ? "UNNAMED" - : p->name()); - sfl->push_back(Struct_field(Typed_identifier(name, p->type(), - this->call_->location()))); - } - return Type::make_struct_type(sfl, this->call_->location())->get_tree(gogo); -} - // Make a call result type. Type* @@ -3369,17 +3363,45 @@ Struct_field::field_name() const { // Avoid crashing in the erroneous case where T is named but // DT is not. - gcc_assert(t != dt); + go_assert(t != dt); if (t->forward_declaration_type() != NULL) return t->forward_declaration_type()->name(); else if (t->named_type() != NULL) return t->named_type()->name(); else - gcc_unreachable(); + go_unreachable(); } } } +// Return whether this field is named NAME. + +bool +Struct_field::is_field_name(const std::string& name) const +{ + const std::string& me(this->typed_identifier_.name()); + if (!me.empty()) + return me == name; + else + { + 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->name() == name) + return true; + + // This is a horrible hack caused by the fact that we don't pack + // the names of builtin types. FIXME. + if (nt != NULL + && nt->is_builtin() + && nt->name() == Gogo::unpack_hidden_name(name)) + return true; + + return false; + } +} + // Class Struct_type. // Traversal. @@ -3429,6 +3451,14 @@ Struct_type::do_verify() p->set_type(Type::make_error_type()); return false; } + if (t->points_to() != NULL + && t->points_to()->interface_type() != NULL) + { + error_at(p->location(), + "embedded type may not be pointer to interface"); + p->set_type(Type::make_error_type()); + return false; + } } } return ret; @@ -3566,7 +3596,7 @@ Struct_type::find_local_field(const std::string& name, pf != fields->end(); ++pf, ++i) { - if (pf->field_name() == name) + if (pf->is_field_name(name)) { if (pindex != NULL) *pindex = i; @@ -3580,7 +3610,7 @@ Struct_type::find_local_field(const std::string& name, Field_reference_expression* Struct_type::field_reference(Expression* struct_expr, const std::string& name, - source_location location) const + Location location) const { unsigned int depth; return this->field_reference_depth(struct_expr, name, location, NULL, @@ -3593,7 +3623,7 @@ Struct_type::field_reference(Expression* struct_expr, const std::string& name, Field_reference_expression* Struct_type::field_reference_depth(Expression* struct_expr, const std::string& name, - source_location location, + Location location, Saw_named_type* saw, unsigned int* depth) const { @@ -3607,7 +3637,7 @@ Struct_type::field_reference_depth(Expression* struct_expr, pf != fields->end(); ++pf, ++i) { - if (pf->field_name() == name) + if (pf->is_field_name(name)) { *depth = 0; return Expression::make_field_reference(struct_expr, i, location); @@ -3681,7 +3711,7 @@ Struct_type::field_reference_depth(Expression* struct_expr, while (sub->expr() != NULL) { sub = sub->expr()->deref()->field_reference_expression(); - gcc_assert(sub != NULL); + go_assert(sub != NULL); } sub->set_struct_expression(here); } @@ -3766,140 +3796,35 @@ Struct_type::method_function(const std::string& name, bool* is_ambiguous) const return Type::method_function(this->all_methods_, name, is_ambiguous); } -// Get the tree for a struct type. - -tree -Struct_type::do_get_tree(Gogo* gogo) -{ - tree type = make_node(RECORD_TYPE); - return this->fill_in_tree(gogo, type); -} - -// Fill in the fields for a struct type. +// Convert struct fields to the backend representation. This is not +// declared in types.h so that types.h doesn't have to #include +// backend.h. -tree -Struct_type::fill_in_tree(Gogo* gogo, tree type) +static void +get_backend_struct_fields(Gogo* gogo, const Struct_field_list* fields, + std::vector* bfields) { - tree field_trees = NULL_TREE; - tree* pp = &field_trees; - bool has_pointer = false; - for (Struct_field_list::const_iterator p = this->fields_->begin(); - p != this->fields_->end(); - ++p) - { - std::string name = Gogo::unpack_hidden_name(p->field_name()); - tree name_tree = get_identifier_with_length(name.data(), name.length()); - - // Don't follow pointers yet, so that we don't get confused by a - // pointer to an array of this struct type. - tree field_type_tree; - if (p->type()->points_to() != NULL || p->type()->function_type() != NULL) - { - field_type_tree = ptr_type_node; - has_pointer = true; - } - else - { - field_type_tree = p->type()->get_tree(gogo); - if (field_type_tree == error_mark_node) - return error_mark_node; - } - - tree field = build_decl(p->location(), FIELD_DECL, name_tree, - field_type_tree); - DECL_CONTEXT(field) = type; - *pp = field; - pp = &DECL_CHAIN(field); - } - - TYPE_FIELDS(type) = field_trees; - - layout_type(type); - - if (has_pointer) + bfields->resize(fields->size()); + size_t i = 0; + for (Struct_field_list::const_iterator p = fields->begin(); + p != fields->end(); + ++p, ++i) { - tree field = field_trees; - for (Struct_field_list::const_iterator p = this->fields_->begin(); - p != this->fields_->end(); - ++p, field = DECL_CHAIN(field)) - { - if (p->type()->points_to() != NULL - || p->type()->function_type() != NULL) - TREE_TYPE(field) = p->type()->get_tree(gogo); - } + (*bfields)[i].name = Gogo::unpack_hidden_name(p->field_name()); + (*bfields)[i].btype = p->type()->get_backend(gogo); + (*bfields)[i].location = p->location(); } - - return type; -} - -// Make sure that all structs which must be converted to the backend -// representation before this one are in fact converted. - -void -Struct_type::convert_prerequisites(Gogo* gogo) -{ - for (std::vector::const_iterator p - = this->prerequisites_.begin(); - p != this->prerequisites_.end(); - ++p) - (*p)->get_tree(gogo); + go_assert(i == fields->size()); } -// Initialize struct fields. +// Get the tree for a struct type. -tree -Struct_type::do_get_init_tree(Gogo* gogo, tree type_tree, bool is_clear) +Btype* +Struct_type::do_get_backend(Gogo* gogo) { - if (this->fields_ == NULL || this->fields_->empty()) - { - if (is_clear) - return NULL; - else - { - tree ret = build_constructor(type_tree, - VEC_alloc(constructor_elt, gc, 0)); - TREE_CONSTANT(ret) = 1; - return ret; - } - } - - bool is_constant = true; - bool any_fields_set = false; - VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, - this->fields_->size()); - - tree field = TYPE_FIELDS(type_tree); - for (Struct_field_list::const_iterator p = this->fields_->begin(); - p != this->fields_->end(); - ++p, field = DECL_CHAIN(field)) - { - tree value = p->type()->get_init_tree(gogo, is_clear); - if (value == error_mark_node) - return error_mark_node; - gcc_assert(field != NULL_TREE); - if (value != NULL) - { - constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL); - elt->index = field; - elt->value = value; - any_fields_set = true; - if (!TREE_CONSTANT(value)) - is_constant = false; - } - } - gcc_assert(field == NULL_TREE); - - if (!any_fields_set) - { - gcc_assert(is_clear); - VEC_free(constructor_elt, gc, init); - return NULL; - } - - tree ret = build_constructor(type_tree, init); - if (is_constant) - TREE_CONSTANT(ret) = 1; - return ret; + std::vector bfields; + get_backend_struct_fields(gogo, this->fields_, &bfields); + return gogo->backend()->struct_type(bfields); } // The type of a struct type descriptor. @@ -3943,7 +3868,7 @@ Struct_type::make_struct_type_descriptor_type() Expression* Struct_type::do_type_descriptor(Gogo* gogo, Named_type* name) { - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); Type* stdt = Struct_type::make_struct_type_descriptor_type(); @@ -3955,16 +3880,16 @@ Struct_type::do_type_descriptor(Gogo* gogo, Named_type* name) const Methods* methods = this->methods(); // A named struct should not have methods--the methods should attach // to the named type. - gcc_assert(methods == NULL || name == NULL); + go_assert(methods == NULL || name == NULL); Struct_field_list::const_iterator ps = fields->begin(); - gcc_assert(ps->field_name() == "commonType"); + go_assert(ps->is_field_name("commonType")); vals->push_back(this->type_descriptor_constructor(gogo, RUNTIME_TYPE_KIND_STRUCT, name, methods, true)); ++ps; - gcc_assert(ps->field_name() == "fields"); + go_assert(ps->is_field_name("fields")); Expression_list* elements = new Expression_list(); elements->reserve(this->fields_->size()); @@ -3979,7 +3904,7 @@ Struct_type::do_type_descriptor(Gogo* gogo, Named_type* name) fvals->reserve(5); Struct_field_list::const_iterator q = f->begin(); - gcc_assert(q->field_name() == "name"); + go_assert(q->is_field_name("name")); if (pf->is_anonymous()) fvals->push_back(Expression::make_nil(bloc)); else @@ -3990,7 +3915,7 @@ Struct_type::do_type_descriptor(Gogo* gogo, Named_type* name) } ++q; - gcc_assert(q->field_name() == "pkgPath"); + go_assert(q->is_field_name("pkgPath")); if (!Gogo::is_hidden_name(pf->field_name())) fvals->push_back(Expression::make_nil(bloc)); else @@ -4001,11 +3926,11 @@ Struct_type::do_type_descriptor(Gogo* gogo, Named_type* name) } ++q; - gcc_assert(q->field_name() == "typ"); + go_assert(q->is_field_name("typ")); fvals->push_back(Expression::make_type_descriptor(pf->type(), bloc)); ++q; - gcc_assert(q->field_name() == "tag"); + go_assert(q->is_field_name("tag")); if (!pf->has_tag()) fvals->push_back(Expression::make_nil(bloc)); else @@ -4015,7 +3940,7 @@ Struct_type::do_type_descriptor(Gogo* gogo, Named_type* name) } ++q; - gcc_assert(q->field_name() == "offset"); + go_assert(q->is_field_name("offset")); fvals->push_back(Expression::make_struct_field_offset(this, &*pf)); Expression* v = Expression::make_struct_composite_literal(element_type, @@ -4140,7 +4065,7 @@ Struct_type::do_export(Export* exp) const { exp->write_c_string("struct { "); const Struct_field_list* fields = this->fields_; - gcc_assert(fields != NULL); + go_assert(fields != NULL); for (Struct_field_list::const_iterator p = fields->begin(); p != fields->end(); ++p) @@ -4157,8 +4082,8 @@ Struct_type::do_export(Export* exp) const if (p->has_tag()) { exp->write_c_string(" "); - Expression* expr = Expression::make_string(p->tag(), - BUILTINS_LOCATION); + Expression* expr = + Expression::make_string(p->tag(), Linemap::predeclared_location()); expr->export_expression(exp); delete expr; } @@ -4196,7 +4121,7 @@ Struct_type::do_import(Import* imp) imp->advance(1); Expression* expr = Expression::import_expression(imp); String_expression* sexpr = expr->string_expression(); - gcc_assert(sexpr != NULL); + go_assert(sexpr != NULL); sf.set_tag(sexpr->val()); delete sexpr; } @@ -4216,7 +4141,7 @@ Struct_type::do_import(Import* imp) Struct_type* Type::make_struct_type(Struct_field_list* fields, - source_location location) + Location location) { return new Struct_type(fields, location); } @@ -4287,6 +4212,10 @@ Array_type::verify_length() { if (this->length_ == NULL) return true; + + Type_context context(Type::lookup_integer_type("int"), false); + this->length_->determine_type(&context); + if (!this->length_->is_constant()) { error_at(this->length_->location(), "array bound is not constant"); @@ -4294,30 +4223,23 @@ Array_type::verify_length() } mpz_t val; - - Type* t = this->length_->type(); - if (t->integer_type() != NULL) + mpz_init(val); + Type* vt; + if (!this->length_->integer_constant_value(true, val, &vt)) { - Type* vt; - mpz_init(val); - if (!this->length_->integer_constant_value(true, val, &vt)) - { - error_at(this->length_->location(), - "array bound is not constant"); - mpz_clear(val); - return false; - } - } - else if (t->float_type() != NULL) - { - Type* vt; mpfr_t fval; mpfr_init(fval); if (!this->length_->float_constant_value(fval, &vt)) { - error_at(this->length_->location(), - "array bound is not constant"); + if (this->length_->type()->integer_type() != NULL + || this->length_->type()->float_type() != NULL) + error_at(this->length_->location(), + "array bound is not constant"); + else + error_at(this->length_->location(), + "array bound is not numeric"); mpfr_clear(fval); + mpz_clear(val); return false; } if (!mpfr_integer_p(fval)) @@ -4325,18 +4247,13 @@ Array_type::verify_length() error_at(this->length_->location(), "array bound truncated to integer"); mpfr_clear(fval); + mpz_clear(val); return false; } mpz_init(val); mpfr_get_z(val, fval, GMP_RNDN); mpfr_clear(fval); } - else - { - if (!t->is_error_type()) - error_at(this->length_->location(), "array bound is not numeric"); - return false; - } if (mpz_sgn(val) < 0) { @@ -4383,50 +4300,13 @@ Array_type::do_hash_for_method(Gogo* gogo) const return this->element_type_->hash_for_method(gogo) + 1; } -// See if the expression passed to make is suitable. The first -// argument is required, and gives the length. An optional second -// argument is permitted for the capacity. - -bool -Array_type::do_check_make_expression(Expression_list* args, - source_location location) -{ - gcc_assert(this->length_ == NULL); - if (args == NULL || args->empty()) - { - error_at(location, "length required when allocating a slice"); - return false; - } - else if (args->size() > 2) - { - error_at(location, "too many expressions passed to make"); - return false; - } - else - { - if (!Type::check_int_value(args->front(), - _("bad length when making slice"), location)) - return false; - - if (args->size() > 1) - { - if (!Type::check_int_value(args->back(), - _("bad capacity when making slice"), - location)) - return false; - } - - return true; - } -} - // Get a tree for the length of a fixed array. The length may be // computed using a function call, so we must only evaluate it once. tree Array_type::get_length_tree(Gogo* gogo) { - gcc_assert(this->length_ != NULL); + go_assert(this->length_ != NULL); if (this->length_tree_ == NULL_TREE) { mpz_t val; @@ -4438,7 +4318,7 @@ Array_type::get_length_tree(Gogo* gogo) t = Type::lookup_integer_type("int"); else if (t->is_abstract()) t = t->make_non_abstract_type(); - tree tt = t->get_tree(gogo); + tree tt = type_to_tree(t->get_backend(gogo)); this->length_tree_ = Expression::integer_constant_tree(val, tt); mpz_clear(val); } @@ -4448,7 +4328,7 @@ Array_type::get_length_tree(Gogo* gogo) // Make up a translation context for the array length // expression. FIXME: This won't work in general. - Translate_context context(gogo, NULL, NULL, NULL_TREE); + Translate_context context(gogo, NULL, NULL, NULL); tree len = this->length_->get_tree(&context); if (len != error_mark_node) { @@ -4461,298 +4341,77 @@ Array_type::get_length_tree(Gogo* gogo) return this->length_tree_; } -// Get a tree for the type of this array. A fixed array is simply -// represented as ARRAY_TYPE with the appropriate index--i.e., it is -// just like an array in C. An open array is a struct with three -// fields: a data pointer, the length, and the capacity. +// Get the backend representation of the fields of a slice. This is +// not declared in types.h so that types.h doesn't have to #include +// backend.h. +// +// We use int for the count and capacity fields. This matches 6g. +// The language more or less assumes that we can't allocate space of a +// size which does not fit in int. -tree -Array_type::do_get_tree(Gogo* gogo) +static void +get_backend_slice_fields(Gogo* gogo, Array_type* type, + std::vector* bfields) { - if (this->length_ == NULL) - { - tree struct_type = gogo->slice_type_tree(void_type_node); - return this->fill_in_slice_tree(gogo, struct_type); - } - else - { - tree array_type = make_node(ARRAY_TYPE); - return this->fill_in_array_tree(gogo, array_type); - } -} + bfields->resize(3); -// Fill in the fields for an array type. This is used for named array -// types. + Type* pet = Type::make_pointer_type(type->element_type()); + Btype* pbet = pet->get_backend(gogo); + Location ploc = Linemap::predeclared_location(); -tree -Array_type::fill_in_array_tree(Gogo* gogo, tree array_type) -{ - gcc_assert(this->length_ != NULL); - - tree element_type_tree = this->element_type_->get_tree(gogo); - tree length_tree = this->get_length_tree(gogo); - if (element_type_tree == error_mark_node - || length_tree == error_mark_node) - return error_mark_node; + Backend::Btyped_identifier* p = &(*bfields)[0]; + p->name = "__values"; + p->btype = pbet; + p->location = ploc; - length_tree = fold_convert(sizetype, length_tree); - - // build_index_type takes the maximum index, which is one less than - // the length. - tree index_type = build_index_type(fold_build2(MINUS_EXPR, sizetype, - length_tree, - size_one_node)); - - TREE_TYPE(array_type) = element_type_tree; - TYPE_DOMAIN(array_type) = index_type; - TYPE_ADDR_SPACE(array_type) = TYPE_ADDR_SPACE(element_type_tree); - layout_type(array_type); + Type* int_type = Type::lookup_integer_type("int"); - if (TYPE_STRUCTURAL_EQUALITY_P(element_type_tree) - || TYPE_STRUCTURAL_EQUALITY_P(index_type)) - SET_TYPE_STRUCTURAL_EQUALITY(array_type); - else if (TYPE_CANONICAL(element_type_tree) != element_type_tree - || TYPE_CANONICAL(index_type) != index_type) - TYPE_CANONICAL(array_type) = - build_array_type(TYPE_CANONICAL(element_type_tree), - TYPE_CANONICAL(index_type)); + p = &(*bfields)[1]; + p->name = "__count"; + p->btype = int_type->get_backend(gogo); + p->location = ploc; - return array_type; + p = &(*bfields)[2]; + p->name = "__capacity"; + p->btype = int_type->get_backend(gogo); + p->location = ploc; } -// Fill in the fields for a slice type. This is used for named slice -// types. - -tree -Array_type::fill_in_slice_tree(Gogo* gogo, tree struct_type) -{ - gcc_assert(this->length_ == NULL); - - tree element_type_tree = this->element_type_->get_tree(gogo); - if (element_type_tree == error_mark_node) - return error_mark_node; - tree field = TYPE_FIELDS(struct_type); - gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0); - gcc_assert(POINTER_TYPE_P(TREE_TYPE(field)) - && TREE_TYPE(TREE_TYPE(field)) == void_type_node); - TREE_TYPE(field) = build_pointer_type(element_type_tree); - - return struct_type; -} - -// Return an initializer for an array type. +// Get a tree for the type of this array. A fixed array is simply +// represented as ARRAY_TYPE with the appropriate index--i.e., it is +// just like an array in C. An open array is a struct with three +// fields: a data pointer, the length, and the capacity. -tree -Array_type::do_get_init_tree(Gogo* gogo, tree type_tree, bool is_clear) +Btype* +Array_type::do_get_backend(Gogo* gogo) { if (this->length_ == NULL) { - // Open array. - - if (is_clear) - return NULL; - - gcc_assert(TREE_CODE(type_tree) == RECORD_TYPE); - - VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 3); - - for (tree field = TYPE_FIELDS(type_tree); - field != NULL_TREE; - field = DECL_CHAIN(field)) - { - constructor_elt* elt = VEC_quick_push(constructor_elt, init, - NULL); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), size_zero_node); - } - - tree ret = build_constructor(type_tree, init); - TREE_CONSTANT(ret) = 1; - return ret; + std::vector bfields; + get_backend_slice_fields(gogo, this, &bfields); + return gogo->backend()->struct_type(bfields); } else { - // Fixed array. - - tree value = this->element_type_->get_init_tree(gogo, is_clear); - if (value == NULL) - return NULL; - if (value == error_mark_node) - return error_mark_node; - - tree length_tree = this->get_length_tree(gogo); - if (length_tree == error_mark_node) - return error_mark_node; - - length_tree = fold_convert(sizetype, length_tree); - tree range = build2(RANGE_EXPR, sizetype, size_zero_node, - fold_build2(MINUS_EXPR, sizetype, - length_tree, size_one_node)); - tree ret = build_constructor_single(type_tree, range, value); - if (TREE_CONSTANT(value)) - TREE_CONSTANT(ret) = 1; - return ret; + Btype* element = this->get_backend_element(gogo); + Bexpression* len = this->get_backend_length(gogo); + return gogo->backend()->array_type(element, len); } } -// Handle the builtin make function for a slice. - -tree -Array_type::do_make_expression_tree(Translate_context* context, - Expression_list* args, - source_location location) +// Return the backend representation of the element type. +Btype* +Array_type::get_backend_element(Gogo* gogo) { - gcc_assert(this->length_ == NULL); - - Gogo* gogo = context->gogo(); - tree type_tree = this->get_tree(gogo); - if (type_tree == error_mark_node) - return error_mark_node; - - tree values_field = TYPE_FIELDS(type_tree); - gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(values_field)), - "__values") == 0); - - tree count_field = DECL_CHAIN(values_field); - gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(count_field)), - "__count") == 0); - - tree element_type_tree = this->element_type_->get_tree(gogo); - if (element_type_tree == error_mark_node) - return error_mark_node; - tree element_size_tree = TYPE_SIZE_UNIT(element_type_tree); - - tree value = this->element_type_->get_init_tree(gogo, true); - if (value == error_mark_node) - return error_mark_node; - - // The first argument is the number of elements, the optional second - // argument is the capacity. - gcc_assert(args != NULL && args->size() >= 1 && args->size() <= 2); - - tree length_tree = args->front()->get_tree(context); - if (length_tree == error_mark_node) - return error_mark_node; - if (!DECL_P(length_tree)) - length_tree = save_expr(length_tree); - if (!INTEGRAL_TYPE_P(TREE_TYPE(length_tree))) - length_tree = convert_to_integer(TREE_TYPE(count_field), length_tree); - - tree bad_index = Expression::check_bounds(length_tree, - TREE_TYPE(count_field), - NULL_TREE, location); - - length_tree = fold_convert_loc(location, TREE_TYPE(count_field), length_tree); - tree capacity_tree; - if (args->size() == 1) - capacity_tree = length_tree; - else - { - capacity_tree = args->back()->get_tree(context); - if (capacity_tree == error_mark_node) - return error_mark_node; - if (!DECL_P(capacity_tree)) - capacity_tree = save_expr(capacity_tree); - if (!INTEGRAL_TYPE_P(TREE_TYPE(capacity_tree))) - capacity_tree = convert_to_integer(TREE_TYPE(count_field), - capacity_tree); - - bad_index = Expression::check_bounds(capacity_tree, - TREE_TYPE(count_field), - bad_index, location); - - tree chktype = (((TYPE_SIZE(TREE_TYPE(capacity_tree)) - > TYPE_SIZE(TREE_TYPE(length_tree))) - || ((TYPE_SIZE(TREE_TYPE(capacity_tree)) - == TYPE_SIZE(TREE_TYPE(length_tree))) - && TYPE_UNSIGNED(TREE_TYPE(capacity_tree)))) - ? TREE_TYPE(capacity_tree) - : TREE_TYPE(length_tree)); - tree chk = fold_build2_loc(location, LT_EXPR, boolean_type_node, - fold_convert_loc(location, chktype, - capacity_tree), - fold_convert_loc(location, chktype, - length_tree)); - if (bad_index == NULL_TREE) - bad_index = chk; - else - bad_index = fold_build2_loc(location, TRUTH_OR_EXPR, boolean_type_node, - bad_index, chk); - - capacity_tree = fold_convert_loc(location, TREE_TYPE(count_field), - capacity_tree); - } - - tree size_tree = fold_build2_loc(location, MULT_EXPR, sizetype, - element_size_tree, - fold_convert_loc(location, sizetype, - capacity_tree)); - - tree chk = fold_build2_loc(location, TRUTH_AND_EXPR, boolean_type_node, - fold_build2_loc(location, GT_EXPR, - boolean_type_node, - fold_convert_loc(location, - sizetype, - capacity_tree), - size_zero_node), - fold_build2_loc(location, LT_EXPR, - boolean_type_node, - size_tree, element_size_tree)); - if (bad_index == NULL_TREE) - bad_index = chk; - else - bad_index = fold_build2_loc(location, TRUTH_OR_EXPR, boolean_type_node, - bad_index, chk); - - tree space = context->gogo()->allocate_memory(this->element_type_, - size_tree, location); - - if (value != NULL_TREE) - space = save_expr(space); - - space = fold_convert(TREE_TYPE(values_field), space); - - if (bad_index != NULL_TREE && bad_index != boolean_false_node) - { - tree crash = Gogo::runtime_error(RUNTIME_ERROR_MAKE_SLICE_OUT_OF_BOUNDS, - location); - space = build2(COMPOUND_EXPR, TREE_TYPE(space), - build3(COND_EXPR, void_type_node, - bad_index, crash, NULL_TREE), - space); - } - - tree constructor = gogo->slice_constructor(type_tree, space, length_tree, - capacity_tree); - - if (value == NULL_TREE) - { - // The array contents are zero initialized. - return constructor; - } - - // The elements must be initialized. - - tree max = fold_build2_loc(location, MINUS_EXPR, TREE_TYPE(count_field), - capacity_tree, - fold_convert_loc(location, TREE_TYPE(count_field), - integer_one_node)); - - tree array_type = build_array_type(element_type_tree, - build_index_type(max)); - - tree value_pointer = fold_convert_loc(location, - build_pointer_type(array_type), - space); + return this->element_type_->get_backend(gogo); +} - tree range = build2(RANGE_EXPR, sizetype, size_zero_node, max); - tree space_init = build_constructor_single(array_type, range, value); +// Return the backend representation of the length. - return build2(COMPOUND_EXPR, TREE_TYPE(constructor), - build2(MODIFY_EXPR, void_type_node, - build_fold_indirect_ref(value_pointer), - space_init), - constructor); +Bexpression* +Array_type::get_backend_length(Gogo* gogo) +{ + return tree_to_expr(this->get_length_tree(gogo)); } // Return a tree for a pointer to the values in ARRAY. @@ -4771,7 +4430,7 @@ Array_type::value_pointer_tree(Gogo*, tree array) const { // Open array. tree field = TYPE_FIELDS(TREE_TYPE(array)); - gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), + go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__values") == 0); ret = fold_build3(COMPONENT_REF, TREE_TYPE(field), array, field, NULL_TREE); @@ -4799,10 +4458,10 @@ Array_type::length_tree(Gogo* gogo, tree array) // This is an open array. We need to read the length field. tree type = TREE_TYPE(array); - gcc_assert(TREE_CODE(type) == RECORD_TYPE); + go_assert(TREE_CODE(type) == RECORD_TYPE); tree field = DECL_CHAIN(TYPE_FIELDS(type)); - gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0); + go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__count") == 0); tree ret = build3(COMPONENT_REF, TREE_TYPE(field), array, field, NULL_TREE); if (TREE_CONSTANT(array)) @@ -4822,10 +4481,10 @@ Array_type::capacity_tree(Gogo* gogo, tree array) // This is an open array. We need to read the capacity field. tree type = TREE_TYPE(array); - gcc_assert(TREE_CODE(type) == RECORD_TYPE); + go_assert(TREE_CODE(type) == RECORD_TYPE); tree field = DECL_CHAIN(DECL_CHAIN(TYPE_FIELDS(type))); - gcc_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0); + go_assert(strcmp(IDENTIFIER_POINTER(DECL_NAME(field)), "__capacity") == 0); return build3(COMPONENT_REF, TREE_TYPE(field), array, field, NULL_TREE); } @@ -4872,9 +4531,10 @@ Array_type::make_array_type_descriptor_type() Type* uintptr_type = Type::lookup_integer_type("uintptr"); Struct_type* sf = - Type::make_builtin_struct_type(3, + Type::make_builtin_struct_type(4, "", tdt, "elem", ptdt, + "slice", ptdt, "len", uintptr_type); ret = Type::make_builtin_named_type("ArrayType", sf); @@ -4921,7 +4581,7 @@ Array_type::do_type_descriptor(Gogo* gogo, Named_type* name) Expression* Array_type::array_type_descriptor(Gogo* gogo, Named_type* name) { - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); Type* atdt = Array_type::make_array_type_descriptor_type(); @@ -4931,21 +4591,26 @@ Array_type::array_type_descriptor(Gogo* gogo, Named_type* name) vals->reserve(3); Struct_field_list::const_iterator p = fields->begin(); - gcc_assert(p->field_name() == "commonType"); + go_assert(p->is_field_name("commonType")); vals->push_back(this->type_descriptor_constructor(gogo, RUNTIME_TYPE_KIND_ARRAY, name, NULL, true)); ++p; - gcc_assert(p->field_name() == "elem"); + go_assert(p->is_field_name("elem")); vals->push_back(Expression::make_type_descriptor(this->element_type_, bloc)); ++p; - gcc_assert(p->field_name() == "len"); + go_assert(p->is_field_name("slice")); + Type* slice_type = Type::make_array_type(this->element_type_, NULL); + vals->push_back(Expression::make_type_descriptor(slice_type, bloc)); + + ++p; + go_assert(p->is_field_name("len")); vals->push_back(Expression::make_cast(p->type(), this->length_, bloc)); ++p; - gcc_assert(p == fields->end()); + go_assert(p == fields->end()); return Expression::make_struct_composite_literal(atdt, vals, bloc); } @@ -4955,7 +4620,7 @@ Array_type::array_type_descriptor(Gogo* gogo, Named_type* name) Expression* Array_type::slice_type_descriptor(Gogo* gogo, Named_type* name) { - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); Type* stdt = Array_type::make_slice_type_descriptor_type(); @@ -4965,17 +4630,17 @@ Array_type::slice_type_descriptor(Gogo* gogo, Named_type* name) vals->reserve(2); Struct_field_list::const_iterator p = fields->begin(); - gcc_assert(p->field_name() == "commonType"); + go_assert(p->is_field_name("commonType")); vals->push_back(this->type_descriptor_constructor(gogo, RUNTIME_TYPE_KIND_SLICE, name, NULL, true)); ++p; - gcc_assert(p->field_name() == "elem"); + go_assert(p->is_field_name("elem")); vals->push_back(Expression::make_type_descriptor(this->element_type_, bloc)); ++p; - gcc_assert(p == fields->end()); + go_assert(p == fields->end()); return Expression::make_struct_composite_literal(stdt, vals, bloc); } @@ -5097,148 +4762,46 @@ Map_type::do_hash_for_method(Gogo* gogo) const + 2); } -// Check that a call to the builtin make function is valid. For a map -// the optional argument is the number of spaces to preallocate for -// values. +// Get the backend representation for a map type. A map type is +// represented as a pointer to a struct. The struct is __go_map in +// libgo/map.h. -bool -Map_type::do_check_make_expression(Expression_list* args, - source_location location) +Btype* +Map_type::do_get_backend(Gogo* gogo) { - if (args != NULL && !args->empty()) + static Btype* backend_map_type; + if (backend_map_type == NULL) { - if (!Type::check_int_value(args->front(), _("bad size when making map"), - location)) - return false; - else if (args->size() > 1) - { - error_at(location, "too many arguments when making map"); - return false; - } - } - return true; -} + std::vector bfields(4); -// Get a tree for a map type. A map type is represented as a pointer -// to a struct. The struct is __go_map in libgo/map.h. - -tree -Map_type::do_get_tree(Gogo* gogo) -{ - static tree type_tree; - if (type_tree == NULL_TREE) - { - tree struct_type = make_node(RECORD_TYPE); + Location bloc = Linemap::predeclared_location(); - tree map_descriptor_type = gogo->map_descriptor_type(); - tree const_map_descriptor_type = - build_qualified_type(map_descriptor_type, TYPE_QUAL_CONST); - tree name = get_identifier("__descriptor"); - tree field = build_decl(BUILTINS_LOCATION, FIELD_DECL, name, - build_pointer_type(const_map_descriptor_type)); - DECL_CONTEXT(field) = struct_type; - TYPE_FIELDS(struct_type) = field; - tree last_field = field; + Type* pdt = Type::make_type_descriptor_ptr_type(); + bfields[0].name = "__descriptor"; + bfields[0].btype = pdt->get_backend(gogo); + bfields[0].location = bloc; - name = get_identifier("__element_count"); - field = build_decl(BUILTINS_LOCATION, FIELD_DECL, name, sizetype); - DECL_CONTEXT(field) = struct_type; - DECL_CHAIN(last_field) = field; - last_field = field; - - name = get_identifier("__bucket_count"); - field = build_decl(BUILTINS_LOCATION, FIELD_DECL, name, sizetype); - DECL_CONTEXT(field) = struct_type; - DECL_CHAIN(last_field) = field; - last_field = field; - - name = get_identifier("__buckets"); - field = build_decl(BUILTINS_LOCATION, FIELD_DECL, name, - build_pointer_type(ptr_type_node)); - DECL_CONTEXT(field) = struct_type; - DECL_CHAIN(last_field) = field; - - layout_type(struct_type); - - // Give the struct a name for better debugging info. - name = get_identifier("__go_map"); - tree type_decl = build_decl(BUILTINS_LOCATION, TYPE_DECL, name, - struct_type); - DECL_ARTIFICIAL(type_decl) = 1; - TYPE_NAME(struct_type) = type_decl; - go_preserve_from_gc(type_decl); - rest_of_decl_compilation(type_decl, 1, 0); - - type_tree = build_pointer_type(struct_type); - go_preserve_from_gc(type_tree); - } - - return type_tree; -} - -// Initialize a map. - -tree -Map_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear) -{ - if (is_clear) - return NULL; - return fold_convert(type_tree, null_pointer_node); -} - -// Return an expression for a newly allocated map. + Type* uintptr_type = Type::lookup_integer_type("uintptr"); + bfields[1].name = "__element_count"; + bfields[1].btype = uintptr_type->get_backend(gogo); + bfields[1].location = bloc; -tree -Map_type::do_make_expression_tree(Translate_context* context, - Expression_list* args, - source_location location) -{ - tree bad_index = NULL_TREE; + bfields[2].name = "__bucket_count"; + bfields[2].btype = bfields[1].btype; + bfields[2].location = bloc; - tree expr_tree; - if (args == NULL || args->empty()) - expr_tree = size_zero_node; - else - { - expr_tree = args->front()->get_tree(context); - if (expr_tree == error_mark_node) - return error_mark_node; - if (!DECL_P(expr_tree)) - expr_tree = save_expr(expr_tree); - if (!INTEGRAL_TYPE_P(TREE_TYPE(expr_tree))) - expr_tree = convert_to_integer(sizetype, expr_tree); - bad_index = Expression::check_bounds(expr_tree, sizetype, bad_index, - location); - } - - tree map_type = this->get_tree(context->gogo()); - - static tree new_map_fndecl; - tree ret = Gogo::call_builtin(&new_map_fndecl, - location, - "__go_new_map", - 2, - map_type, - TREE_TYPE(TYPE_FIELDS(TREE_TYPE(map_type))), - context->gogo()->map_descriptor(this), - sizetype, - expr_tree); - if (ret == error_mark_node) - return error_mark_node; - // This can panic if the capacity is out of range. - TREE_NOTHROW(new_map_fndecl) = 0; + Btype* bvt = gogo->backend()->void_type(); + Btype* bpvt = gogo->backend()->pointer_type(bvt); + Btype* bppvt = gogo->backend()->pointer_type(bpvt); + bfields[3].name = "__buckets"; + bfields[3].btype = bppvt; + bfields[3].location = bloc; - if (bad_index == NULL_TREE) - return ret; - else - { - tree crash = Gogo::runtime_error(RUNTIME_ERROR_MAKE_MAP_OUT_OF_BOUNDS, - location); - return build2(COMPOUND_EXPR, TREE_TYPE(ret), - build3(COND_EXPR, void_type_node, - bad_index, crash, NULL_TREE), - ret); + Btype *bt = gogo->backend()->struct_type(bfields); + bt = gogo->backend()->named_type("__go_map", bt, bloc); + backend_map_type = gogo->backend()->pointer_type(bt); } + return backend_map_type; } // The type of a map type descriptor. @@ -5269,7 +4832,7 @@ Map_type::make_map_type_descriptor_type() Expression* Map_type::do_type_descriptor(Gogo* gogo, Named_type* name) { - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); Type* mtdt = Map_type::make_map_type_descriptor_type(); @@ -5279,25 +4842,148 @@ Map_type::do_type_descriptor(Gogo* gogo, Named_type* name) vals->reserve(3); Struct_field_list::const_iterator p = fields->begin(); - gcc_assert(p->field_name() == "commonType"); + go_assert(p->is_field_name("commonType")); vals->push_back(this->type_descriptor_constructor(gogo, RUNTIME_TYPE_KIND_MAP, name, NULL, true)); ++p; - gcc_assert(p->field_name() == "key"); + go_assert(p->is_field_name("key")); vals->push_back(Expression::make_type_descriptor(this->key_type_, bloc)); ++p; - gcc_assert(p->field_name() == "elem"); + go_assert(p->is_field_name("elem")); vals->push_back(Expression::make_type_descriptor(this->val_type_, bloc)); ++p; - gcc_assert(p == fields->end()); + go_assert(p == fields->end()); return Expression::make_struct_composite_literal(mtdt, vals, bloc); } +// A mapping from map types to map descriptors. + +Map_type::Map_descriptors Map_type::map_descriptors; + +// Build a map descriptor for this type. Return a pointer to it. + +tree +Map_type::map_descriptor_pointer(Gogo* gogo, Location location) +{ + Bvariable* bvar = this->map_descriptor(gogo); + tree var_tree = var_to_tree(bvar); + if (var_tree == error_mark_node) + return error_mark_node; + return build_fold_addr_expr_loc(location.gcc_location(), var_tree); +} + +// Build a map descriptor for this type. + +Bvariable* +Map_type::map_descriptor(Gogo* gogo) +{ + std::pair val(this, NULL); + std::pair ins = + Map_type::map_descriptors.insert(val); + if (!ins.second) + return ins.first->second; + + Type* key_type = this->key_type_; + Type* val_type = this->val_type_; + + // The map entry type is a struct with three fields. Build that + // struct so that we can get the offsets of the key and value within + // a map entry. The first field should technically be a pointer to + // this type itself, but since we only care about field offsets we + // just use pointer to bool. + Type* pbool = Type::make_pointer_type(Type::make_boolean_type()); + Struct_type* map_entry_type = + Type::make_builtin_struct_type(3, + "__next", pbool, + "__key", key_type, + "__val", val_type); + + Type* map_descriptor_type = Map_type::make_map_descriptor_type(); + + const Struct_field_list* fields = + map_descriptor_type->struct_type()->fields(); + + Expression_list* vals = new Expression_list(); + vals->reserve(4); + + Location bloc = Linemap::predeclared_location(); + + Struct_field_list::const_iterator p = fields->begin(); + + go_assert(p->is_field_name("__map_descriptor")); + vals->push_back(Expression::make_type_descriptor(this, bloc)); + + ++p; + go_assert(p->is_field_name("__entry_size")); + Expression::Type_info type_info = Expression::TYPE_INFO_SIZE; + vals->push_back(Expression::make_type_info(map_entry_type, type_info)); + + Struct_field_list::const_iterator pf = map_entry_type->fields()->begin(); + ++pf; + go_assert(pf->is_field_name("__key")); + + ++p; + go_assert(p->is_field_name("__key_offset")); + vals->push_back(Expression::make_struct_field_offset(map_entry_type, &*pf)); + + ++pf; + go_assert(pf->is_field_name("__val")); + + ++p; + go_assert(p->is_field_name("__val_offset")); + vals->push_back(Expression::make_struct_field_offset(map_entry_type, &*pf)); + + ++p; + go_assert(p == fields->end()); + + Expression* initializer = + Expression::make_struct_composite_literal(map_descriptor_type, vals, bloc); + + std::string mangled_name = "__go_map_" + this->mangled_name(gogo); + Btype* map_descriptor_btype = map_descriptor_type->get_backend(gogo); + Bvariable* bvar = gogo->backend()->immutable_struct(mangled_name, true, + map_descriptor_btype, + bloc); + + Translate_context context(gogo, NULL, NULL, NULL); + context.set_is_const(); + Bexpression* binitializer = tree_to_expr(initializer->get_tree(&context)); + + gogo->backend()->immutable_struct_set_init(bvar, mangled_name, true, + map_descriptor_btype, bloc, + binitializer); + + ins.first->second = bvar; + return bvar; +} + +// Build the type of a map descriptor. This must match the struct +// __go_map_descriptor in libgo/runtime/map.h. + +Type* +Map_type::make_map_descriptor_type() +{ + static Type* ret; + if (ret == NULL) + { + Type* ptdt = Type::make_type_descriptor_ptr_type(); + Type* uintptr_type = Type::lookup_integer_type("uintptr"); + Struct_type* sf = + Type::make_builtin_struct_type(4, + "__map_descriptor", ptdt, + "__entry_size", uintptr_type, + "__key_offset", uintptr_type, + "__val_offset", uintptr_type); + ret = Type::make_builtin_named_type("__go_map_descriptor", sf); + } + return ret; +} + // Reflection string for a map. void @@ -5346,7 +5032,7 @@ Map_type::do_import(Import* imp) // Make a map type. Map_type* -Type::make_map_type(Type* key_type, Type* val_type, source_location location) +Type::make_map_type(Type* key_type, Type* val_type, Location location) { return new Map_type(key_type, val_type, location); } @@ -5358,139 +5044,46 @@ Type::make_map_type(Type* key_type, Type* val_type, source_location location) unsigned int Channel_type::do_hash_for_method(Gogo* gogo) const { - unsigned int ret = 0; - if (this->may_send_) - ret += 1; - if (this->may_receive_) - ret += 2; - if (this->element_type_ != NULL) - ret += this->element_type_->hash_for_method(gogo) << 2; - return ret << 3; -} - -// Whether this type is the same as T. - -bool -Channel_type::is_identical(const Channel_type* t, - bool errors_are_identical) const -{ - if (!Type::are_identical(this->element_type(), t->element_type(), - errors_are_identical, NULL)) - return false; - return (this->may_send_ == t->may_send_ - && this->may_receive_ == t->may_receive_); -} - -// Check whether the parameters for a call to the builtin function -// make are OK for a channel. A channel can take an optional single -// parameter which is the buffer size. - -bool -Channel_type::do_check_make_expression(Expression_list* args, - source_location location) -{ - if (args != NULL && !args->empty()) - { - if (!Type::check_int_value(args->front(), - _("bad buffer size when making channel"), - location)) - return false; - else if (args->size() > 1) - { - error_at(location, "too many arguments when making channel"); - return false; - } - } - return true; -} - -// Return the tree for a channel type. A channel is a pointer to a -// __go_channel struct. The __go_channel struct is defined in -// libgo/runtime/channel.h. - -tree -Channel_type::do_get_tree(Gogo*) -{ - static tree type_tree; - if (type_tree == NULL_TREE) - { - tree ret = make_node(RECORD_TYPE); - TYPE_NAME(ret) = get_identifier("__go_channel"); - TYPE_STUB_DECL(ret) = build_decl(BUILTINS_LOCATION, TYPE_DECL, NULL_TREE, - ret); - type_tree = build_pointer_type(ret); - go_preserve_from_gc(type_tree); - } - return type_tree; + unsigned int ret = 0; + if (this->may_send_) + ret += 1; + if (this->may_receive_) + ret += 2; + if (this->element_type_ != NULL) + ret += this->element_type_->hash_for_method(gogo) << 2; + return ret << 3; } -// Initialize a channel variable. +// Whether this type is the same as T. -tree -Channel_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear) +bool +Channel_type::is_identical(const Channel_type* t, + bool errors_are_identical) const { - if (is_clear) - return NULL; - return fold_convert(type_tree, null_pointer_node); + if (!Type::are_identical(this->element_type(), t->element_type(), + errors_are_identical, NULL)) + return false; + return (this->may_send_ == t->may_send_ + && this->may_receive_ == t->may_receive_); } -// Handle the builtin function make for a channel. +// Return the tree for a channel type. A channel is a pointer to a +// __go_channel struct. The __go_channel struct is defined in +// libgo/runtime/channel.h. -tree -Channel_type::do_make_expression_tree(Translate_context* context, - Expression_list* args, - source_location location) +Btype* +Channel_type::do_get_backend(Gogo* gogo) { - Gogo* gogo = context->gogo(); - tree channel_type = this->get_tree(gogo); - - tree element_tree = this->element_type_->get_tree(gogo); - tree element_size_tree = size_in_bytes(element_tree); - - tree bad_index = NULL_TREE; - - tree expr_tree; - if (args == NULL || args->empty()) - expr_tree = size_zero_node; - else - { - expr_tree = args->front()->get_tree(context); - if (expr_tree == error_mark_node) - return error_mark_node; - if (!DECL_P(expr_tree)) - expr_tree = save_expr(expr_tree); - if (!INTEGRAL_TYPE_P(TREE_TYPE(expr_tree))) - expr_tree = convert_to_integer(sizetype, expr_tree); - bad_index = Expression::check_bounds(expr_tree, sizetype, bad_index, - location); - } - - static tree new_channel_fndecl; - tree ret = Gogo::call_builtin(&new_channel_fndecl, - location, - "__go_new_channel", - 2, - channel_type, - sizetype, - element_size_tree, - sizetype, - expr_tree); - if (ret == error_mark_node) - return error_mark_node; - // This can panic if the capacity is out of range. - TREE_NOTHROW(new_channel_fndecl) = 0; - - if (bad_index == NULL_TREE) - return ret; - else + static Btype* backend_channel_type; + if (backend_channel_type == NULL) { - tree crash = Gogo::runtime_error(RUNTIME_ERROR_MAKE_CHAN_OUT_OF_BOUNDS, - location); - return build2(COMPOUND_EXPR, TREE_TYPE(ret), - build3(COND_EXPR, void_type_node, - bad_index, crash, NULL_TREE), - ret); + std::vector bfields; + Btype* bt = gogo->backend()->struct_type(bfields); + bt = gogo->backend()->named_type("__go_channel", bt, + Linemap::predeclared_location()); + backend_channel_type = gogo->backend()->pointer_type(bt); } + return backend_channel_type; } // Build a type descriptor for a channel type. @@ -5523,7 +5116,7 @@ Channel_type::make_chan_type_descriptor_type() Expression* Channel_type::do_type_descriptor(Gogo* gogo, Named_type* name) { - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); Type* ctdt = Channel_type::make_chan_type_descriptor_type(); @@ -5533,17 +5126,17 @@ Channel_type::do_type_descriptor(Gogo* gogo, Named_type* name) vals->reserve(3); Struct_field_list::const_iterator p = fields->begin(); - gcc_assert(p->field_name() == "commonType"); + go_assert(p->is_field_name("commonType")); vals->push_back(this->type_descriptor_constructor(gogo, RUNTIME_TYPE_KIND_CHAN, name, NULL, true)); ++p; - gcc_assert(p->field_name() == "elem"); + go_assert(p->is_field_name("elem")); vals->push_back(Expression::make_type_descriptor(this->element_type_, bloc)); ++p; - gcc_assert(p->field_name() == "dir"); + go_assert(p->is_field_name("dir")); // These bits must match the ones in libgo/runtime/go-type.h. int val = 0; if (this->may_receive_) @@ -5556,7 +5149,7 @@ Channel_type::do_type_descriptor(Gogo* gogo, Named_type* name) mpz_clear(iv); ++p; - gcc_assert(p == fields->end()); + go_assert(p == fields->end()); return Expression::make_struct_composite_literal(ctdt, vals, bloc); } @@ -5806,14 +5399,14 @@ Interface_type::find_method(const std::string& name) const size_t Interface_type::method_index(const std::string& name) const { - gcc_assert(this->methods_ != NULL); + go_assert(this->methods_ != NULL); size_t ret = 0; for (Typed_identifier_list::const_iterator p = this->methods_->begin(); p != this->methods_->end(); ++p, ++ret) if (p->name() == name) return ret; - gcc_unreachable(); + go_unreachable(); } // Return whether NAME is an unexported method, for better error @@ -6029,7 +5622,7 @@ Interface_type::implements_interface(const Type* t, std::string* reason) const Function_type *p_fn_type = p->type()->function_type(); Function_type* m_fn_type = m->type()->function_type(); - gcc_assert(p_fn_type != NULL && m_fn_type != NULL); + go_assert(p_fn_type != NULL && m_fn_type != NULL); std::string subreason; if (!p_fn_type->is_identical(m_fn_type, true, true, &subreason)) { @@ -6071,128 +5664,97 @@ Interface_type::implements_interface(const Type* t, std::string* reason) const return true; } -// Return a tree for an interface type. An interface is a pointer to -// a struct. The struct has three fields. The first field is a -// pointer to the type descriptor for the dynamic type of the object. -// The second field is a pointer to a table of methods for the -// interface to be used with the object. The third field is the value -// of the object itself. +// Return the backend representation of the empty interface type. We +// use the same struct for all empty interfaces. -tree -Interface_type::do_get_tree(Gogo* gogo) +Btype* +Interface_type::get_backend_empty_interface_type(Gogo* gogo) { - if (this->methods_ == NULL) + static Btype* empty_interface_type; + if (empty_interface_type == NULL) { - // At the tree level, use the same type for all empty - // interfaces. This lets us assign them to each other directly - // without triggering GIMPLE type errors. - tree dtype = Type::make_type_descriptor_type()->get_tree(gogo); - dtype = build_pointer_type(build_qualified_type(dtype, TYPE_QUAL_CONST)); - static tree empty_interface; - return Gogo::builtin_struct(&empty_interface, "__go_empty_interface", - NULL_TREE, 2, - "__type_descriptor", - dtype, - "__object", - ptr_type_node); - } - - return this->fill_in_tree(gogo, make_node(RECORD_TYPE)); -} - -// Fill in the tree for an interface type. This is used for named -// interface types. - -tree -Interface_type::fill_in_tree(Gogo* gogo, tree type) -{ - gcc_assert(this->methods_ != NULL); + std::vector bfields(2); - // Because the methods may refer to the interface type itself, we - // need to build the interface type first, and then update the - // method pointer later. + Location bloc = Linemap::predeclared_location(); - tree field_trees = NULL_TREE; - tree* pp = &field_trees; + Type* pdt = Type::make_type_descriptor_ptr_type(); + bfields[0].name = "__type_descriptor"; + bfields[0].btype = pdt->get_backend(gogo); + bfields[0].location = bloc; - tree name_tree = get_identifier("__methods"); - tree methods_field = build_decl(this->location_, FIELD_DECL, name_tree, - ptr_type_node); - DECL_CONTEXT(methods_field) = type; - *pp = methods_field; - pp = &DECL_CHAIN(methods_field); + Type* vt = Type::make_pointer_type(Type::make_void_type()); + bfields[1].name = "__object"; + bfields[1].btype = vt->get_backend(gogo); + bfields[1].location = bloc; - name_tree = get_identifier("__object"); - tree field = build_decl(this->location_, FIELD_DECL, name_tree, - ptr_type_node); - DECL_CONTEXT(field) = type; - *pp = field; - - TYPE_FIELDS(type) = field_trees; + empty_interface_type = gogo->backend()->struct_type(bfields); + } + return empty_interface_type; +} - layout_type(type); +// Return the fields of a non-empty interface type. This is not +// declared in types.h so that types.h doesn't have to #include +// backend.h. - // Build the type of the table of methods. +static void +get_backend_interface_fields(Gogo* gogo, Interface_type* type, + std::vector* bfields) +{ + Location loc = type->location(); - tree method_table = make_node(RECORD_TYPE); + std::vector mfields(type->methods()->size() + 1); - // The first field is a pointer to the type descriptor. - name_tree = get_identifier("__type_descriptor"); - tree dtype = Type::make_type_descriptor_type()->get_tree(gogo); - dtype = build_pointer_type(build_qualified_type(dtype, TYPE_QUAL_CONST)); - field = build_decl(this->location_, FIELD_DECL, name_tree, dtype); - DECL_CONTEXT(field) = method_table; - TYPE_FIELDS(method_table) = field; + Type* pdt = Type::make_type_descriptor_ptr_type(); + mfields[0].name = "__type_descriptor"; + mfields[0].btype = pdt->get_backend(gogo); + mfields[0].location = loc; std::string last_name = ""; - pp = &DECL_CHAIN(field); - for (Typed_identifier_list::const_iterator p = this->methods_->begin(); - p != this->methods_->end(); - ++p) - { - std::string name = Gogo::unpack_hidden_name(p->name()); - name_tree = get_identifier_with_length(name.data(), name.length()); - tree field_type = p->type()->get_tree(gogo); - if (field_type == error_mark_node) - return error_mark_node; - field = build_decl(this->location_, FIELD_DECL, name_tree, field_type); - DECL_CONTEXT(field) = method_table; - *pp = field; - pp = &DECL_CHAIN(field); + size_t i = 1; + for (Typed_identifier_list::const_iterator p = type->methods()->begin(); + p != type->methods()->end(); + ++p, ++i) + { + mfields[i].name = Gogo::unpack_hidden_name(p->name()); + mfields[i].btype = p->type()->get_backend(gogo); + mfields[i].location = loc; // Sanity check: the names should be sorted. - gcc_assert(p->name() > last_name); + go_assert(p->name() > last_name); last_name = p->name(); } - layout_type(method_table); - // Update the type of the __methods field from a generic pointer to - // a pointer to the method table. - TREE_TYPE(methods_field) = build_pointer_type(method_table); + Btype* methods = gogo->backend()->struct_type(mfields); - return type; + bfields->resize(2); + + (*bfields)[0].name = "__methods"; + (*bfields)[0].btype = gogo->backend()->pointer_type(methods); + (*bfields)[0].location = loc; + + Type* vt = Type::make_pointer_type(Type::make_void_type()); + (*bfields)[1].name = "__object"; + (*bfields)[1].btype = vt->get_backend(gogo); + (*bfields)[1].location = Linemap::predeclared_location(); } -// Initialization value. +// Return a tree for an interface type. An interface is a pointer to +// a struct. The struct has three fields. The first field is a +// pointer to the type descriptor for the dynamic type of the object. +// The second field is a pointer to a table of methods for the +// interface to be used with the object. The third field is the value +// of the object itself. -tree -Interface_type::do_get_init_tree(Gogo*, tree type_tree, bool is_clear) +Btype* +Interface_type::do_get_backend(Gogo* gogo) { - if (is_clear) - return NULL; - - VEC(constructor_elt,gc)* init = VEC_alloc(constructor_elt, gc, 2); - for (tree field = TYPE_FIELDS(type_tree); - field != NULL_TREE; - field = DECL_CHAIN(field)) + if (this->methods_ == NULL) + return Interface_type::get_backend_empty_interface_type(gogo); + else { - constructor_elt* elt = VEC_quick_push(constructor_elt, init, NULL); - elt->index = field; - elt->value = fold_convert(TREE_TYPE(field), null_pointer_node); + std::vector bfields; + get_backend_interface_fields(gogo, this, &bfields); + return gogo->backend()->struct_type(bfields); } - - tree ret = build_constructor(type_tree, init); - TREE_CONSTANT(ret) = 1; - return ret; } // The type of an interface type descriptor. @@ -6234,7 +5796,7 @@ Interface_type::make_interface_type_descriptor_type() Expression* Interface_type::do_type_descriptor(Gogo* gogo, Named_type* name) { - source_location bloc = BUILTINS_LOCATION; + Location bloc = Linemap::predeclared_location(); Type* itdt = Interface_type::make_interface_type_descriptor_type(); @@ -6244,13 +5806,13 @@ Interface_type::do_type_descriptor(Gogo* gogo, Named_type* name) ivals->reserve(2); Struct_field_list::const_iterator pif = ifields->begin(); - gcc_assert(pif->field_name() == "commonType"); - ivals->push_back(this->type_descriptor_constructor(gogo, - RUNTIME_TYPE_KIND_INTERFACE, - name, NULL, true)); + go_assert(pif->is_field_name("commonType")); + const int rt = RUNTIME_TYPE_KIND_INTERFACE; + ivals->push_back(this->type_descriptor_constructor(gogo, rt, name, NULL, + true)); ++pif; - gcc_assert(pif->field_name() == "methods"); + go_assert(pif->is_field_name("methods")); Expression_list* methods = new Expression_list(); if (this->methods_ != NULL && !this->methods_->empty()) @@ -6268,13 +5830,13 @@ Interface_type::do_type_descriptor(Gogo* gogo, Named_type* name) mvals->reserve(3); Struct_field_list::const_iterator pmf = mfields->begin(); - gcc_assert(pmf->field_name() == "name"); + go_assert(pmf->is_field_name("name")); std::string s = Gogo::unpack_hidden_name(pm->name()); Expression* e = Expression::make_string(s, bloc); mvals->push_back(Expression::make_unary(OPERATOR_AND, e, bloc)); ++pmf; - gcc_assert(pmf->field_name() == "pkgPath"); + go_assert(pmf->is_field_name("pkgPath")); if (!Gogo::is_hidden_name(pm->name())) mvals->push_back(Expression::make_nil(bloc)); else @@ -6285,11 +5847,11 @@ Interface_type::do_type_descriptor(Gogo* gogo, Named_type* name) } ++pmf; - gcc_assert(pmf->field_name() == "typ"); + go_assert(pmf->is_field_name("typ")); mvals->push_back(Expression::make_type_descriptor(pm->type(), bloc)); ++pmf; - gcc_assert(pmf == mfields->end()); + go_assert(pmf == mfields->end()); e = Expression::make_struct_composite_literal(elemtype, mvals, bloc); @@ -6301,7 +5863,7 @@ Interface_type::do_type_descriptor(Gogo* gogo, Named_type* name) methods, bloc)); ++pif; - gcc_assert(pif == ifields->end()); + go_assert(pif == ifields->end()); return Expression::make_struct_composite_literal(itdt, ivals, bloc); } @@ -6314,21 +5876,31 @@ Interface_type::do_reflection(Gogo* gogo, std::string* ret) const ret->append("interface {"); if (this->methods_ != NULL) { + ret->push_back(' '); for (Typed_identifier_list::const_iterator p = this->methods_->begin(); p != this->methods_->end(); ++p) { if (p != this->methods_->begin()) - ret->append(";"); - ret->push_back(' '); - ret->append(Gogo::unpack_hidden_name(p->name())); + ret->append("; "); + if (!Gogo::is_hidden_name(p->name())) + ret->append(p->name()); + else + { + // This matches what the gc compiler does. + std::string prefix = Gogo::hidden_name_prefix(p->name()); + ret->append(prefix.substr(prefix.find('.') + 1)); + ret->push_back('.'); + ret->append(Gogo::unpack_hidden_name(p->name())); + } std::string sub = p->type()->reflection(gogo); - gcc_assert(sub.compare(0, 4, "func") == 0); + go_assert(sub.compare(0, 4, "func") == 0); sub = sub.substr(4); ret->append(sub); } + ret->push_back(' '); } - ret->append(" }"); + ret->append("}"); } // Mangled name. @@ -6471,7 +6043,7 @@ Interface_type::do_import(Import* imp) ptype, imp->location())); if (imp->peek_char() != ',') break; - gcc_assert(!is_varargs); + go_assert(!is_varargs); imp->require_c_string(", "); } } @@ -6531,7 +6103,7 @@ Interface_type::do_import(Import* imp) Interface_type* Type::make_interface_type(Typed_identifier_list* methods, - source_location location) + Location location) { return new Interface_type(methods, location); } @@ -6541,7 +6113,7 @@ Type::make_interface_type(Typed_identifier_list* methods, // Bind a method to an object. Expression* -Method::bind_method(Expression* expr, source_location location) const +Method::bind_method(Expression* expr, Location location) const { if (this->stub_ == NULL) { @@ -6549,10 +6121,7 @@ Method::bind_method(Expression* expr, source_location location) const // the child class. return this->do_bind_method(expr, location); } - - Expression* func = Expression::make_func_reference(this->stub_, NULL, - location); - return Expression::make_bound_method(expr, func, location); + return Expression::make_bound_method(expr, this->stub_, location); } // Return the named object associated with a method. This may only be @@ -6578,12 +6147,12 @@ Named_method::do_type() const else if (this->named_object_->is_function_declaration()) return this->named_object_->func_declaration_value()->type(); else - gcc_unreachable(); + go_unreachable(); } // Return the location of the method receiver. -source_location +Location Named_method::do_receiver_location() const { return this->do_type()->receiver()->location(); @@ -6592,11 +6161,10 @@ Named_method::do_receiver_location() const // Bind a method to an object. Expression* -Named_method::do_bind_method(Expression* expr, source_location location) const +Named_method::do_bind_method(Expression* expr, Location location) const { - Expression* func = Expression::make_func_reference(this->named_object_, NULL, - location); - Bound_method_expression* bme = Expression::make_bound_method(expr, func, + Named_object* no = this->named_object_; + Bound_method_expression* bme = Expression::make_bound_method(expr, no, location); // If this is not a local method, and it does not use a stub, then // the real method expects a different type. We need to cast the @@ -6604,7 +6172,7 @@ Named_method::do_bind_method(Expression* expr, source_location location) const if (this->depth() > 0 && !this->needs_stub_method()) { Function_type* ftype = this->do_type(); - gcc_assert(ftype->is_method()); + go_assert(ftype->is_method()); Type* frtype = ftype->receiver()->type(); bme->set_first_argument_type(frtype); } @@ -6617,7 +6185,7 @@ Named_method::do_bind_method(Expression* expr, source_location location) const Expression* Interface_method::do_bind_method(Expression* expr, - source_location location) const + Location location) const { return Expression::make_interface_field_reference(expr, this->name_, location); @@ -6691,22 +6259,22 @@ Named_type::message_name() const Type* Named_type::named_base() { - if (this->seen_ > 0) + if (this->seen_) return this; - ++this->seen_; + this->seen_ = true; Type* ret = this->type_->base(); - --this->seen_; + this->seen_ = false; return ret; } const Type* Named_type::named_base() const { - if (this->seen_ > 0) + if (this->seen_) return this; - ++this->seen_; + this->seen_ = true; const Type* ret = this->type_->base(); - --this->seen_; + this->seen_ = false; return ret; } @@ -6716,11 +6284,11 @@ Named_type::named_base() const bool Named_type::is_named_error_type() const { - if (this->seen_ > 0) + if (this->seen_) return false; - ++this->seen_; + this->seen_ = true; bool ret = this->type_->is_error_type(); - --this->seen_; + this->seen_ = false; return ret; } @@ -6739,7 +6307,7 @@ Named_type::add_method(const std::string& name, Function* function) Named_object* Named_type::add_method_declaration(const std::string& name, Package* package, Function_type* type, - source_location location) + Location location) { if (this->local_methods_ == NULL) this->local_methods_ = new Bindings(NULL); @@ -6837,7 +6405,7 @@ tree Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface, bool is_pointer) { - gcc_assert(!interface->is_empty()); + go_assert(!interface->is_empty()); Interface_method_tables** pimt = (is_pointer ? &this->interface_method_tables_ @@ -6852,7 +6420,7 @@ Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface, if (ins.second) { // This is a new entry in the hash table. - gcc_assert(ins.first->second == NULL_TREE); + go_assert(ins.first->second == NULL_TREE); ins.first->second = gogo->interface_method_table_for_type(interface, this, is_pointer); @@ -6861,7 +6429,7 @@ Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface, tree decl = ins.first->second; if (decl == error_mark_node) return error_mark_node; - gcc_assert(decl != NULL_TREE && TREE_CODE(decl) == VAR_DECL); + go_assert(decl != NULL_TREE && TREE_CODE(decl) == VAR_DECL); return build_fold_addr_expr(decl); } @@ -6870,11 +6438,11 @@ Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface, bool Named_type::named_type_has_hidden_fields(std::string* reason) const { - if (this->seen_ > 0) + if (this->seen_) return false; - ++this->seen_; + this->seen_ = true; bool ret = this->type_->has_hidden_fields(this, reason); - --this->seen_; + this->seen_ = false; return ret; } @@ -6884,7 +6452,7 @@ Named_type::named_type_has_hidden_fields(std::string* reason) const class Find_type_use : public Traverse { public: - Find_type_use(Type* find_type) + Find_type_use(Named_type* find_type) : Traverse(traverse_types), find_type_(find_type), found_(false) { } @@ -6900,7 +6468,7 @@ class Find_type_use : public Traverse private: // The type we are looking for. - Type* find_type_; + Named_type* find_type_; // Whether we found the type. bool found_; }; @@ -6910,16 +6478,17 @@ class Find_type_use : public Traverse int Find_type_use::type(Type* type) { - if (this->find_type_ == type) + if (type->named_type() != NULL && this->find_type_ == type->named_type()) { this->found_ = true; return TRAVERSE_EXIT; } + // It's OK if we see a reference to the type in any type which is // essentially a pointer: a pointer, a slice, a function, a map, or // a channel. if (type->points_to() != NULL - || type->is_open_array_type() + || type->is_slice_type() || type->function_type() != NULL || type->map_type() != NULL || type->channel_type() != NULL) @@ -6948,6 +6517,42 @@ Find_type_use::type(Type* type) return TRAVERSE_SKIP_COMPONENTS; } + // Otherwise, FIND_TYPE_ depends on TYPE, in the sense that we need + // to convert TYPE to the backend representation before we convert + // FIND_TYPE_. + if (type->named_type() != NULL) + { + switch (type->base()->classification()) + { + case Type::TYPE_ERROR: + case Type::TYPE_BOOLEAN: + case Type::TYPE_INTEGER: + case Type::TYPE_FLOAT: + case Type::TYPE_COMPLEX: + case Type::TYPE_STRING: + case Type::TYPE_NIL: + break; + + case Type::TYPE_ARRAY: + case Type::TYPE_STRUCT: + this->find_type_->add_dependency(type->named_type()); + break; + + case Type::TYPE_VOID: + case Type::TYPE_SINK: + case Type::TYPE_FUNCTION: + case Type::TYPE_POINTER: + case Type::TYPE_CALL_MULTIPLE_RESULT: + case Type::TYPE_MAP: + case Type::TYPE_CHANNEL: + case Type::TYPE_INTERFACE: + case Type::TYPE_NAMED: + case Type::TYPE_FORWARD: + default: + go_unreachable(); + } + } + return TRAVERSE_CONTINUE; } @@ -6973,9 +6578,8 @@ Named_type::do_verify() if (this->local_methods_ != NULL) { Struct_type* st = this->type_->struct_type(); - Interface_type* it = this->type_->interface_type(); bool found_dup = false; - if (st != NULL || it != NULL) + if (st != NULL) { for (Bindings::const_declarations_iterator p = this->local_methods_->begin_declarations(); @@ -6990,49 +6594,12 @@ Named_type::do_verify() Gogo::message_name(name).c_str()); found_dup = true; } - if (it != NULL && it->find_method(name) != NULL) - { - error_at(p->second->location(), - "method %qs redeclares interface method name", - Gogo::message_name(name).c_str()); - found_dup = true; - } } } if (found_dup) return false; } - // If this is a struct, then if any of the fields of the struct - // themselves have struct type, or array of struct type, then this - // struct must be converted to the backend representation before the - // field's type is converted. That may seem backward, but it works - // because if the field's type refers to this one, e.g., via a - // pointer, then the conversion process will pick up the half-built - // struct and do the right thing. - if (this->struct_type() != NULL) - { - const Struct_field_list* fields = this->struct_type()->fields(); - for (Struct_field_list::const_iterator p = fields->begin(); - p != fields->end(); - ++p) - { - Struct_type* st = p->type()->struct_type(); - if (st != NULL) - st->add_prerequisite(this); - else - { - Array_type* at = p->type()->array_type(); - if (at != NULL && !at->is_open_array_type()) - { - st = at->element_type()->struct_type(); - if (st != NULL) - st->add_prerequisite(this); - } - } - } - } - return true; } @@ -7041,11 +6608,11 @@ Named_type::do_verify() bool Named_type::do_has_pointer() const { - if (this->seen_ > 0) + if (this->seen_) return false; - ++this->seen_; + this->seen_ = true; bool ret = this->type_->has_pointer(); - --this->seen_; + this->seen_ = false; return ret; } @@ -7082,22 +6649,32 @@ Named_type::do_hash_for_method(Gogo* gogo) const return ret; } -// Get a tree for a named type. +// Convert a named type to the backend representation. In order to +// get dependencies right, we fill in a dummy structure for this type, +// then convert all the dependencies, then complete this type. When +// this function is complete, the size of the type is known. -tree -Named_type::do_get_tree(Gogo* gogo) +void +Named_type::convert(Gogo* gogo) { - if (this->is_error_) - return error_mark_node; + if (this->is_error_ || this->is_converted_) + return; - // Go permits types to refer to themselves in various ways. Break - // the recursion here. - tree t; - switch (this->type_->forwarded()->classification()) - { - case TYPE_ERROR: - return error_mark_node; + this->create_placeholder(gogo); + + // Convert all the dependencies. If they refer indirectly back to + // this type, they will pick up the intermediate tree we just + // created. + for (std::vector::const_iterator p = this->dependencies_.begin(); + p != this->dependencies_.end(); + ++p) + (*p)->convert(gogo); + // Complete this type. + Btype* bt = this->named_btype_; + Type* base = this->type_->base(); + switch (base->classification()) + { case TYPE_VOID: case TYPE_BOOLEAN: case TYPE_INTEGER: @@ -7105,163 +6682,278 @@ Named_type::do_get_tree(Gogo* gogo) case TYPE_COMPLEX: case TYPE_STRING: case TYPE_NIL: - // These types can not refer to themselves. + break; + case TYPE_MAP: case TYPE_CHANNEL: - // All maps and channels have the same type in GENERIC. - t = Type::get_named_type_tree(gogo, this->type_); - if (t == error_mark_node) - return error_mark_node; - // Build a copy to set TYPE_NAME. - t = build_variant_type_copy(t); break; case TYPE_FUNCTION: - // GENERIC can't handle a pointer to a function type whose - // return type is a pointer to the function type itself. It - // goes into an infinite loop when walking the types. - if (this->seen_ > 0) + case TYPE_POINTER: + // The size of these types is already correct. We don't worry + // about filling them in until later, when we also track + // circular references. + break; + + case TYPE_STRUCT: + { + std::vector bfields; + get_backend_struct_fields(gogo, base->struct_type()->fields(), + &bfields); + if (!gogo->backend()->set_placeholder_struct_type(bt, bfields)) + bt = gogo->backend()->error_type(); + } + break; + + case TYPE_ARRAY: + // Slice types were completed in create_placeholder. + if (!base->is_slice_type()) { - Function_type* fntype = this->type_->function_type(); - if (fntype->results() != NULL - && fntype->results()->size() == 1 - && fntype->results()->front().type()->forwarded() == this) - return ptr_type_node; - - // We can legitimately see ourselves here twice when a named - // type is defined using a struct which refers to the named - // type. If we see ourselves too often we are in a loop. - if (this->seen_ > 3) - return ptr_type_node; + Btype* bet = base->array_type()->get_backend_element(gogo); + Bexpression* blen = base->array_type()->get_backend_length(gogo); + if (!gogo->backend()->set_placeholder_array_type(bt, bet, blen)) + bt = gogo->backend()->error_type(); } - ++this->seen_; - t = Type::get_named_type_tree(gogo, this->type_); - --this->seen_; - if (t == error_mark_node) - return error_mark_node; - t = build_variant_type_copy(t); break; - case TYPE_POINTER: - // Don't recur infinitely if a pointer type refers to itself. - // Ideally we would build a circular data structure here, but - // GENERIC can't handle them. - if (this->seen_ > 0) - { - if (this->type_->points_to()->forwarded() == this) - return ptr_type_node; + case TYPE_INTERFACE: + // Interface types were completed in create_placeholder. + break; - if (this->seen_ > 3) - return ptr_type_node; - } - ++this->seen_; - t = Type::get_named_type_tree(gogo, this->type_); - --this->seen_; - if (t == error_mark_node) - return error_mark_node; - t = build_variant_type_copy(t); + case TYPE_ERROR: + return; + + default: + case TYPE_SINK: + case TYPE_CALL_MULTIPLE_RESULT: + case TYPE_NAMED: + case TYPE_FORWARD: + go_unreachable(); + } + + this->named_btype_ = bt; + this->is_converted_ = true; +} + +// Create the placeholder for a named type. This is the first step in +// converting to the backend representation. + +void +Named_type::create_placeholder(Gogo* gogo) +{ + if (this->is_error_) + this->named_btype_ = gogo->backend()->error_type(); + + if (this->named_btype_ != NULL) + return; + + // Create the structure for this type. Note that because we call + // base() here, we don't attempt to represent a named type defined + // as another named type. Instead both named types will point to + // different base representations. + Type* base = this->type_->base(); + Btype* bt; + bool set_name = true; + switch (base->classification()) + { + case TYPE_ERROR: + this->is_error_ = true; + this->named_btype_ = gogo->backend()->error_type(); + return; + + case TYPE_VOID: + case TYPE_BOOLEAN: + case TYPE_INTEGER: + case TYPE_FLOAT: + case TYPE_COMPLEX: + case TYPE_STRING: + case TYPE_NIL: + // These are simple basic types, we can just create them + // directly. + bt = Type::get_named_base_btype(gogo, base); break; - case TYPE_STRUCT: - // If there are structs which must be converted first, do them. - if (this->seen_ == 0) - { - ++this->seen_; - this->type_->struct_type()->convert_prerequisites(gogo); - --this->seen_; - } + case TYPE_MAP: + case TYPE_CHANNEL: + // All maps and channels have the same backend representation. + bt = Type::get_named_base_btype(gogo, base); + break; - if (this->named_tree_ != NULL_TREE) - return this->named_tree_; + case TYPE_FUNCTION: + case TYPE_POINTER: + { + bool for_function = base->classification() == TYPE_FUNCTION; + bt = gogo->backend()->placeholder_pointer_type(this->name(), + this->location_, + for_function); + set_name = false; + } + break; - t = make_node(RECORD_TYPE); - this->named_tree_ = t; - t = this->type_->struct_type()->fill_in_tree(gogo, t); - if (t == error_mark_node) - { - this->named_tree_ = error_mark_node; - return error_mark_node; - } + case TYPE_STRUCT: + bt = gogo->backend()->placeholder_struct_type(this->name(), + this->location_); + set_name = false; break; case TYPE_ARRAY: - if (this->named_tree_ != NULL_TREE) - return this->named_tree_; - if (!this->is_open_array_type()) - { - t = make_node(ARRAY_TYPE); - this->named_tree_ = t; - t = this->type_->array_type()->fill_in_array_tree(gogo, t); - } + if (base->is_slice_type()) + bt = gogo->backend()->placeholder_struct_type(this->name(), + this->location_); else - { - t = gogo->slice_type_tree(void_type_node); - this->named_tree_ = t; - t = this->type_->array_type()->fill_in_slice_tree(gogo, t); - } - if (t == error_mark_node) - return error_mark_node; - t = build_variant_type_copy(t); + bt = gogo->backend()->placeholder_array_type(this->name(), + this->location_); + set_name = false; break; case TYPE_INTERFACE: - if (this->type_->interface_type()->is_empty()) - { - t = Type::get_named_type_tree(gogo, this->type_); - if (t == error_mark_node) - return error_mark_node; - t = build_variant_type_copy(t); - } + if (base->interface_type()->is_empty()) + bt = Interface_type::get_backend_empty_interface_type(gogo); else { - if (this->named_tree_ != NULL_TREE) - return this->named_tree_; - t = make_node(RECORD_TYPE); - this->named_tree_ = t; - t = this->type_->interface_type()->fill_in_tree(gogo, t); - if (t == error_mark_node) - { - this->named_tree_ = error_mark_node; - return error_mark_node; - } + bt = gogo->backend()->placeholder_struct_type(this->name(), + this->location_); + set_name = false; } break; + default: + case TYPE_SINK: + case TYPE_CALL_MULTIPLE_RESULT: case TYPE_NAMED: - { - // When a named type T1 is defined as another named type T2, - // the definition must simply be "type T1 T2". If the - // definition of T2 may refer to T1, then we must simply - // return the type for T2 here. It's not precisely correct, - // but it's as close as we can get with GENERIC. - ++this->seen_; - t = Type::get_named_type_tree(gogo, this->type_); - --this->seen_; - if (this->seen_ > 0) - return t; - if (t == error_mark_node) - return error_mark_node; - t = build_variant_type_copy(t); - } - break; - case TYPE_FORWARD: - // An undefined forwarding type. Make sure the error is - // emitted. - this->type_->forward_declaration_type()->real_type(); - return error_mark_node; + go_unreachable(); + } + + if (set_name) + bt = gogo->backend()->named_type(this->name(), bt, this->location_); + + this->named_btype_ = bt; + + if (base->is_slice_type()) + { + // We do not record slices as dependencies of other types, + // because we can fill them in completely here with the final + // size. + std::vector bfields; + get_backend_slice_fields(gogo, base->array_type(), &bfields); + if (!gogo->backend()->set_placeholder_struct_type(bt, bfields)) + this->named_btype_ = gogo->backend()->error_type(); + } + else if (base->interface_type() != NULL + && !base->interface_type()->is_empty()) + { + // We do not record interfaces as dependencies of other types, + // because we can fill them in completely here with the final + // size. + std::vector bfields; + get_backend_interface_fields(gogo, base->interface_type(), &bfields); + if (!gogo->backend()->set_placeholder_struct_type(bt, bfields)) + this->named_btype_ = gogo->backend()->error_type(); + } +} + +// Get a tree for a named type. + +Btype* +Named_type::do_get_backend(Gogo* gogo) +{ + if (this->is_error_) + return gogo->backend()->error_type(); + + Btype* bt = this->named_btype_; + + if (!gogo->named_types_are_converted()) + { + // We have not completed converting named types. NAMED_BTYPE_ + // is a placeholder and we shouldn't do anything further. + if (bt != NULL) + return bt; + + // We don't build dependencies for types whose sizes do not + // change or are not relevant, so we may see them here while + // converting types. + this->create_placeholder(gogo); + bt = this->named_btype_; + go_assert(bt != NULL); + return bt; + } + + // We are not converting types. This should only be called if the + // type has already been converted. + if (!this->is_converted_) + { + go_assert(saw_errors()); + return gogo->backend()->error_type(); + } + + go_assert(bt != NULL); + + // Complete the tree. + Type* base = this->type_->base(); + Btype* bt1; + switch (base->classification()) + { + case TYPE_ERROR: + return gogo->backend()->error_type(); + + case TYPE_VOID: + case TYPE_BOOLEAN: + case TYPE_INTEGER: + case TYPE_FLOAT: + case TYPE_COMPLEX: + case TYPE_STRING: + case TYPE_NIL: + case TYPE_MAP: + case TYPE_CHANNEL: + case TYPE_STRUCT: + case TYPE_ARRAY: + case TYPE_INTERFACE: + return bt; + + case TYPE_FUNCTION: + // Don't build a circular data structure. GENERIC can't handle + // it. + if (this->seen_in_get_backend_) + { + this->is_circular_ = true; + return gogo->backend()->circular_pointer_type(bt, true); + } + this->seen_in_get_backend_ = true; + bt1 = Type::get_named_base_btype(gogo, base); + this->seen_in_get_backend_ = false; + if (this->is_circular_) + bt1 = gogo->backend()->circular_pointer_type(bt, true); + if (!gogo->backend()->set_placeholder_function_type(bt, bt1)) + bt = gogo->backend()->error_type(); + return bt; + + case TYPE_POINTER: + // Don't build a circular data structure. GENERIC can't handle + // it. + if (this->seen_in_get_backend_) + { + this->is_circular_ = true; + return gogo->backend()->circular_pointer_type(bt, false); + } + this->seen_in_get_backend_ = true; + bt1 = Type::get_named_base_btype(gogo, base); + this->seen_in_get_backend_ = false; + if (this->is_circular_) + bt1 = gogo->backend()->circular_pointer_type(bt, false); + if (!gogo->backend()->set_placeholder_pointer_type(bt, bt1)) + bt = gogo->backend()->error_type(); + return bt; default: case TYPE_SINK: case TYPE_CALL_MULTIPLE_RESULT: - gcc_unreachable(); + case TYPE_NAMED: + case TYPE_FORWARD: + go_unreachable(); } - tree id = this->named_object_->get_id(gogo); - tree decl = build_decl(this->location_, TYPE_DECL, id, t); - TYPE_NAME(t) = decl; - - return t; + go_unreachable(); } // Build a type descriptor for a named type. @@ -7283,7 +6975,7 @@ Named_type::do_type_descriptor(Gogo* gogo, Named_type* name) void Named_type::do_reflection(Gogo* gogo, std::string* ret) const { - if (this->location() != BUILTINS_LOCATION) + if (!Linemap::is_predeclared_location(this->location())) { const Package* package = this->named_object_->package(); if (package != NULL) @@ -7307,8 +6999,8 @@ Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const { Named_object* no = this->named_object_; std::string name; - if (this->location() == BUILTINS_LOCATION) - gcc_assert(this->in_function_ == NULL); + if (Linemap::is_predeclared_location(this->location())) + go_assert(this->in_function_ == NULL); else { const std::string& unique_prefix(no->package() == NULL @@ -7354,7 +7046,7 @@ Named_type::import_named_type(Import* imp, Named_type** ptype) imp->require_c_string("type "); Type *type = imp->read_type(); *ptype = type->named_type(); - gcc_assert(*ptype != NULL); + go_assert(*ptype != NULL); imp->require_c_string(";\n"); } @@ -7397,7 +7089,7 @@ Named_type::do_export(Export* exp) const Named_type* Type::make_named_type(Named_object* named_object, Type* type, - source_location location) + Location location) { return new Named_type(named_object, type, location); } @@ -7407,7 +7099,7 @@ Type::make_named_type(Named_object* named_object, Type* type, // all required stubs. void -Type::finalize_methods(Gogo* gogo, const Type* type, source_location location, +Type::finalize_methods(Gogo* gogo, const Type* type, Location location, Methods** all_methods) { *all_methods = NULL; @@ -7589,7 +7281,7 @@ Type::add_interface_methods_for_type(const Type* type, // when we look at the methods for IT. continue; } - gcc_assert(!fntype->is_method()); + go_assert(!fntype->is_method()); fntype = fntype->copy_with_receiver(const_cast(type)); Method* m = new Interface_method(pm->name(), pm->location(), fntype, field_indexes, depth); @@ -7607,7 +7299,7 @@ Type::add_interface_methods_for_type(const Type* type, void Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods, - source_location location) + Location location) { if (methods == NULL) return; @@ -7633,7 +7325,7 @@ Type::build_stub_methods(Gogo* gogo, const Type* type, const Methods* methods, Type* receiver_type = const_cast(type); if (!m->is_value_method()) receiver_type = Type::make_pointer_type(receiver_type); - source_location receiver_location = m->receiver_location(); + Location receiver_location = m->receiver_location(); Typed_identifier* receiver = new Typed_identifier(buf, receiver_type, receiver_location); @@ -7713,10 +7405,10 @@ Type::build_one_stub_method(Gogo* gogo, Method* method, const char* receiver_name, const Typed_identifier_list* params, bool is_varargs, - source_location location) + Location location) { Named_object* receiver_object = gogo->lookup(receiver_name, NULL); - gcc_assert(receiver_object != NULL); + go_assert(receiver_object != NULL); Expression* expr = Expression::make_var_reference(receiver_object, location); expr = Type::apply_field_indexes(expr, method->field_indexes(), location); @@ -7734,7 +7426,7 @@ Type::build_one_stub_method(Gogo* gogo, Method* method, ++p) { Named_object* param = gogo->lookup(p->name(), NULL); - gcc_assert(param != NULL); + go_assert(param != NULL); Expression* param_ref = Expression::make_var_reference(param, location); arguments->push_back(param_ref); @@ -7742,12 +7434,13 @@ Type::build_one_stub_method(Gogo* gogo, Method* method, } Expression* func = method->bind_method(expr, location); - gcc_assert(func != NULL); + go_assert(func != NULL); Call_expression* call = Expression::make_call(func, arguments, is_varargs, location); + call->set_hidden_fields_are_ok(); size_t count = call->result_count(); if (count == 0) - gogo->add_statement(Statement::make_statement(call)); + gogo->add_statement(Statement::make_statement(call, true)); else { Expression_list* retvals = new Expression_list(); @@ -7758,10 +7451,13 @@ Type::build_one_stub_method(Gogo* gogo, Method* method, for (size_t i = 0; i < count; ++i) retvals->push_back(Expression::make_call_result(call, i)); } - const Function* function = gogo->current_function()->func_value(); - const Typed_identifier_list* results = function->type()->results(); - Statement* retstat = Statement::make_return_statement(results, retvals, - location); + Return_statement* retstat = Statement::make_return_statement(retvals, + location); + + // We can return values with hidden fields from a stub. This is + // necessary if the method is itself hidden. + retstat->set_hidden_fields_are_ok(); + gogo->add_statement(retstat); } } @@ -7772,19 +7468,19 @@ Type::build_one_stub_method(Gogo* gogo, Method* method, Expression* Type::apply_field_indexes(Expression* expr, const Method::Field_indexes* field_indexes, - source_location location) + Location location) { if (field_indexes == NULL) return expr; expr = Type::apply_field_indexes(expr, field_indexes->next, location); Struct_type* stype = expr->type()->deref()->struct_type(); - gcc_assert(stype != NULL + go_assert(stype != NULL && field_indexes->field_index < stype->field_count()); if (expr->type()->struct_type() == NULL) { - gcc_assert(expr->type()->points_to() != NULL); + go_assert(expr->type()->points_to() != NULL); expr = Expression::make_unary(OPERATOR_MULT, expr, location); - gcc_assert(expr->type()->struct_type() == stype); + go_assert(expr->type()->struct_type() == stype); } return Expression::make_field_reference(expr, field_indexes->field_index, location); @@ -7801,7 +7497,7 @@ Type::method_expects_pointer(const Named_object* no) else if (no->is_function_declaration()) fntype = no->func_declaration_value()->type(); else - gcc_unreachable(); + go_unreachable(); return fntype->receiver()->type()->points_to() != NULL; } @@ -7838,16 +7534,14 @@ Type::method_function(const Methods* methods, const std::string& name, Expression* Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr, const std::string& name, - source_location location) + Location location) { if (type->deref()->is_error_type()) return Expression::make_error(location); - const Named_type* nt = type->named_type(); - if (nt == NULL) - nt = type->deref()->named_type(); + const Named_type* nt = type->deref()->named_type(); const Struct_type* st = type->deref()->struct_type(); - const Interface_type* it = type->deref()->interface_type(); + const Interface_type* it = type->interface_type(); // If this is a pointer to a pointer, then it is possible that the // pointed-to type has methods. @@ -7863,7 +7557,6 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr, return Expression::make_error(location); nt = type->points_to()->named_type(); st = type->points_to()->struct_type(); - it = type->points_to()->interface_type(); } bool receiver_can_be_pointer = (expr->type()->points_to() != NULL @@ -7880,13 +7573,13 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr, Expression* ret; if (!is_method) { - gcc_assert(st != NULL); + go_assert(st != NULL); if (type->struct_type() == NULL) { - gcc_assert(type->points_to() != NULL); + go_assert(type->points_to() != NULL); expr = Expression::make_unary(OPERATOR_MULT, expr, location); - gcc_assert(expr->type()->struct_type() == st); + go_assert(expr->type()->struct_type() == st); } ret = st->field_reference(expr, name, location); } @@ -7901,22 +7594,21 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr, else if (st != NULL) m = st->method_function(name, NULL); else - gcc_unreachable(); - gcc_assert(m != NULL); + go_unreachable(); + go_assert(m != NULL); if (!m->is_value_method() && expr->type()->points_to() == NULL) expr = Expression::make_unary(OPERATOR_AND, expr, location); ret = m->bind_method(expr, location); } - gcc_assert(ret != NULL); + go_assert(ret != NULL); return ret; } else { if (!ambig1.empty()) error_at(location, "%qs is ambiguous via %qs and %qs", - Gogo::message_name(name).c_str(), - Gogo::message_name(ambig1).c_str(), - Gogo::message_name(ambig2).c_str()); + Gogo::message_name(name).c_str(), ambig1.c_str(), + ambig2.c_str()); else if (found_pointer_method) error_at(location, "method requires a pointer"); else if (nt == NULL && st == NULL && it == NULL) @@ -8016,7 +7708,7 @@ Type::find_field_or_method(const Type* type, } // Interface types can have methods. - const Interface_type* it = type->deref()->interface_type(); + const Interface_type* it = type->interface_type(); if (it != NULL && it->find_method(name) != NULL) { *is_method = true; @@ -8044,7 +7736,7 @@ Type::find_field_or_method(const Type* type, pf != fields->end(); ++pf) { - if (pf->field_name() == name) + if (pf->is_field_name(name)) { *is_method = false; if (nt != NULL) @@ -8062,7 +7754,7 @@ Type::find_field_or_method(const Type* type, Named_type* fnt = pf->type()->named_type(); if (fnt == NULL) fnt = pf->type()->deref()->named_type(); - gcc_assert(fnt != NULL); + go_assert(fnt != NULL); int sublevel = level == NULL ? 1 : *level + 1; bool sub_is_method; @@ -8087,8 +7779,10 @@ Type::find_field_or_method(const Type* type, // pass the ambiguity back to the caller. if (found_level == 0 || sublevel <= found_level) { - found_ambig1 = pf->field_name() + '.' + subambig1; - found_ambig2 = pf->field_name() + '.' + subambig2; + found_ambig1 = (Gogo::message_name(pf->field_name()) + + '.' + subambig1); + found_ambig2 = (Gogo::message_name(pf->field_name()) + + '.' + subambig2); found_level = sublevel; } } @@ -8111,9 +7805,9 @@ Type::find_field_or_method(const Type* type, else if (found_ambig1.empty()) { // We found an ambiguity. - gcc_assert(found_parent != NULL); - found_ambig1 = found_parent->field_name(); - found_ambig2 = pf->field_name(); + go_assert(found_parent != NULL); + found_ambig1 = Gogo::message_name(found_parent->field_name()); + found_ambig2 = Gogo::message_name(pf->field_name()); } else { @@ -8135,7 +7829,7 @@ Type::find_field_or_method(const Type* type, return false; else if (!found_ambig1.empty()) { - gcc_assert(!found_ambig1.empty()); + go_assert(!found_ambig1.empty()); ambig1->assign(found_ambig1); ambig2->assign(found_ambig2); if (level != NULL) @@ -8178,12 +7872,12 @@ Type::is_unexported_field_or_method(Gogo* gogo, const Type* type, } } - type = type->deref(); - const Interface_type* it = type->interface_type(); if (it != NULL && it->is_unexported_method(gogo, name)) return true; + type = type->deref(); + const Struct_type* st = type->struct_type(); if (st != NULL && st->is_unexported_local_field(gogo, name)) return true; @@ -8235,7 +7929,7 @@ Forward_declaration_type::Forward_declaration_type(Named_object* named_object) : Type(TYPE_FORWARD), named_object_(named_object->resolve()), warned_(false) { - gcc_assert(this->named_object_->is_unknown() + go_assert(this->named_object_->is_unknown() || this->named_object_->is_type_declaration()); } @@ -8354,7 +8048,7 @@ Forward_declaration_type::add_method(const std::string& name, Named_object* Forward_declaration_type::add_method_declaration(const std::string& name, Function_type* type, - source_location location) + Location location) { Named_object* no = this->named_object(); if (no->is_unknown()) @@ -8374,27 +8068,24 @@ Forward_declaration_type::do_traverse(Traverse* traverse) return TRAVERSE_CONTINUE; } -// Get a tree for the type. +// Get the backend representation for the type. -tree -Forward_declaration_type::do_get_tree(Gogo* gogo) +Btype* +Forward_declaration_type::do_get_backend(Gogo* gogo) { if (this->is_defined()) - return Type::get_named_type_tree(gogo, this->real_type()); + return Type::get_named_base_btype(gogo, this->real_type()); if (this->warned_) - return error_mark_node; + return gogo->backend()->error_type(); // We represent an undefined type as a struct with no fields. That - // should work fine for the middle-end, since the same case can - // arise in C. - Named_object* no = this->named_object(); - tree type_tree = make_node(RECORD_TYPE); - tree id = no->get_id(gogo); - tree decl = build_decl(no->location(), TYPE_DECL, id, type_tree); - TYPE_NAME(type_tree) = decl; - layout_type(type_tree); - return type_tree; + // should work fine for the backend, since the same case can arise + // in C. + std::vector fields; + Btype* bt = gogo->backend()->struct_type(fields); + return gogo->backend()->named_type(this->name(), bt, + this->named_object()->location()); } // Build a type descriptor for a forwarded type. @@ -8402,15 +8093,16 @@ Forward_declaration_type::do_get_tree(Gogo* gogo) Expression* Forward_declaration_type::do_type_descriptor(Gogo* gogo, Named_type* name) { + Location ploc = Linemap::predeclared_location(); if (!this->is_defined()) - return Expression::make_nil(BUILTINS_LOCATION); + return Expression::make_nil(ploc); else { Type* t = this->real_type(); if (name != NULL) return this->named_type_descriptor(gogo, t, name); else - return Expression::make_type_descriptor(t, BUILTINS_LOCATION); + return Expression::make_type_descriptor(t, ploc); } } @@ -8455,7 +8147,7 @@ void Forward_declaration_type::do_export(Export*) const { // If there is a base type, that should be exported instead of this. - gcc_assert(!this->is_defined()); + go_assert(!this->is_defined()); // We don't output anything. }