diff options
author | Cary Coutant <ccoutant@google.com> | 2012-03-09 11:50:43 -0800 |
---|---|---|
committer | Cary Coutant <ccoutant@google.com> | 2012-03-09 11:50:43 -0800 |
commit | 4ed2fc3a6bbaaf1f2ea4d1c077dc7fa0867cd005 (patch) | |
tree | 7774dcb772ccc005c2fd8f8831dc45b90a8f6060 /gcc/go/gofrontend | |
parent | 2400d467a903f32c96df9f9fcb0de7be8a655afa (diff) | |
parent | f9c681635d1850543f547fdbb6efd5a010aca015 (diff) | |
download | gcc-4ed2fc3a6bbaaf1f2ea4d1c077dc7fa0867cd005.tar.gz |
Merge branch 'master' into google-debugfission
Diffstat (limited to 'gcc/go/gofrontend')
-rw-r--r-- | gcc/go/gofrontend/export.cc | 57 | ||||
-rw-r--r-- | gcc/go/gofrontend/export.h | 10 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.cc | 137 | ||||
-rw-r--r-- | gcc/go/gofrontend/expressions.h | 4 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo-tree.cc | 4 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.cc | 43 | ||||
-rw-r--r-- | gcc/go/gofrontend/gogo.h | 5 | ||||
-rw-r--r-- | gcc/go/gofrontend/import.cc | 40 | ||||
-rw-r--r-- | gcc/go/gofrontend/import.h | 13 | ||||
-rw-r--r-- | gcc/go/gofrontend/parse.cc | 7 | ||||
-rw-r--r-- | gcc/go/gofrontend/statements.cc | 4 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.cc | 129 | ||||
-rw-r--r-- | gcc/go/gofrontend/types.h | 3 | ||||
-rw-r--r-- | gcc/go/gofrontend/unsafe.cc | 56 |
14 files changed, 321 insertions, 191 deletions
diff --git a/gcc/go/gofrontend/export.cc b/gcc/go/gofrontend/export.cc index b6c0740cade..174596753ef 100644 --- a/gcc/go/gofrontend/export.cc +++ b/gcc/go/gofrontend/export.cc @@ -93,6 +93,7 @@ void Export::export_globals(const std::string& package_name, const std::string& unique_prefix, int package_priority, + const std::map<std::string, Package*>& imports, const std::string& import_init_fn, const std::set<Import_init>& imported_init_fns, const Bindings* bindings) @@ -149,6 +150,8 @@ Export::export_globals(const std::string& package_name, snprintf(buf, sizeof buf, "priority %d;\n", package_priority); this->write_c_string(buf); + this->write_imports(imports); + this->write_imported_init_fns(package_name, package_priority, import_init_fn, imported_init_fns); @@ -177,7 +180,46 @@ Export::export_globals(const std::string& package_name, this->stream_->write_checksum(s); } -// Write out the import control variables for this package. +// Sort imported packages. + +static bool +import_compare(const std::pair<std::string, Package*>& a, + const std::pair<std::string, Package*>& b) +{ + return a.first < b.first; +} + +// Write out the imported packages. + +void +Export::write_imports(const std::map<std::string, Package*>& imports) +{ + // Sort the imports for more consistent output. + std::vector<std::pair<std::string, Package*> > imp; + for (std::map<std::string, Package*>::const_iterator p = imports.begin(); + p != imports.end(); + ++p) + imp.push_back(std::make_pair(p->first, p->second)); + + std::sort(imp.begin(), imp.end(), import_compare); + + for (std::vector<std::pair<std::string, Package*> >::const_iterator p = + imp.begin(); + p != imp.end(); + ++p) + { + this->write_c_string("import "); + this->write_string(p->second->name()); + this->write_c_string(" "); + this->write_string(p->second->unique_prefix()); + this->write_c_string(" \""); + this->write_string(p->first); + this->write_c_string("\";\n"); + } +} + +// Write out the initialization functions which need to run for this +// package. void Export::write_imported_init_fns( @@ -189,7 +231,7 @@ Export::write_imported_init_fns( if (import_init_fn.empty() && imported_init_fns.empty()) return; - this->write_c_string("import"); + this->write_c_string("init"); if (!import_init_fn.empty()) { @@ -229,6 +271,17 @@ Export::write_imported_init_fns( this->write_c_string(";\n"); } +// Write a name to the export stream. + +void +Export::write_name(const std::string& name) +{ + if (name.empty()) + this->write_c_string("?"); + else + this->write_string(Gogo::message_name(name)); +} + // Export a type. We have to ensure that on import we create a single // Named_type node for each named type. We do this by keeping a hash // table mapping named types to reference numbers. The first time we diff --git a/gcc/go/gofrontend/export.h b/gcc/go/gofrontend/export.h index 087f477e482..0e03f4853d6 100644 --- a/gcc/go/gofrontend/export.h +++ b/gcc/go/gofrontend/export.h @@ -14,6 +14,7 @@ class Gogo; class Import_init; class Bindings; class Type; +class Package; // Codes used for the builtin types. These are all negative to make // them easily distinct from the codes assigned by Export::write_type. @@ -126,6 +127,7 @@ class Export : public String_dump export_globals(const std::string& package_name, const std::string& unique_prefix, int package_priority, + const std::map<std::string, Package*>& imports, const std::string& import_init_fn, const std::set<Import_init>& imported_init_fns, const Bindings* bindings); @@ -145,6 +147,10 @@ class Export : public String_dump write_bytes(const char* bytes, size_t length) { this->stream_->write_bytes(bytes, length); } + // Write a name to the export stream. If NAME is empty, write "?". + void + write_name(const std::string& name); + // Write out a type. This handles references back to previous // definitions. void @@ -154,6 +160,10 @@ class Export : public String_dump Export(const Export&); Export& operator=(const Export&); + // Write out the imported packages. + void + write_imports(const std::map<std::string, Package*>& imports); + // Write out the imported initialization functions. void write_imported_init_fns(const std::string& package_name, int priority, diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc index 20c49f13b0e..90cf6f32dab 100644 --- a/gcc/go/gofrontend/expressions.cc +++ b/gcc/go/gofrontend/expressions.cc @@ -205,9 +205,6 @@ Expression::convert_for_assignment(Translate_context* context, Type* lhs_type, Type* rhs_type, tree rhs_tree, Location location) { - if (lhs_type == rhs_type) - return rhs_tree; - if (lhs_type->is_error() || rhs_type->is_error()) return error_mark_node; @@ -220,7 +217,7 @@ Expression::convert_for_assignment(Translate_context* context, Type* lhs_type, if (lhs_type_tree == error_mark_node) return error_mark_node; - if (lhs_type->interface_type() != NULL) + if (lhs_type != rhs_type && lhs_type->interface_type() != NULL) { if (rhs_type->interface_type() == NULL) return Expression::convert_type_to_interface(context, lhs_type, @@ -231,7 +228,7 @@ Expression::convert_for_assignment(Translate_context* context, Type* lhs_type, rhs_type, rhs_tree, false, location); } - else if (rhs_type->interface_type() != NULL) + else if (lhs_type != rhs_type && rhs_type->interface_type() != NULL) return Expression::convert_interface_to_type(context, lhs_type, rhs_type, rhs_tree, location); else if (lhs_type->is_slice_type() && rhs_type->is_nil_type()) @@ -284,13 +281,21 @@ Expression::convert_for_assignment(Translate_context* context, Type* lhs_type, || SCALAR_FLOAT_TYPE_P(lhs_type_tree) || COMPLEX_FLOAT_TYPE_P(lhs_type_tree)) return fold_convert_loc(location.gcc_location(), lhs_type_tree, rhs_tree); - else if (TREE_CODE(lhs_type_tree) == RECORD_TYPE - && TREE_CODE(TREE_TYPE(rhs_tree)) == RECORD_TYPE) + else if ((TREE_CODE(lhs_type_tree) == RECORD_TYPE + && TREE_CODE(TREE_TYPE(rhs_tree)) == RECORD_TYPE) + || (TREE_CODE(lhs_type_tree) == ARRAY_TYPE + && TREE_CODE(TREE_TYPE(rhs_tree)) == ARRAY_TYPE)) { + // Avoid confusion from zero sized variables which may be + // represented as non-zero-sized. + if (int_size_in_bytes(lhs_type_tree) == 0 + || int_size_in_bytes(TREE_TYPE(rhs_tree)) == 0) + return rhs_tree; + // This conversion must be permitted by Go, or we wouldn't have // gotten here. go_assert(int_size_in_bytes(lhs_type_tree) - == int_size_in_bytes(TREE_TYPE(rhs_tree))); + == int_size_in_bytes(TREE_TYPE(rhs_tree))); return fold_build1_loc(location.gcc_location(), VIEW_CONVERT_EXPR, lhs_type_tree, rhs_tree); } @@ -3942,10 +3947,6 @@ Unsafe_type_conversion_expression::do_get_tree(Translate_context* context) go_assert(et->map_type() != NULL); else if (t->channel_type() != NULL) go_assert(et->channel_type() != NULL); - else if (t->points_to() != NULL && t->points_to()->channel_type() != NULL) - go_assert((et->points_to() != NULL - && et->points_to()->channel_type() != NULL) - || et->is_nil_type()); else if (t->points_to() != NULL) go_assert(et->points_to() != NULL || et->is_nil_type()); else if (et->is_unsafe_pointer_type()) @@ -4304,14 +4305,23 @@ Unary_expression::eval_integer(Operator op, Type* utype, mpz_t uval, mpz_t val, unsigned HOST_WIDE_INT* phwi = new unsigned HOST_WIDE_INT[count]; memset(phwi, 0, count * sizeof(HOST_WIDE_INT)); + size_t obits = utype->integer_type()->bits(); + + if (!utype->integer_type()->is_unsigned() + && mpz_sgn(uval) < 0) + { + mpz_t adj; + mpz_init_set_ui(adj, 1); + mpz_mul_2exp(adj, adj, obits); + mpz_add(uval, uval, adj); + mpz_clear(adj); + } + size_t ecount; mpz_export(phwi, &ecount, -1, sizeof(HOST_WIDE_INT), 0, 0, uval); go_assert(ecount <= count); // Trim down to the number of words required by the type. - size_t obits = utype->integer_type()->bits(); - if (!utype->integer_type()->is_unsigned()) - ++obits; size_t ocount = ((obits + HOST_BITS_PER_WIDE_INT - 1) / HOST_BITS_PER_WIDE_INT); go_assert(ocount <= count); @@ -4326,6 +4336,16 @@ Unary_expression::eval_integer(Operator op, Type* utype, mpz_t uval, mpz_t val, mpz_import(val, ocount, -1, sizeof(HOST_WIDE_INT), 0, 0, phwi); + if (!utype->integer_type()->is_unsigned() + && mpz_tstbit(val, obits - 1)) + { + mpz_t adj; + mpz_init_set_ui(adj, 1); + mpz_mul_2exp(adj, adj, obits); + mpz_sub(val, val, adj); + mpz_clear(adj); + } + delete[] phwi; } return Integer_expression::check_constant(val, utype, location); @@ -4690,29 +4710,33 @@ Unary_expression::do_get_tree(Translate_context* context) // need to check for nil. We don't bother to check for small // structs because we expect the system to crash on a nil // pointer dereference. - HOST_WIDE_INT s = int_size_in_bytes(TREE_TYPE(TREE_TYPE(expr))); - if (s == -1 || s >= 4096) + tree target_type_tree = TREE_TYPE(TREE_TYPE(expr)); + if (!VOID_TYPE_P(target_type_tree)) { - if (!DECL_P(expr)) - expr = save_expr(expr); - tree compare = fold_build2_loc(loc.gcc_location(), EQ_EXPR, - boolean_type_node, - expr, - fold_convert(TREE_TYPE(expr), - null_pointer_node)); - tree crash = Gogo::runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, - loc); - expr = fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR, - TREE_TYPE(expr), build3(COND_EXPR, - void_type_node, - compare, crash, - NULL_TREE), - expr); + HOST_WIDE_INT s = int_size_in_bytes(target_type_tree); + if (s == -1 || s >= 4096) + { + if (!DECL_P(expr)) + expr = save_expr(expr); + tree compare = fold_build2_loc(loc.gcc_location(), EQ_EXPR, + boolean_type_node, + expr, + fold_convert(TREE_TYPE(expr), + null_pointer_node)); + tree crash = Gogo::runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE, + loc); + expr = fold_build2_loc(loc.gcc_location(), COMPOUND_EXPR, + TREE_TYPE(expr), build3(COND_EXPR, + void_type_node, + compare, crash, + NULL_TREE), + expr); + } } // If the type of EXPR is a recursive pointer type, then we // need to insert a cast before indirecting. - if (TREE_TYPE(TREE_TYPE(expr)) == ptr_type_node) + if (VOID_TYPE_P(target_type_tree)) { Type* pt = this->expr_->type()->points_to(); tree ind = type_to_tree(pt->get_backend(context->gogo())); @@ -5564,6 +5588,7 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, && op != OPERATOR_RSHIFT) { // May be a type error--let it be diagnosed later. + return this; } else if (is_comparison) { @@ -5667,6 +5692,7 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, && op != OPERATOR_RSHIFT) { // May be a type error--let it be diagnosed later. + return this; } else if (is_comparison) { @@ -5750,6 +5776,7 @@ Binary_expression::do_lower(Gogo* gogo, Named_object*, && left_type->base() != right_type->base()) { // May be a type error--let it be diagnosed later. + return this; } else if (op == OPERATOR_EQEQ || op == OPERATOR_NOTEQ) { @@ -8499,6 +8526,7 @@ Builtin_call_expression::do_check_types(Gogo*) case BUILTIN_INVALID: case BUILTIN_NEW: case BUILTIN_MAKE: + case BUILTIN_DELETE: return; case BUILTIN_LEN: @@ -8667,13 +8695,17 @@ Builtin_call_expression::do_check_types(Gogo*) this->report_error(_("too many arguments")); break; } + if (args->front()->type()->is_error() + || args->back()->type()->is_error()) + break; + + Array_type* at = args->front()->type()->array_type(); + Type* e = at->element_type(); // The language permits appending a string to a []byte, as a // special case. if (args->back()->type()->is_string_type()) { - const Array_type* at = args->front()->type()->array_type(); - const Type* e = at->element_type()->forwarded(); if (e->integer_type() != NULL && e->integer_type()->is_byte()) break; } @@ -8682,8 +8714,7 @@ Builtin_call_expression::do_check_types(Gogo*) // assignable to a slice of the element type of the first // argument. We already know the first argument is a slice // type. - Array_type* at = args->front()->type()->array_type(); - Type* arg2_type = Type::make_array_type(at->element_type(), NULL); + Type* arg2_type = Type::make_array_type(e, NULL); std::string reason; if (!Type::are_assignable(arg2_type, args->back()->type(), &reason)) { @@ -8979,7 +9010,10 @@ Builtin_call_expression::do_get_tree(Translate_context* context) fnname = "__go_print_slice"; } else - go_unreachable(); + { + go_assert(saw_errors()); + return error_mark_node; + } tree call = Gogo::call_builtin(pfndecl, location, @@ -9662,8 +9696,11 @@ Call_expression::result_count() const Temporary_statement* Call_expression::result(size_t i) const { - go_assert(this->results_ != NULL - && this->results_->size() > i); + if (this->results_ == NULL || this->results_->size() <= i) + { + go_assert(saw_errors()); + return NULL; + } return (*this->results_)[i]; } @@ -10150,6 +10187,11 @@ Call_expression::set_results(Translate_context* context, tree call_tree) go_assert(field != NULL_TREE); Temporary_statement* temp = this->result(i); + if (temp == NULL) + { + go_assert(saw_errors()); + return error_mark_node; + } Temporary_reference_expression* ref = Expression::make_temporary_reference(temp, loc); ref->set_is_lvalue(); @@ -10329,8 +10371,17 @@ tree Call_result_expression::do_get_tree(Translate_context* context) { Call_expression* ce = this->call_->call_expression(); - go_assert(ce != NULL); + if (ce == NULL) + { + go_assert(this->call_->is_error_expression()); + return error_mark_node; + } Temporary_statement* ts = ce->result(this->index_); + if (ts == NULL) + { + go_assert(saw_errors()); + return error_mark_node; + } Expression* ref = Expression::make_temporary_reference(ts, this->location()); return ref->get_tree(context); } @@ -11780,7 +11831,7 @@ Selector_expression::lower_method_expression(Gogo* gogo) p != method_parameters->end(); ++p, ++i) { - if (!p->name().empty() && p->name() != Import::import_marker) + if (!p->name().empty()) parameters->push_back(*p); else { @@ -13836,7 +13887,7 @@ tree Heap_composite_expression::do_get_tree(Translate_context* context) { tree expr_tree = this->expr_->get_tree(context); - if (expr_tree == error_mark_node) + if (expr_tree == error_mark_node || TREE_TYPE(expr_tree) == error_mark_node) return error_mark_node; tree expr_size = TYPE_SIZE_UNIT(TREE_TYPE(expr_tree)); go_assert(TREE_CODE(expr_size) == INTEGER_CST); diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h index 6672b684e47..0a3f2050dd4 100644 --- a/gcc/go/gofrontend/expressions.h +++ b/gcc/go/gofrontend/expressions.h @@ -1066,6 +1066,10 @@ class Set_and_use_temporary_expression : public Expression { return this->expr_; } protected: + int + do_traverse(Traverse* traverse) + { return Expression::traverse(&this->expr_, traverse); } + Type* do_type(); diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc index 603b97ec0c1..fa229320c96 100644 --- a/gcc/go/gofrontend/gogo-tree.cc +++ b/gcc/go/gofrontend/gogo-tree.cc @@ -843,7 +843,9 @@ Gogo::write_globals() this->backend()->global_variable_set_init(var, tree_to_expr(init)); } - else if (is_sink) + else if (is_sink + || int_size_in_bytes(TREE_TYPE(init)) == 0 + || int_size_in_bytes(TREE_TYPE(vec[i])) == 0) var_init_tree = init; else var_init_tree = fold_build2_loc(no->location().gcc_location(), diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc index a90ce1df384..5fe5aead9c0 100644 --- a/gcc/go/gofrontend/gogo.cc +++ b/gcc/go/gofrontend/gogo.cc @@ -628,7 +628,7 @@ Gogo::start_function(const std::string& name, Function_type* type, Variable* this_param = new Variable(receiver->type(), NULL, false, true, true, location); std::string rname = receiver->name(); - if (rname.empty()) + if (rname.empty() || Gogo::is_sink_name(rname)) { // We need to give receivers a name since they wind up in // DECL_ARGUMENTS. FIXME. @@ -638,8 +638,7 @@ Gogo::start_function(const std::string& name, Function_type* type, ++count; rname = buf; } - if (!Gogo::is_sink_name(rname)) - block->bindings()->add_variable(rname, NULL, this_param); + block->bindings()->add_variable(rname, NULL, this_param); } const Typed_identifier_list* parameters = type->parameters(); @@ -2500,6 +2499,9 @@ Build_recover_thunks::function(Named_object* orig_no) Call_expression* call = Expression::make_call(fn, args, false, location); + // Any varargs call has already been lowered. + call->set_varargs_are_lowered(); + Statement* s; if (orig_fntype->results() == NULL || orig_fntype->results()->empty()) s = Statement::make_statement(call, true); @@ -2859,6 +2861,7 @@ Gogo::do_exports() exp.export_globals(this->package_name(), this->unique_prefix(), this->package_priority(), + this->imports_, (this->need_init_fn_ && !this->is_main_package() ? this->get_init_fn_name() : ""), @@ -3274,7 +3277,10 @@ Function::export_func_with_type(Export* exp, const std::string& name, if (fntype->is_method()) { exp->write_c_string("("); - exp->write_type(fntype->receiver()->type()); + const Typed_identifier* receiver = fntype->receiver(); + exp->write_name(receiver->name()); + exp->write_c_string(" "); + exp->write_type(receiver->type()); exp->write_c_string(") "); } @@ -3294,6 +3300,8 @@ Function::export_func_with_type(Export* exp, const std::string& name, first = false; else exp->write_c_string(", "); + exp->write_name(p->name()); + exp->write_c_string(" "); if (!is_varargs || p + 1 != parameters->end()) exp->write_type(p->type()); else @@ -3308,7 +3316,7 @@ Function::export_func_with_type(Export* exp, const std::string& name, const Typed_identifier_list* results = fntype->results(); if (results != NULL) { - if (results->size() == 1) + if (results->size() == 1 && results->begin()->name().empty()) { exp->write_c_string(" "); exp->write_type(results->begin()->type()); @@ -3325,6 +3333,8 @@ Function::export_func_with_type(Export* exp, const std::string& name, first = false; else exp->write_c_string(", "); + exp->write_name(p->name()); + exp->write_c_string(" "); exp->write_type(p->type()); } exp->write_c_string(")"); @@ -3348,9 +3358,10 @@ Function::import_func(Import* imp, std::string* pname, if (imp->peek_char() == '(') { imp->require_c_string("("); + std::string name = imp->read_name(); + imp->require_c_string(" "); Type* rtype = imp->read_type(); - *preceiver = new Typed_identifier(Import::import_marker, rtype, - imp->location()); + *preceiver = new Typed_identifier(name, rtype, imp->location()); imp->require_c_string(") "); } @@ -3366,6 +3377,9 @@ Function::import_func(Import* imp, std::string* pname, parameters = new Typed_identifier_list(); while (true) { + std::string name = imp->read_name(); + imp->require_c_string(" "); + if (imp->match_c_string("...")) { imp->advance(3); @@ -3375,8 +3389,8 @@ Function::import_func(Import* imp, std::string* pname, Type* ptype = imp->read_type(); if (*is_varargs) ptype = Type::make_array_type(ptype, NULL); - parameters->push_back(Typed_identifier(Import::import_marker, - ptype, imp->location())); + parameters->push_back(Typed_identifier(name, ptype, + imp->location())); if (imp->peek_char() != ',') break; go_assert(!*is_varargs); @@ -3396,17 +3410,18 @@ Function::import_func(Import* imp, std::string* pname, if (imp->peek_char() != '(') { Type* rtype = imp->read_type(); - results->push_back(Typed_identifier(Import::import_marker, rtype, - imp->location())); + results->push_back(Typed_identifier("", rtype, imp->location())); } else { imp->require_c_string("("); while (true) { + std::string name = imp->read_name(); + imp->require_c_string(" "); Type* rtype = imp->read_type(); - results->push_back(Typed_identifier(Import::import_marker, - rtype, imp->location())); + results->push_back(Typed_identifier(name, rtype, + imp->location())); if (imp->peek_char() != ',') break; imp->require_c_string(", "); @@ -5333,5 +5348,5 @@ Statement_inserter::insert(Statement* s) else if (this->var_ != NULL) this->var_->add_preinit_statement(this->gogo_, s); else - go_unreachable(); + go_assert(saw_errors()); } diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h index 008c8a09872..6c77c3bd9e9 100644 --- a/gcc/go/gofrontend/gogo.h +++ b/gcc/go/gofrontend/gogo.h @@ -398,6 +398,11 @@ class Gogo void write_specific_type_functions(); + // Whether we are done writing out specific type functions. + bool + specific_type_functions_are_written() const + { return this->specific_type_functions_are_written_; } + // Traverse the tree. See the Traverse class. void traverse(Traverse*); diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc index 44ffda61fba..58b0355c6c6 100644 --- a/gcc/go/gofrontend/import.cc +++ b/gcc/go/gofrontend/import.cc @@ -11,6 +11,7 @@ #include "go-c.h" #include "gogo.h" +#include "lex.h" #include "types.h" #include "export.h" #include "import.h" @@ -33,11 +34,6 @@ go_add_search_path(const char* path) search_path.push_back(std::string(path)); } -// The name used for parameters, receivers, and results in imported -// function types. - -const char* const Import::import_marker = "*imported*"; - // Find import data. This searches the file system for FILENAME and // returns a pointer to a Stream object to read the data that it // exports. If the file is not found, it returns NULL. @@ -308,7 +304,10 @@ Import::import(Gogo* gogo, const std::string& local_name, this->package_->set_priority(prio); this->require_c_string(";\n"); - if (stream->match_c_string("import ")) + while (stream->match_c_string("import")) + this->read_one_import(); + + if (stream->match_c_string("init")) this->read_import_init_fns(gogo); // Loop over all the input data for this package. @@ -348,12 +347,24 @@ Import::import(Gogo* gogo, const std::string& local_name, return this->package_; } +// Read an import line. We don't actually care about these. + +void +Import::read_one_import() +{ + this->require_c_string("import "); + Stream* stream = this->stream_; + while (stream->peek_char() != ';') + stream->advance(1); + this->require_c_string(";\n"); +} + // Read the list of import control functions. void Import::read_import_init_fns(Gogo* gogo) { - this->require_c_string("import"); + this->require_c_string("init"); while (!this->match_c_string(";")) { this->require_c_string(" "); @@ -749,6 +760,21 @@ Import::read_identifier() return ret; } +// Read a name from the stream. + +std::string +Import::read_name() +{ + std::string ret = this->read_identifier(); + if (ret == "?") + ret.clear(); + else if (!Lex::is_exported_name(ret)) + ret = ('.' + this->package_->unique_prefix() + + '.' + this->package_->name() + + '.' + ret); + return ret; +} + // Turn a string into a integer with appropriate error handling. bool diff --git a/gcc/go/gofrontend/import.h b/gcc/go/gofrontend/import.h index bdff0c2a9e1..67bdcb02d57 100644 --- a/gcc/go/gofrontend/import.h +++ b/gcc/go/gofrontend/import.h @@ -181,14 +181,15 @@ class Import std::string read_identifier(); + // Read a name. This is like read_identifier, except that a "?" is + // returned as an empty string. This matches Export::write_name. + std::string + read_name(); + // Read a type. Type* read_type(); - // The name used for parameters, receivers, and results in imported - // function types. - static const char* const import_marker; - private: static Stream* try_package_in_directory(const std::string&, Location); @@ -212,6 +213,10 @@ class Import find_archive_export_data(const std::string& filename, int fd, Location); + // Read an import line. + void + read_one_import(); + // Read the import control functions. void read_import_init_fns(Gogo*); diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc index 6eb1981a4be..1a9c153a578 100644 --- a/gcc/go/gofrontend/parse.cc +++ b/gcc/go/gofrontend/parse.cc @@ -2491,7 +2491,7 @@ Parse::operand(bool may_be_sink) if (token->is_op(OPERATOR_LPAREN)) { this->advance_token(); - ret = this->expression(PRECEDENCE_NORMAL, false, true, NULL); + ret = this->expression(PRECEDENCE_NORMAL, may_be_sink, true, NULL); if (!this->peek_token()->is_op(OPERATOR_RPAREN)) error_at(this->location(), "missing %<)%>"); else @@ -3948,8 +3948,9 @@ Parse::return_stat() ++p) { Named_object* no = this->gogo_->lookup((*p)->name(), NULL); - go_assert(no != NULL); - if (!no->is_result_variable()) + if (no == NULL) + go_assert(saw_errors()); + else if (!no->is_result_variable()) error_at(location, "%qs is shadowed during return", (*p)->message_name().c_str()); } diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc index e55dc74b3b7..65c64c5e906 100644 --- a/gcc/go/gofrontend/statements.cc +++ b/gcc/go/gofrontend/statements.cc @@ -1013,7 +1013,7 @@ Tuple_assignment_statement::do_lower(Gogo*, Named_object*, Block* enclosing, b->add_statement(s); ++ptemp; } - go_assert(ptemp == temps.end()); + go_assert(ptemp == temps.end() || saw_errors()); return Statement::make_block_statement(b, loc); } @@ -3452,7 +3452,7 @@ Case_clauses::Case_clause::get_backend(Translate_context* context, { // Value was already present. error_at(this->location_, "duplicate case in switch"); - continue; + e = Expression::make_error(this->location_); } tree case_tree = e->get_tree(context); diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc index 4ed54bb5358..03f1b3ea0c6 100644 --- a/gcc/go/gofrontend/types.cc +++ b/gcc/go/gofrontend/types.cc @@ -622,16 +622,24 @@ Type::are_assignable_check_hidden(const Type* lhs, const Type* rhs, std::string* reason) { // Do some checks first. Make sure the types are defined. - if (rhs != NULL - && rhs->forwarded()->forward_declaration_type() == NULL - && rhs->is_void_type()) + if (rhs != NULL && !rhs->is_undefined()) { - if (reason != NULL) - *reason = "non-value used as value"; - return false; + if (rhs->is_void_type()) + { + if (reason != NULL) + *reason = "non-value used as value"; + return false; + } + if (rhs->is_call_multiple_result_type()) + { + if (reason != NULL) + reason->assign(_("multiple value function call in " + "single value context")); + return false; + } } - if (lhs != NULL && lhs->forwarded()->forward_declaration_type() == NULL) + if (lhs != NULL && !lhs->is_undefined()) { // Any value may be assigned to the blank identifier. if (lhs->is_sink_type()) @@ -639,9 +647,7 @@ Type::are_assignable_check_hidden(const Type* lhs, const Type* rhs, // All fields of a struct must be exported, or the assignment // must be in the same package. - if (check_hidden_fields - && rhs != NULL - && rhs->forwarded()->forward_declaration_type() == NULL) + if (check_hidden_fields && rhs != NULL && !rhs->is_undefined()) { if (lhs->has_hidden_fields(NULL, reason) || rhs->has_hidden_fields(NULL, reason)) @@ -715,9 +721,6 @@ Type::are_assignable_check_hidden(const Type* lhs, const Type* rhs, { if (rhs->interface_type() != NULL) reason->assign(_("need explicit conversion")); - else if (rhs->is_call_multiple_result_type()) - reason->assign(_("multiple value function call in " - "single value context")); else if (lhs->named_type() != NULL && rhs->named_type() != NULL) { size_t len = (lhs->named_type()->name().length() @@ -1787,6 +1790,12 @@ Type::write_specific_type_functions(Gogo* gogo, Named_type* name, { Location bloc = Linemap::predeclared_location(); + if (gogo->specific_type_functions_are_written()) + { + go_assert(saw_errors()); + return; + } + Named_object* hash_fn = gogo->start_function(hash_name, hash_fntype, false, bloc); gogo->start_block(bloc); @@ -3111,9 +3120,7 @@ Function_type::is_valid_redeclaration(const Function_type* t, // A redeclaration of a function is required to use the same names // for the receiver and parameters. if (this->receiver() != NULL - && this->receiver()->name() != t->receiver()->name() - && this->receiver()->name() != Import::import_marker - && t->receiver()->name() != Import::import_marker) + && this->receiver()->name() != t->receiver()->name()) { if (reason != NULL) *reason = "receiver name changed"; @@ -3129,9 +3136,7 @@ Function_type::is_valid_redeclaration(const Function_type* t, p2 != parms2->end(); ++p2, ++p1) { - if (p1->name() != p2->name() - && p1->name() != Import::import_marker - && p2->name() != Import::import_marker) + if (p1->name() != p2->name()) { if (reason != NULL) *reason = "parameter name changed"; @@ -3160,9 +3165,7 @@ Function_type::is_valid_redeclaration(const Function_type* t, res2 != results2->end(); ++res2, ++res1) { - if (res1->name() != res2->name() - && res1->name() != Import::import_marker - && res2->name() != Import::import_marker) + if (res1->name() != res2->name()) { if (reason != NULL) *reason = "result name changed"; @@ -3609,6 +3612,8 @@ Function_type::do_export(Export* exp) const first = false; else exp->write_c_string(", "); + exp->write_name(p->name()); + exp->write_c_string(" "); if (!is_varargs || p + 1 != this->parameters_->end()) exp->write_type(p->type()); else @@ -3624,7 +3629,7 @@ Function_type::do_export(Export* exp) const if (results != NULL) { exp->write_c_string(" "); - if (results->size() == 1) + if (results->size() == 1 && results->begin()->name().empty()) exp->write_type(results->begin()->type()); else { @@ -3638,6 +3643,8 @@ Function_type::do_export(Export* exp) const first = false; else exp->write_c_string(", "); + exp->write_name(p->name()); + exp->write_c_string(" "); exp->write_type(p->type()); } exp->write_c_string(")"); @@ -3660,6 +3667,9 @@ Function_type::do_import(Import* imp) parameters = new Typed_identifier_list(); while (true) { + std::string name = imp->read_name(); + imp->require_c_string(" "); + if (imp->match_c_string("...")) { imp->advance(3); @@ -3669,8 +3679,8 @@ Function_type::do_import(Import* imp) Type* ptype = imp->read_type(); if (is_varargs) ptype = Type::make_array_type(ptype, NULL); - parameters->push_back(Typed_identifier(Import::import_marker, - ptype, imp->location())); + parameters->push_back(Typed_identifier(name, ptype, + imp->location())); if (imp->peek_char() != ',') break; go_assert(!is_varargs); @@ -3689,17 +3699,18 @@ Function_type::do_import(Import* imp) if (imp->peek_char() != '(') { Type* rtype = imp->read_type(); - results->push_back(Typed_identifier(Import::import_marker, rtype, - imp->location())); + results->push_back(Typed_identifier("", rtype, imp->location())); } else { imp->advance(1); while (true) { + std::string name = imp->read_name(); + imp->require_c_string(" "); Type* rtype = imp->read_type(); - results->push_back(Typed_identifier(Import::import_marker, - rtype, imp->location())); + results->push_back(Typed_identifier(name, rtype, + imp->location())); if (imp->peek_char() != ',') break; imp->require_c_string(", "); @@ -3739,8 +3750,12 @@ Function_type::copy_with_receiver(Type* receiver_type) const go_assert(!this->is_method()); Typed_identifier* receiver = new Typed_identifier("", receiver_type, this->location_); - return Type::make_function_type(receiver, this->parameters_, - this->results_, this->location_); + Function_type* ret = Type::make_function_type(receiver, this->parameters_, + this->results_, + this->location_); + if (this->is_varargs_) + ret->set_is_varargs(); + return ret; } // Make a function type. @@ -4114,7 +4129,6 @@ Struct_type::do_verify() Struct_field_list* fields = this->fields_; if (fields == NULL) return true; - bool ret = true; for (Struct_field_list::iterator p = fields->begin(); p != fields->end(); ++p) @@ -4124,7 +4138,6 @@ Struct_type::do_verify() { error_at(p->location(), "struct field type is incomplete"); p->set_type(Type::make_error_type()); - ret = false; } else if (p->is_anonymous()) { @@ -4132,19 +4145,17 @@ Struct_type::do_verify() { error_at(p->location(), "embedded type may not be a pointer"); p->set_type(Type::make_error_type()); - return false; } - if (t->points_to() != NULL - && t->points_to()->interface_type() != NULL) + else 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; + return true; } // Whether this contains a pointer. @@ -5204,10 +5215,7 @@ bool Array_type::do_verify() { if (!this->verify_length()) - { - this->length_ = Expression::make_error(this->length_->location()); - return false; - } + this->length_ = Expression::make_error(this->length_->location()); return true; } @@ -5897,10 +5905,7 @@ Map_type::do_verify() { // The runtime support uses "map[void]void". if (!this->key_type_->is_comparable() && !this->key_type_->is_void_type()) - { - error_at(this->location_, "invalid map key type"); - return false; - } + error_at(this->location_, "invalid map key type"); return true; } @@ -6469,7 +6474,7 @@ Interface_type::finalize_methods() } Named_type* nt = t->named_type(); - if (nt != NULL) + if (nt != NULL && it->parse_methods_ != NULL) { std::vector<Named_type*>::const_iterator q; for (q = seen.begin(); q != seen.end(); ++q) @@ -7185,7 +7190,7 @@ Interface_type::do_export(Export* exp) const { if (pm->name().empty()) { - exp->write_c_string("$ "); + exp->write_c_string("? "); exp->write_type(pm->type()); } else @@ -7209,6 +7214,8 @@ Interface_type::do_export(Export* exp) const first = false; else exp->write_c_string(", "); + exp->write_name(pp->name()); + exp->write_c_string(" "); if (!is_varargs || pp + 1 != parameters->end()) exp->write_type(pp->type()); else @@ -7226,7 +7233,7 @@ Interface_type::do_export(Export* exp) const if (results != NULL) { exp->write_c_string(" "); - if (results->size() == 1) + if (results->size() == 1 && results->begin()->name().empty()) exp->write_type(results->begin()->type()); else { @@ -7241,6 +7248,8 @@ Interface_type::do_export(Export* exp) const first = false; else exp->write_c_string(", "); + exp->write_name(p->name()); + exp->write_c_string(" "); exp->write_type(p->type()); } exp->write_c_string(")"); @@ -7267,7 +7276,7 @@ Interface_type::do_import(Import* imp) { std::string name = imp->read_identifier(); - if (name == "$") + if (name == "?") { imp->require_c_string(" "); Type* t = imp->read_type(); @@ -7287,6 +7296,9 @@ Interface_type::do_import(Import* imp) parameters = new Typed_identifier_list; while (true) { + std::string name = imp->read_name(); + imp->require_c_string(" "); + if (imp->match_c_string("...")) { imp->advance(3); @@ -7296,8 +7308,8 @@ Interface_type::do_import(Import* imp) Type* ptype = imp->read_type(); if (is_varargs) ptype = Type::make_array_type(ptype, NULL); - parameters->push_back(Typed_identifier(Import::import_marker, - ptype, imp->location())); + parameters->push_back(Typed_identifier(name, ptype, + imp->location())); if (imp->peek_char() != ',') break; go_assert(!is_varargs); @@ -7316,17 +7328,18 @@ Interface_type::do_import(Import* imp) if (imp->peek_char() != '(') { Type* rtype = imp->read_type(); - results->push_back(Typed_identifier(Import::import_marker, - rtype, imp->location())); + results->push_back(Typed_identifier("", rtype, imp->location())); } else { imp->advance(1); while (true) { + std::string name = imp->read_name(); + imp->require_c_string(" "); Type* rtype = imp->read_type(); - results->push_back(Typed_identifier(Import::import_marker, - rtype, imp->location())); + results->push_back(Typed_identifier(name, rtype, + imp->location())); if (imp->peek_char() != ',') break; imp->require_c_string(", "); @@ -7875,7 +7888,6 @@ Named_type::do_verify() if (this->local_methods_ != NULL) { Struct_type* st = this->type_->struct_type(); - bool found_dup = false; if (st != NULL) { for (Bindings::const_declarations_iterator p = @@ -7889,12 +7901,9 @@ Named_type::do_verify() error_at(p->second->location(), "method %qs redeclares struct field name", Gogo::message_name(name).c_str()); - found_dup = true; } } } - if (found_dup) - return false; } return true; diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h index 72c42ebb4ba..3fe80488a49 100644 --- a/gcc/go/gofrontend/types.h +++ b/gcc/go/gofrontend/types.h @@ -510,7 +510,8 @@ class Type // Verify the type. This is called after parsing, and verifies that // types are complete and meet the language requirements. This - // returns false if the type is invalid. + // returns false if the type is invalid and we should not continue + // traversing it. bool verify() { return this->do_verify(); } diff --git a/gcc/go/gofrontend/unsafe.cc b/gcc/go/gofrontend/unsafe.cc index 6e8a4042e72..bc949c6b56e 100644 --- a/gcc/go/gofrontend/unsafe.cc +++ b/gcc/go/gofrontend/unsafe.cc @@ -34,6 +34,8 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, package->set_location(location); package->set_is_imported(); + this->imports_.insert(std::make_pair("unsafe", package)); + Bindings* bindings = package->bindings(); // The type may have already been created by an import. @@ -86,60 +88,6 @@ Gogo::import_unsafe(const std::string& local_name, bool is_local_name_exported, if (add_to_globals) this->add_named_object(no); - // Typeof. - Type* empty_interface = Type::make_empty_interface_type(bloc); - Typed_identifier_list* parameters = new Typed_identifier_list; - parameters->push_back(Typed_identifier("i", empty_interface, bloc)); - results = new Typed_identifier_list; - results->push_back(Typed_identifier("", empty_interface, bloc)); - fntype = Type::make_function_type(NULL, parameters, results, bloc); - no = bindings->add_function_declaration("Typeof", package, fntype, bloc); - if (add_to_globals) - this->add_named_object(no); - - // Reflect. - parameters = new Typed_identifier_list; - parameters->push_back(Typed_identifier("it", empty_interface, bloc)); - results = new Typed_identifier_list; - results->push_back(Typed_identifier("", empty_interface, bloc)); - results->push_back(Typed_identifier("", pointer_type, bloc)); - fntype = Type::make_function_type(NULL, parameters, results, bloc); - no = bindings->add_function_declaration("Reflect", package, fntype, bloc); - if (add_to_globals) - this->add_named_object(no); - - // Unreflect. - parameters = new Typed_identifier_list; - parameters->push_back(Typed_identifier("typ", empty_interface, bloc)); - parameters->push_back(Typed_identifier("addr", pointer_type, bloc)); - results = new Typed_identifier_list; - results->push_back(Typed_identifier("", empty_interface, bloc)); - fntype = Type::make_function_type(NULL, parameters, results, bloc); - no = bindings->add_function_declaration("Unreflect", package, fntype, bloc); - if (add_to_globals) - this->add_named_object(no); - - // New. - parameters = new Typed_identifier_list; - parameters->push_back(Typed_identifier("typ", empty_interface, bloc)); - results = new Typed_identifier_list; - results->push_back(Typed_identifier("", pointer_type, bloc)); - fntype = Type::make_function_type(NULL, parameters, results, bloc); - no = bindings->add_function_declaration("New", package, fntype, bloc); - if (add_to_globals) - this->add_named_object(no); - - // NewArray. - parameters = new Typed_identifier_list; - parameters->push_back(Typed_identifier("typ", empty_interface, bloc)); - parameters->push_back(Typed_identifier("n", int_type, bloc)); - results = new Typed_identifier_list; - results->push_back(Typed_identifier("", pointer_type, bloc)); - fntype = Type::make_function_type(NULL, parameters, results, bloc); - no = bindings->add_function_declaration("NewArray", package, fntype, bloc); - if (add_to_globals) - this->add_named_object(no); - if (!this->imported_unsafe_) { go_imported_unsafe(); |