summaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend
diff options
context:
space:
mode:
authorCary Coutant <ccoutant@google.com>2012-03-09 11:50:43 -0800
committerCary Coutant <ccoutant@google.com>2012-03-09 11:50:43 -0800
commit4ed2fc3a6bbaaf1f2ea4d1c077dc7fa0867cd005 (patch)
tree7774dcb772ccc005c2fd8f8831dc45b90a8f6060 /gcc/go/gofrontend
parent2400d467a903f32c96df9f9fcb0de7be8a655afa (diff)
parentf9c681635d1850543f547fdbb6efd5a010aca015 (diff)
downloadgcc-4ed2fc3a6bbaaf1f2ea4d1c077dc7fa0867cd005.tar.gz
Merge branch 'master' into google-debugfission
Diffstat (limited to 'gcc/go/gofrontend')
-rw-r--r--gcc/go/gofrontend/export.cc57
-rw-r--r--gcc/go/gofrontend/export.h10
-rw-r--r--gcc/go/gofrontend/expressions.cc137
-rw-r--r--gcc/go/gofrontend/expressions.h4
-rw-r--r--gcc/go/gofrontend/gogo-tree.cc4
-rw-r--r--gcc/go/gofrontend/gogo.cc43
-rw-r--r--gcc/go/gofrontend/gogo.h5
-rw-r--r--gcc/go/gofrontend/import.cc40
-rw-r--r--gcc/go/gofrontend/import.h13
-rw-r--r--gcc/go/gofrontend/parse.cc7
-rw-r--r--gcc/go/gofrontend/statements.cc4
-rw-r--r--gcc/go/gofrontend/types.cc129
-rw-r--r--gcc/go/gofrontend/types.h3
-rw-r--r--gcc/go/gofrontend/unsafe.cc56
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();