summaryrefslogtreecommitdiff
path: root/gcc/go
diff options
context:
space:
mode:
authorH.J. Lu <hjl.tools@gmail.com>2013-01-18 12:34:11 -0800
committerH.J. Lu <hjl.tools@gmail.com>2013-01-18 12:34:11 -0800
commit43269d882367dc4f0e4c2651d6625e1b7de78764 (patch)
tree6aaf525a6fb8a4fb63a71c9ca56be58bc1d6655b /gcc/go
parentce97ec0e268b7b50b9f801dd12ffc67042c47193 (diff)
parent48dc1117de124a2265129a36bfbbc211522c2c02 (diff)
downloadgcc-43269d882367dc4f0e4c2651d6625e1b7de78764.tar.gz
Merge remote-tracking branch 'origin/gcc-4_7-branch' into hjl/tsx/gcc-4_7-branchhjl/tsx/gcc-4_7-branch
Conflicts: gcc/config/i386/driver-i386.c gcc/config/i386/i386.c gcc/config/i386/sync.md
Diffstat (limited to 'gcc/go')
-rw-r--r--gcc/go/ChangeLog19
-rw-r--r--gcc/go/Make-lang.in9
-rw-r--r--gcc/go/gccgo.texi6
-rw-r--r--gcc/go/go-c.h3
-rw-r--r--gcc/go/go-lang.c8
-rw-r--r--gcc/go/gofrontend/expressions.cc277
-rw-r--r--gcc/go/gofrontend/expressions.h23
-rw-r--r--gcc/go/gofrontend/go.cc5
-rw-r--r--gcc/go/gofrontend/gogo-tree.cc30
-rw-r--r--gcc/go/gofrontend/gogo.cc110
-rw-r--r--gcc/go/gofrontend/gogo.h43
-rw-r--r--gcc/go/gofrontend/import.cc29
-rw-r--r--gcc/go/gofrontend/import.h4
-rw-r--r--gcc/go/gofrontend/lex.cc55
-rw-r--r--gcc/go/gofrontend/lex.h4
-rw-r--r--gcc/go/gofrontend/parse.cc171
-rw-r--r--gcc/go/gofrontend/parse.h7
-rw-r--r--gcc/go/gofrontend/statements.cc55
-rw-r--r--gcc/go/gofrontend/types.cc341
-rw-r--r--gcc/go/gofrontend/types.h107
-rw-r--r--gcc/go/lang.opt4
21 files changed, 987 insertions, 323 deletions
diff --git a/gcc/go/ChangeLog b/gcc/go/ChangeLog
index d236325e52a..d78924ba60c 100644
--- a/gcc/go/ChangeLog
+++ b/gcc/go/ChangeLog
@@ -1,3 +1,22 @@
+2012-10-30 Ian Lance Taylor <iant@google.com>
+
+ * lang.opt (-fgo-relative-import-path): New option.
+ * go-lang.c (go_relative_import_path): New static variable.
+ (go_langhook_init): Pass go_relative_import_path to
+ go_create_gogo.
+ (go_langhook_handle_option): Handle -fgo-relative-import-path.
+ * go-c.h (go_create_gogo): Update declaration.
+ * gccgo.texi (Invoking gccgo): Document
+ -fgo-relative-import-path.
+
+2012-09-20 Ian Lance Taylor <iant@google.com>
+
+ * Make-lang.in (go/gogo.o): Depend on filenames.h.
+
+2012-09-20 Release Manager
+
+ * GCC 4.7.2 released.
+
2012-06-14 Release Manager
* GCC 4.7.1 released.
diff --git a/gcc/go/Make-lang.in b/gcc/go/Make-lang.in
index 34e5584cc09..b3cb2bdbc19 100644
--- a/gcc/go/Make-lang.in
+++ b/gcc/go/Make-lang.in
@@ -289,10 +289,11 @@ go/gogo-tree.o: go/gofrontend/gogo-tree.cc $(GO_SYSTEM_H) $(TOPLEV_H) \
convert.h output.h $(DIAGNOSTIC_H) $(GO_TYPES_H) \
$(GO_EXPRESSIONS_H) $(GO_STATEMENTS_H) $(GO_RUNTIME_H) \
go/gofrontend/backend.h $(GO_GOGO_H)
-go/gogo.o: go/gofrontend/gogo.cc $(GO_SYSTEM_H) $(GO_C_H) \
- go/gofrontend/go-dump.h $(GO_LEX_H) $(GO_TYPES_H) $(GO_STATEMENTS_H) \
- $(GO_EXPRESSIONS_H) go/gofrontend/dataflow.h $(GO_RUNTIME_H) \
- $(GO_IMPORT_H) $(GO_EXPORT_H) go/gofrontend/backend.h $(GO_GOGO_H)
+go/gogo.o: go/gofrontend/gogo.cc $(GO_SYSTEM_H) \
+ $(srcdir)/../include/filenames.h $(GO_C_H) go/gofrontend/go-dump.h \
+ $(GO_LEX_H) $(GO_TYPES_H) $(GO_STATEMENTS_H) $(GO_EXPRESSIONS_H) \
+ go/gofrontend/dataflow.h $(GO_RUNTIME_H) $(GO_IMPORT_H) \
+ $(GO_EXPORT_H) go/gofrontend/backend.h $(GO_GOGO_H)
go/import.o: go/gofrontend/import.cc $(GO_SYSTEM_H) \
$(srcdir)/../include/filenames.h $(srcdir)/../include/simple-object.h \
$(GO_C_H) $(GO_GOGO_H) $(GO_LEX_H) $(GO_TYPES_H) $(GO_EXPORT_H) \
diff --git a/gcc/go/gccgo.texi b/gcc/go/gccgo.texi
index a5e37e76e80..91930c812f6 100644
--- a/gcc/go/gccgo.texi
+++ b/gcc/go/gccgo.texi
@@ -184,6 +184,12 @@ Using either @option{-fgo-pkgpath} or @option{-fgo-prefix} disables
the special treatment of the @code{main} package and permits that
package to be imported like any other.
+@item -fgo-relative-import-path=@var{dir}
+@cindex @option{-fgo-relative-import-path}
+A relative import is an import that starts with @file{./} or
+@file{../}. If this option is used, @command{gccgo} will use
+@var{dir} as a prefix for the relative import when searching for it.
+
@item -frequire-return-statement
@itemx -fno-require-return-statement
@cindex @option{-frequire-return-statement}
diff --git a/gcc/go/go-c.h b/gcc/go/go-c.h
index d46a08796e3..ea59fb6b39a 100644
--- a/gcc/go/go-c.h
+++ b/gcc/go/go-c.h
@@ -42,7 +42,8 @@ extern int go_enable_optimize (const char*);
extern void go_add_search_path (const char*);
extern void go_create_gogo (int int_type_size, int pointer_size,
- const char* pkgpath, const char *prefix);
+ const char* pkgpath, const char *prefix,
+ const char *relative_import_path);
extern void go_parse_input_files (const char**, unsigned int,
bool only_check_syntax,
diff --git a/gcc/go/go-lang.c b/gcc/go/go-lang.c
index f02f769252b..61ca1478be6 100644
--- a/gcc/go/go-lang.c
+++ b/gcc/go/go-lang.c
@@ -85,6 +85,7 @@ struct GTY(()) language_function
static const char *go_pkgpath = NULL;
static const char *go_prefix = NULL;
+static const char *go_relative_import_path = NULL;
/* Language hooks. */
@@ -101,7 +102,8 @@ go_langhook_init (void)
to, e.g., unsigned_char_type_node) but before calling
build_common_builtin_nodes (because it calls, indirectly,
go_type_for_size). */
- go_create_gogo (INT_TYPE_SIZE, POINTER_SIZE, go_pkgpath, go_prefix);
+ go_create_gogo (INT_TYPE_SIZE, POINTER_SIZE, go_pkgpath, go_prefix,
+ go_relative_import_path);
build_common_builtin_nodes ();
@@ -240,6 +242,10 @@ go_langhook_handle_option (
go_prefix = arg;
break;
+ case OPT_fgo_relative_import_path_:
+ go_relative_import_path = arg;
+ break;
+
default:
/* Just return 1 to indicate that the option is valid. */
break;
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index f57ca411885..e16cd84d0a0 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -89,10 +89,11 @@ Expression::do_traverse(Traverse*)
// expression is being discarded. By default, we give an error.
// Expressions with side effects override.
-void
+bool
Expression::do_discarding_value()
{
this->unused_value_error();
+ return false;
}
// This virtual function is called to export expressions. This will
@@ -109,7 +110,7 @@ Expression::do_export(Export*) const
void
Expression::unused_value_error()
{
- error_at(this->location(), "value computed is not used");
+ this->report_error(_("value computed is not used"));
}
// Note that this expression is an error. This is called by children
@@ -301,19 +302,25 @@ Expression::convert_type_to_interface(Translate_context* context,
// object type: a list of function pointers for each interface
// method.
Named_type* rhs_named_type = rhs_type->named_type();
+ Struct_type* rhs_struct_type = rhs_type->struct_type();
bool is_pointer = false;
- if (rhs_named_type == NULL)
+ if (rhs_named_type == NULL && rhs_struct_type == NULL)
{
rhs_named_type = rhs_type->deref()->named_type();
+ rhs_struct_type = rhs_type->deref()->struct_type();
is_pointer = true;
}
tree method_table;
- if (rhs_named_type == NULL)
- method_table = null_pointer_node;
- else
+ if (rhs_named_type != NULL)
method_table =
rhs_named_type->interface_method_table(gogo, lhs_interface_type,
is_pointer);
+ else if (rhs_struct_type != NULL)
+ method_table =
+ rhs_struct_type->interface_method_table(gogo, lhs_interface_type,
+ is_pointer);
+ else
+ method_table = null_pointer_node;
first_field_value = fold_convert_loc(location.gcc_location(),
const_ptr_type_node, method_table);
}
@@ -783,9 +790,9 @@ class Error_expression : public Expression
return true;
}
- void
+ bool
do_discarding_value()
- { }
+ { return true; }
Type*
do_type()
@@ -1146,9 +1153,9 @@ class Sink_expression : public Expression
{ }
protected:
- void
+ bool
do_discarding_value()
- { }
+ { return true; }
Type*
do_type();
@@ -5184,6 +5191,9 @@ Binary_expression::lower_struct_comparison(Gogo* gogo,
pf != fields->end();
++pf, ++field_index)
{
+ if (Gogo::is_sink_name(pf->field_name()))
+ continue;
+
if (field_index > 0)
{
if (left_temp == NULL)
@@ -5314,13 +5324,19 @@ Binary_expression::do_numeric_constant_value(Numeric_constant* nc) const
// Note that the value is being discarded.
-void
+bool
Binary_expression::do_discarding_value()
{
if (this->op_ == OPERATOR_OROR || this->op_ == OPERATOR_ANDAND)
- this->right_->discarding_value();
+ {
+ this->right_->discarding_value();
+ return true;
+ }
else
- this->unused_value_error();
+ {
+ this->unused_value_error();
+ return false;
+ }
}
// Get type.
@@ -5450,7 +5466,8 @@ Binary_expression::do_determine_type(const Type_context* context)
&& (this->left_->type()->integer_type() == NULL
|| (subcontext.type->integer_type() == NULL
&& subcontext.type->float_type() == NULL
- && subcontext.type->complex_type() == NULL)))
+ && subcontext.type->complex_type() == NULL
+ && subcontext.type->interface_type() == NULL)))
this->report_error(("invalid context-determined non-integer type "
"for shift operand"));
@@ -6518,7 +6535,7 @@ class Builtin_call_expression : public Call_expression
bool
do_numeric_constant_value(Numeric_constant*) const;
- void
+ bool
do_discarding_value();
Type*
@@ -6682,38 +6699,6 @@ Builtin_call_expression::do_set_recover_arg(Expression* arg)
this->set_args(new_args);
}
-// A traversal class which looks for a call expression.
-
-class Find_call_expression : public Traverse
-{
- public:
- Find_call_expression()
- : Traverse(traverse_expressions),
- found_(false)
- { }
-
- int
- expression(Expression**);
-
- bool
- found()
- { return this->found_; }
-
- private:
- bool found_;
-};
-
-int
-Find_call_expression::expression(Expression** pexpr)
-{
- if ((*pexpr)->call_expression() != NULL)
- {
- this->found_ = true;
- return TRAVERSE_EXIT;
- }
- return TRAVERSE_CONTINUE;
-}
-
// Lower a builtin call expression. This turns new and make into
// specific expressions. We also convert to a constant if we can.
@@ -6734,20 +6719,6 @@ Builtin_call_expression::do_lower(Gogo* gogo, Named_object* function,
if (this->is_constant())
{
- // We can only lower len and cap if there are no function calls
- // in the arguments. Otherwise we have to make the call.
- if (this->code_ == BUILTIN_LEN || this->code_ == BUILTIN_CAP)
- {
- Expression* arg = this->one_arg();
- if (arg != NULL && !arg->is_constant())
- {
- Find_call_expression find_call;
- Expression::traverse(&arg, &find_call);
- if (find_call.found())
- return this;
- }
- }
-
Numeric_constant nc;
if (this->numeric_constant_value(&nc))
return nc.expression(loc);
@@ -7064,8 +7035,42 @@ Builtin_call_expression::one_arg() const
return args->front();
}
-// Return whether this is constant: len of a string, or len or cap of
-// a fixed array, or unsafe.Sizeof, unsafe.Offsetof, unsafe.Alignof.
+// A traversal class which looks for a call or receive expression.
+
+class Find_call_expression : public Traverse
+{
+ public:
+ Find_call_expression()
+ : Traverse(traverse_expressions),
+ found_(false)
+ { }
+
+ int
+ expression(Expression**);
+
+ bool
+ found()
+ { return this->found_; }
+
+ private:
+ bool found_;
+};
+
+int
+Find_call_expression::expression(Expression** pexpr)
+{
+ if ((*pexpr)->call_expression() != NULL
+ || (*pexpr)->receive_expression() != NULL)
+ {
+ this->found_ = true;
+ return TRAVERSE_EXIT;
+ }
+ return TRAVERSE_CONTINUE;
+}
+
+// Return whether this is constant: len of a string constant, or len
+// or cap of an array, or unsafe.Sizeof, unsafe.Offsetof,
+// unsafe.Alignof.
bool
Builtin_call_expression::do_is_constant() const
@@ -7088,6 +7093,17 @@ Builtin_call_expression::do_is_constant() const
&& !arg_type->points_to()->is_slice_type())
arg_type = arg_type->points_to();
+ // The len and cap functions are only constant if there are no
+ // function calls or channel operations in the arguments.
+ // Otherwise we have to make the call.
+ if (!arg->is_constant())
+ {
+ Find_call_expression find_call;
+ Expression::traverse(&arg, &find_call);
+ if (find_call.found())
+ return false;
+ }
+
if (arg_type->array_type() != NULL
&& arg_type->array_type()->length() != NULL)
return true;
@@ -7321,7 +7337,7 @@ Builtin_call_expression::do_numeric_constant_value(Numeric_constant* nc) const
// discarding the value of an ordinary function call, but we do for
// builtin functions, purely for consistency with the gc compiler.
-void
+bool
Builtin_call_expression::do_discarding_value()
{
switch (this->code_)
@@ -7342,7 +7358,7 @@ Builtin_call_expression::do_discarding_value()
case BUILTIN_OFFSETOF:
case BUILTIN_SIZEOF:
this->unused_value_error();
- break;
+ return false;
case BUILTIN_CLOSE:
case BUILTIN_COPY:
@@ -7351,7 +7367,7 @@ Builtin_call_expression::do_discarding_value()
case BUILTIN_PRINT:
case BUILTIN_PRINTLN:
case BUILTIN_RECOVER:
- break;
+ return true;
}
}
@@ -7474,7 +7490,7 @@ Builtin_call_expression::do_determine_type(const Type_context* context)
if (args != NULL && args->size() == 2)
{
Type* t1 = args->front()->type();
- Type* t2 = args->front()->type();
+ Type* t2 = args->back()->type();
if (!t1->is_abstract())
arg_type = t1;
else if (!t2->is_abstract())
@@ -8497,6 +8513,16 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
return Expression::make_cast(this->fn_->type(), this->args_->front(),
loc);
+ // Because do_type will return an error type and thus prevent future
+ // errors, check for that case now to ensure that the error gets
+ // reported.
+ if (this->get_function_type() == NULL)
+ {
+ if (!this->fn_->type()->is_error())
+ this->report_error(_("expected function"));
+ return Expression::make_error(loc);
+ }
+
// Recognize a call to a builtin function.
Func_expression* fne = this->fn_->func_expression();
if (fne != NULL
@@ -9186,6 +9212,9 @@ Call_expression::do_get_tree(Translate_context* context)
}
}
+ if (func == NULL)
+ fn = save_expr(fn);
+
tree ret = build_call_array(excess_type != NULL_TREE ? excess_type : rettype,
fn, nargs, args);
delete[] args;
@@ -9219,6 +9248,24 @@ Call_expression::do_get_tree(Translate_context* context)
if (this->results_ != NULL)
ret = this->set_results(context, ret);
+ // We can't unwind the stack past a call to nil, so we need to
+ // insert an explicit check so that the panic can be recovered.
+ if (func == NULL)
+ {
+ tree compare = fold_build2_loc(location.gcc_location(), EQ_EXPR,
+ boolean_type_node, fn,
+ fold_convert_loc(location.gcc_location(),
+ TREE_TYPE(fn),
+ null_pointer_node));
+ tree crash = build3_loc(location.gcc_location(), COND_EXPR,
+ void_type_node, compare,
+ gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE,
+ location),
+ NULL_TREE);
+ ret = fold_build2_loc(location.gcc_location(), COMPOUND_EXPR,
+ TREE_TYPE(ret), crash, ret);
+ }
+
this->tree_ = ret;
return ret;
@@ -14070,7 +14117,7 @@ Numeric_constant::check_int_type(Integer_type* type, bool issue_error,
bool
Numeric_constant::check_float_type(Float_type* type, bool issue_error,
- Location location) const
+ Location location)
{
mpfr_t val;
switch (this->classification_)
@@ -14123,6 +14170,29 @@ Numeric_constant::check_float_type(Float_type* type, bool issue_error,
}
ret = exp <= max_exp;
+
+ if (ret)
+ {
+ // Round the constant to the desired type.
+ mpfr_t t;
+ mpfr_init(t);
+ switch (type->bits())
+ {
+ case 32:
+ mpfr_set_prec(t, 24);
+ break;
+ case 64:
+ mpfr_set_prec(t, 53);
+ break;
+ default:
+ go_unreachable();
+ }
+ mpfr_set(t, val, GMP_RNDN);
+ mpfr_set(val, t, GMP_RNDN);
+ mpfr_clear(t);
+
+ this->set_float(type, val);
+ }
}
mpfr_clear(val);
@@ -14137,7 +14207,7 @@ Numeric_constant::check_float_type(Float_type* type, bool issue_error,
bool
Numeric_constant::check_complex_type(Complex_type* type, bool issue_error,
- Location location) const
+ Location location)
{
if (type->is_abstract())
return true;
@@ -14156,46 +14226,77 @@ Numeric_constant::check_complex_type(Complex_type* type, bool issue_error,
}
mpfr_t real;
+ mpfr_t imag;
switch (this->classification_)
{
case NC_INT:
case NC_RUNE:
mpfr_init_set_z(real, this->u_.int_val, GMP_RNDN);
+ mpfr_init_set_ui(imag, 0, GMP_RNDN);
break;
case NC_FLOAT:
mpfr_init_set(real, this->u_.float_val, GMP_RNDN);
+ mpfr_init_set_ui(imag, 0, GMP_RNDN);
break;
case NC_COMPLEX:
- if (!mpfr_nan_p(this->u_.complex_val.imag)
- && !mpfr_inf_p(this->u_.complex_val.imag)
- && !mpfr_zero_p(this->u_.complex_val.imag))
- {
- if (mpfr_get_exp(this->u_.complex_val.imag) > max_exp)
- {
- if (issue_error)
- error_at(location, "complex imaginary part overflow");
- return false;
- }
- }
mpfr_init_set(real, this->u_.complex_val.real, GMP_RNDN);
+ mpfr_init_set(imag, this->u_.complex_val.imag, GMP_RNDN);
break;
default:
go_unreachable();
}
- bool ret;
- if (mpfr_nan_p(real) || mpfr_inf_p(real) || mpfr_zero_p(real))
- ret = true;
- else
- ret = mpfr_get_exp(real) <= max_exp;
+ bool ret = true;
+ if (!mpfr_nan_p(real)
+ && !mpfr_inf_p(real)
+ && !mpfr_zero_p(real)
+ && mpfr_get_exp(real) > max_exp)
+ {
+ if (issue_error)
+ error_at(location, "complex real part overflow");
+ ret = false;
+ }
- mpfr_clear(real);
+ if (!mpfr_nan_p(imag)
+ && !mpfr_inf_p(imag)
+ && !mpfr_zero_p(imag)
+ && mpfr_get_exp(imag) > max_exp)
+ {
+ if (issue_error)
+ error_at(location, "complex imaginary part overflow");
+ ret = false;
+ }
- if (!ret && issue_error)
- error_at(location, "complex real part overflow");
+ if (ret)
+ {
+ // Round the constant to the desired type.
+ mpfr_t t;
+ mpfr_init(t);
+ switch (type->bits())
+ {
+ case 64:
+ mpfr_set_prec(t, 24);
+ break;
+ case 128:
+ mpfr_set_prec(t, 53);
+ break;
+ default:
+ go_unreachable();
+ }
+ mpfr_set(t, real, GMP_RNDN);
+ mpfr_set(real, t, GMP_RNDN);
+ mpfr_set(t, imag, GMP_RNDN);
+ mpfr_set(imag, t, GMP_RNDN);
+ mpfr_clear(t);
+
+ this->set_complex(type, real, imag);
+ }
+
+ mpfr_clear(real);
+ mpfr_clear(imag);
return ret;
}
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index eea141fe776..1b74b801748 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -360,10 +360,11 @@ class Expression
// This is called if the value of this expression is being
// discarded. This issues warnings about computed values being
- // unused.
- void
+ // unused. This returns true if all is well, false if it issued an
+ // error message.
+ bool
discarding_value()
- { this->do_discarding_value(); }
+ { return this->do_discarding_value(); }
// Return whether this is an error expression.
bool
@@ -689,7 +690,7 @@ class Expression
{ return false; }
// Called by the parser if the value is being discarded.
- virtual void
+ virtual bool
do_discarding_value();
// Child class holds type.
@@ -1205,7 +1206,7 @@ class Binary_expression : public Expression
bool
do_numeric_constant_value(Numeric_constant*) const;
- void
+ bool
do_discarding_value();
Type*
@@ -1373,9 +1374,9 @@ class Call_expression : public Expression
virtual Expression*
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
- void
+ bool
do_discarding_value()
- { }
+ { return true; }
virtual Type*
do_type();
@@ -2051,9 +2052,9 @@ class Receive_expression : public Expression
do_traverse(Traverse* traverse)
{ return Expression::traverse(&this->channel_, traverse); }
- void
+ bool
do_discarding_value()
- { }
+ { return true; }
Type*
do_type();
@@ -2219,10 +2220,10 @@ class Numeric_constant
check_int_type(Integer_type*, bool, Location) const;
bool
- check_float_type(Float_type*, bool, Location) const;
+ check_float_type(Float_type*, bool, Location);
bool
- check_complex_type(Complex_type*, bool, Location) const;
+ check_complex_type(Complex_type*, bool, Location);
// The kinds of constants.
enum Classification
diff --git a/gcc/go/gofrontend/go.cc b/gcc/go/gofrontend/go.cc
index 1f2ce8adcde..11692af8095 100644
--- a/gcc/go/gofrontend/go.cc
+++ b/gcc/go/gofrontend/go.cc
@@ -21,7 +21,7 @@ static Gogo* gogo;
GO_EXTERN_C
void
go_create_gogo(int int_type_size, int pointer_size, const char *pkgpath,
- const char *prefix)
+ const char *prefix, const char *relative_import_path)
{
go_assert(::gogo == NULL);
Linemap* linemap = go_get_linemap();
@@ -32,6 +32,9 @@ go_create_gogo(int int_type_size, int pointer_size, const char *pkgpath,
else if (prefix != NULL)
::gogo->set_prefix(prefix);
+ if (relative_import_path != NULL)
+ ::gogo->set_relative_import_path(relative_import_path);
+
// FIXME: This should be in the gcc dependent code.
::gogo->define_builtin_function_trees();
}
diff --git a/gcc/go/gofrontend/gogo-tree.cc b/gcc/go/gofrontend/gogo-tree.cc
index c746b9b1ee5..ad38e59d6f3 100644
--- a/gcc/go/gofrontend/gogo-tree.cc
+++ b/gcc/go/gofrontend/gogo-tree.cc
@@ -1002,9 +1002,19 @@ Named_object::get_id(Gogo* gogo)
}
if (this->is_type())
{
- const Named_object* in_function = this->type_value()->in_function();
+ unsigned int index;
+ const Named_object* in_function = this->type_value()->in_function(&index);
if (in_function != NULL)
- decl_name += '$' + Gogo::unpack_hidden_name(in_function->name());
+ {
+ decl_name += '$' + Gogo::unpack_hidden_name(in_function->name());
+ if (index > 0)
+ {
+ char buf[30];
+ snprintf(buf, sizeof buf, "%u", index);
+ decl_name += '$';
+ decl_name += buf;
+ }
+ }
}
return get_identifier_from_string(decl_name);
}
@@ -2133,8 +2143,7 @@ Gogo::slice_constructor(tree slice_type_tree, tree values, tree count,
tree
Gogo::interface_method_table_for_type(const Interface_type* interface,
- Named_type* type,
- bool is_pointer)
+ Type* type, bool is_pointer)
{
const Typed_identifier_list* interface_methods = interface->methods();
go_assert(!interface_methods->empty());
@@ -2163,7 +2172,9 @@ Gogo::interface_method_table_for_type(const Interface_type* interface,
// interface. If the interface has hidden methods, and the named
// type is defined in a different package, then the interface
// conversion table will be defined by that other package.
- if (has_hidden_methods && type->named_object()->package() != NULL)
+ if (has_hidden_methods
+ && type->named_type() != NULL
+ && type->named_type()->named_object()->package() != NULL)
{
tree array_type = build_array_type(const_ptr_type_node, NULL);
tree decl = build_decl(BUILTINS_LOCATION, VAR_DECL, id, array_type);
@@ -2191,13 +2202,20 @@ Gogo::interface_method_table_for_type(const Interface_type* interface,
Linemap::predeclared_location());
elt->value = fold_convert(const_ptr_type_node, tdp);
+ Named_type* nt = type->named_type();
+ Struct_type* st = type->struct_type();
+ go_assert(nt != NULL || st != NULL);
size_t i = 1;
for (Typed_identifier_list::const_iterator p = interface_methods->begin();
p != interface_methods->end();
++p, ++i)
{
bool is_ambiguous;
- Method* m = type->method_function(p->name(), &is_ambiguous);
+ Method* m;
+ if (nt != NULL)
+ m = nt->method_function(p->name(), &is_ambiguous);
+ else
+ m = st->method_function(p->name(), &is_ambiguous);
go_assert(m != NULL);
Named_object* no = m->named_object();
diff --git a/gcc/go/gofrontend/gogo.cc b/gcc/go/gofrontend/gogo.cc
index 6e9b8c124aa..c0aa496acc3 100644
--- a/gcc/go/gofrontend/gogo.cc
+++ b/gcc/go/gofrontend/gogo.cc
@@ -6,6 +6,8 @@
#include "go-system.h"
+#include "filenames.h"
+
#include "go-c.h"
#include "go-dump.h"
#include "lex.h"
@@ -42,6 +44,7 @@ Gogo::Gogo(Backend* backend, Linemap* linemap, int int_type_size,
pkgpath_set_(false),
pkgpath_from_option_(false),
prefix_from_option_(false),
+ relative_import_path_(),
verify_types_(),
interface_types_(),
specific_type_functions_(),
@@ -385,6 +388,57 @@ Gogo::import_package(const std::string& filename,
bool is_local_name_exported,
Location location)
{
+ if (filename.empty())
+ {
+ error_at(location, "import path is empty");
+ return;
+ }
+
+ const char *pf = filename.data();
+ const char *pend = pf + filename.length();
+ while (pf < pend)
+ {
+ unsigned int c;
+ int adv = Lex::fetch_char(pf, &c);
+ if (adv == 0)
+ {
+ error_at(location, "import path contains invalid UTF-8 sequence");
+ return;
+ }
+ if (c == '\0')
+ {
+ error_at(location, "import path contains NUL");
+ return;
+ }
+ if (c < 0x20 || c == 0x7f)
+ {
+ error_at(location, "import path contains control character");
+ return;
+ }
+ if (c == '\\')
+ {
+ error_at(location, "import path contains backslash; use slash");
+ return;
+ }
+ if (Lex::is_unicode_space(c))
+ {
+ error_at(location, "import path contains space character");
+ return;
+ }
+ if (c < 0x7f && strchr("!\"#$%&'()*,:;<=>?[]^`{|}", c) != NULL)
+ {
+ error_at(location, "import path contains invalid character '%c'", c);
+ return;
+ }
+ pf += adv;
+ }
+
+ if (IS_ABSOLUTE_PATH(filename.c_str()))
+ {
+ error_at(location, "import path cannot be absolute path");
+ return;
+ }
+
if (filename == "unsafe")
{
this->import_unsafe(local_name, is_local_name_exported, location);
@@ -424,7 +478,8 @@ Gogo::import_package(const std::string& filename,
return;
}
- Import::Stream* stream = Import::open_package(filename, location);
+ Import::Stream* stream = Import::open_package(filename, location,
+ this->relative_import_path_);
if (stream == NULL)
{
error_at(location, "import file %qs not found", filename.c_str());
@@ -1003,7 +1058,15 @@ Gogo::add_type(const std::string& name, Type* type, Location location)
Named_object* no = this->current_bindings()->add_type(name, NULL, type,
location);
if (!this->in_global_scope() && no->is_type())
- no->type_value()->set_in_function(this->functions_.back().function);
+ {
+ Named_object* f = this->functions_.back().function;
+ unsigned int index;
+ if (f->is_function())
+ index = f->func_value()->new_local_type_index();
+ else
+ index = 0;
+ no->type_value()->set_in_function(f, index);
+ }
}
// Add a named type.
@@ -1025,7 +1088,12 @@ Gogo::declare_type(const std::string& name, Location location)
if (!this->in_global_scope() && no->is_type_declaration())
{
Named_object* f = this->functions_.back().function;
- no->type_declaration_value()->set_in_function(f);
+ unsigned int index;
+ if (f->is_function())
+ index = f->func_value()->new_local_type_index();
+ else
+ index = 0;
+ no->type_declaration_value()->set_in_function(f, index);
}
return no;
}
@@ -2806,7 +2874,8 @@ int
Build_method_tables::type(Type* type)
{
Named_type* nt = type->named_type();
- if (nt != NULL)
+ Struct_type* st = type->struct_type();
+ if (nt != NULL || st != NULL)
{
for (std::vector<Interface_type*>::const_iterator p =
this->interfaces_.begin();
@@ -2816,10 +2885,23 @@ Build_method_tables::type(Type* type)
// We ask whether a pointer to the named type implements the
// interface, because a pointer can implement more methods
// than a value.
- if ((*p)->implements_interface(Type::make_pointer_type(nt), NULL))
+ if (nt != NULL)
+ {
+ if ((*p)->implements_interface(Type::make_pointer_type(nt),
+ NULL))
+ {
+ nt->interface_method_table(this->gogo_, *p, false);
+ nt->interface_method_table(this->gogo_, *p, true);
+ }
+ }
+ else
{
- nt->interface_method_table(this->gogo_, *p, false);
- nt->interface_method_table(this->gogo_, *p, true);
+ if ((*p)->implements_interface(Type::make_pointer_type(st),
+ NULL))
+ {
+ st->interface_method_table(this->gogo_, *p, false);
+ st->interface_method_table(this->gogo_, *p, true);
+ }
}
}
}
@@ -2989,9 +3071,10 @@ Gogo::convert_named_types_in_bindings(Bindings* bindings)
Function::Function(Function_type* type, Function* enclosing, Block* block,
Location location)
: type_(type), enclosing_(enclosing), results_(NULL),
- closure_var_(NULL), block_(block), location_(location), fndecl_(NULL),
- defer_stack_(NULL), results_are_named_(false), calls_recover_(false),
- is_recover_thunk_(false), has_recover_thunk_(false)
+ closure_var_(NULL), block_(block), location_(location), labels_(),
+ local_type_count_(0), fndecl_(NULL), defer_stack_(NULL),
+ results_are_named_(false), calls_recover_(false), is_recover_thunk_(false),
+ has_recover_thunk_(false)
{
}
@@ -4157,7 +4240,7 @@ Variable::determine_type()
else if (type->is_call_multiple_result_type())
{
error_at(this->location_,
- "single variable set to multiple value function call");
+ "single variable set to multiple-value function call");
type = Type::make_error_type();
}
@@ -4599,9 +4682,10 @@ Named_object::set_type_value(Named_type* named_type)
go_assert(this->classification_ == NAMED_OBJECT_TYPE_DECLARATION);
Type_declaration* td = this->u_.type_declaration;
td->define_methods(named_type);
- Named_object* in_function = td->in_function();
+ unsigned int index;
+ Named_object* in_function = td->in_function(&index);
if (in_function != NULL)
- named_type->set_in_function(in_function);
+ named_type->set_in_function(in_function, index);
delete td;
this->classification_ = NAMED_OBJECT_TYPE;
this->u_.type_value = named_type;
diff --git a/gcc/go/gofrontend/gogo.h b/gcc/go/gofrontend/gogo.h
index deb9968e84f..cc707ad2dde 100644
--- a/gcc/go/gofrontend/gogo.h
+++ b/gcc/go/gofrontend/gogo.h
@@ -206,6 +206,17 @@ class Gogo
pkgpath_from_option() const
{ return this->pkgpath_from_option_; }
+ // Return the relative import path as set from the command line.
+ // Returns an empty string if it was not set.
+ const std::string&
+ relative_import_path() const
+ { return this->relative_import_path_; }
+
+ // Set the relative import path from a command line option.
+ void
+ set_relative_import_path(const std::string& s)
+ {this->relative_import_path_ = s; }
+
// Return the priority to use for the package we are compiling.
// This is two more than the largest priority of any package we
// import.
@@ -574,7 +585,7 @@ class Gogo
// Build an interface method table for a type: a list of function
// pointers, one for each interface method. This returns a decl.
tree
- interface_method_table_for_type(const Interface_type*, Named_type*,
+ interface_method_table_for_type(const Interface_type*, Type*,
bool is_pointer);
// Return a tree which allocate SIZE bytes to hold values of type
@@ -732,6 +743,9 @@ class Gogo
bool pkgpath_from_option_;
// Whether an explicit prefix was set by -fgo-prefix.
bool prefix_from_option_;
+ // The relative import path, from the -fgo-relative-import-path
+ // option.
+ std::string relative_import_path_;
// A list of types to verify.
std::vector<Type*> verify_types_;
// A list of interface types defined while parsing.
@@ -963,6 +977,11 @@ class Function
void
check_labels() const;
+ // Note that a new local type has been added. Return its index.
+ unsigned int
+ new_local_type_index()
+ { return this->local_type_count_++; }
+
// Whether this function calls the predeclared recover function.
bool
calls_recover() const
@@ -1084,6 +1103,8 @@ class Function
Location location_;
// Labels defined or referenced in the function.
Labels labels_;
+ // The number of local types defined in this function.
+ unsigned int local_type_count_;
// The function decl.
tree fndecl_;
// The defer stack variable. A pointer to this variable is used to
@@ -1638,8 +1659,8 @@ class Type_declaration
{
public:
Type_declaration(Location location)
- : location_(location), in_function_(NULL), methods_(),
- issued_warning_(false)
+ : location_(location), in_function_(NULL), in_function_index_(0),
+ methods_(), issued_warning_(false)
{ }
// Return the location.
@@ -1650,13 +1671,19 @@ class Type_declaration
// Return the function in which this type is declared. This will
// return NULL for a type declared in global scope.
Named_object*
- in_function()
- { return this->in_function_; }
+ in_function(unsigned int* pindex)
+ {
+ *pindex = this->in_function_index_;
+ return this->in_function_;
+ }
// Set the function in which this type is declared.
void
- set_in_function(Named_object* f)
- { this->in_function_ = f; }
+ set_in_function(Named_object* f, unsigned int index)
+ {
+ this->in_function_ = f;
+ this->in_function_index_ = index;
+ }
// Add a method to this type. This is used when methods are defined
// before the type.
@@ -1689,6 +1716,8 @@ class Type_declaration
// If this type is declared in a function, a pointer back to the
// function in which it is defined.
Named_object* in_function_;
+ // The index of this type in IN_FUNCTION_.
+ unsigned int in_function_index_;
// Methods defined before the type is defined.
Methods methods_;
// True if we have issued a warning about a use of this type
diff --git a/gcc/go/gofrontend/import.cc b/gcc/go/gofrontend/import.cc
index 9febf231897..4913100b5fd 100644
--- a/gcc/go/gofrontend/import.cc
+++ b/gcc/go/gofrontend/import.cc
@@ -41,6 +41,9 @@ go_add_search_path(const char* path)
// When FILENAME is not an absolute path and does not start with ./ or
// ../, we use the search path provided by -I and -L options.
+// When FILENAME does start with ./ or ../, we use
+// RELATIVE_IMPORT_PATH as a prefix.
+
// When FILENAME does not exist, we try modifying FILENAME to find the
// file. We use the first of these which exists:
// * We append ".gox".
@@ -55,19 +58,35 @@ go_add_search_path(const char* path)
// later in the search path.
Import::Stream*
-Import::open_package(const std::string& filename, Location location)
+Import::open_package(const std::string& filename, Location location,
+ const std::string& relative_import_path)
{
bool is_local;
if (IS_ABSOLUTE_PATH(filename))
is_local = true;
- else if (filename[0] == '.' && IS_DIR_SEPARATOR(filename[1]))
+ else if (filename[0] == '.'
+ && (filename[1] == '\0' || IS_DIR_SEPARATOR(filename[1])))
is_local = true;
else if (filename[0] == '.'
&& filename[1] == '.'
- && IS_DIR_SEPARATOR(filename[2]))
+ && (filename[2] == '\0' || IS_DIR_SEPARATOR(filename[2])))
is_local = true;
else
is_local = false;
+
+ std::string fn = filename;
+ if (is_local && !IS_ABSOLUTE_PATH(filename) && !relative_import_path.empty())
+ {
+ if (fn == ".")
+ {
+ // A special case.
+ fn = relative_import_path;
+ }
+ else
+ fn = relative_import_path + '/' + fn;
+ is_local = false;
+ }
+
if (!is_local)
{
for (std::vector<std::string>::const_iterator p = search_path.begin();
@@ -77,14 +96,14 @@ Import::open_package(const std::string& filename, Location location)
std::string indir = *p;
if (!indir.empty() && indir[indir.size() - 1] != '/')
indir += '/';
- indir += filename;
+ indir += fn;
Stream* s = Import::try_package_in_directory(indir, location);
if (s != NULL)
return s;
}
}
- Stream* s = Import::try_package_in_directory(filename, location);
+ Stream* s = Import::try_package_in_directory(fn, location);
if (s != NULL)
return s;
diff --git a/gcc/go/gofrontend/import.h b/gcc/go/gofrontend/import.h
index 67bdcb02d57..c6844cda8a5 100644
--- a/gcc/go/gofrontend/import.h
+++ b/gcc/go/gofrontend/import.h
@@ -124,8 +124,10 @@ class Import
// 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. LOCATION is the location of the import statement.
+ // RELATIVE_IMPORT_PATH is used as a prefix for a relative import.
static Stream*
- open_package(const std::string& filename, Location location);
+ open_package(const std::string& filename, Location location,
+ const std::string& relative_import_path);
// Constructor.
Import(Stream*, Location);
diff --git a/gcc/go/gofrontend/lex.cc b/gcc/go/gofrontend/lex.cc
index 5b7ce6869e6..6add84ed1f7 100644
--- a/gcc/go/gofrontend/lex.cc
+++ b/gcc/go/gofrontend/lex.cc
@@ -722,7 +722,16 @@ Lex::next_token()
unsigned int ci;
bool issued_error;
this->lineoff_ = p - this->linebuf_;
- this->advance_one_utf8_char(p, &ci, &issued_error);
+ const char *pnext = this->advance_one_utf8_char(p, &ci,
+ &issued_error);
+
+ // Ignore byte order mark at start of file.
+ if (ci == 0xfeff)
+ {
+ p = pnext;
+ break;
+ }
+
if (Lex::is_unicode_letter(ci))
return this->gather_identifier();
@@ -831,6 +840,14 @@ Lex::advance_one_utf8_char(const char* p, unsigned int* value,
*issued_error = true;
return p + 1;
}
+
+ // Warn about byte order mark, except at start of file.
+ if (*value == 0xfeff && (this->lineno_ != 1 || this->lineoff_ != 0))
+ {
+ error_at(this->location(), "Unicode (UTF-8) BOM in middle of file");
+ *issued_error = true;
+ }
+
return p + adv;
}
@@ -1295,6 +1312,12 @@ Lex::append_char(unsigned int v, bool is_character, std::string* str,
// Turn it into the "replacement character".
v = 0xfffd;
}
+ if (v >= 0xd800 && v < 0xe000)
+ {
+ warning_at(location, 0,
+ "unicode code point 0x%x is invalid surrogate pair", v);
+ v = 0xfffd;
+ }
if (v <= 0xffff)
{
buf[0] = 0xe0 + (v >> 12);
@@ -1705,6 +1728,27 @@ struct Unicode_range
unsigned int stride;
};
+// A table of whitespace characters--Unicode code points classified as
+// "Space", "C" locale whitespace characters, the "next line" control
+// character (0085), the line separator (2028), the paragraph
+// separator (2029), and the "zero-width non-break space" (feff).
+
+static const Unicode_range unicode_space[] =
+{
+ { 0x0009, 0x000d, 1 },
+ { 0x0020, 0x0020, 1 },
+ { 0x0085, 0x0085, 1 },
+ { 0x00a0, 0x00a0, 1 },
+ { 0x1680, 0x1680, 1 },
+ { 0x180e, 0x180e, 1 },
+ { 0x2000, 0x200a, 1 },
+ { 0x2028, 0x2029, 1 },
+ { 0x202f, 0x202f, 1 },
+ { 0x205f, 0x205f, 1 },
+ { 0x3000, 0x3000, 1 },
+ { 0xfeff, 0xfeff, 1 },
+};
+
// A table of Unicode digits--Unicode code points classified as
// "Digit".
@@ -2294,6 +2338,15 @@ Lex::is_in_unicode_range(unsigned int c, const Unicode_range* ranges,
}
}
+// Return whether C is a space character.
+
+bool
+Lex::is_unicode_space(unsigned int c)
+{
+ return Lex::is_in_unicode_range(c, unicode_space,
+ ARRAY_SIZE(unicode_space));
+}
+
// Return whether C is a Unicode digit--a Unicode code point
// classified as "Digit".
diff --git a/gcc/go/gofrontend/lex.h b/gcc/go/gofrontend/lex.h
index 8858e73d97a..074bbaea4ed 100644
--- a/gcc/go/gofrontend/lex.h
+++ b/gcc/go/gofrontend/lex.h
@@ -375,6 +375,10 @@ class Lex
static int
fetch_char(const char* str, unsigned int *value);
+ // Return whether C is a Unicode or "C" locale space character.
+ static bool
+ is_unicode_space(unsigned int c);
+
private:
ssize_t
get_line();
diff --git a/gcc/go/gofrontend/parse.cc b/gcc/go/gofrontend/parse.cc
index 29323f05c6c..c65325d016e 100644
--- a/gcc/go/gofrontend/parse.cc
+++ b/gcc/go/gofrontend/parse.cc
@@ -1631,12 +1631,16 @@ Parse::init_vars(const Typed_identifier_list* til, Type* type,
// Note that INIT was already parsed with the old name bindings, so
// we don't have to worry that it will accidentally refer to the
- // newly declared variables.
+ // newly declared variables. But we do have to worry about a mix of
+ // newly declared variables and old variables if the old variables
+ // appear in the initializations.
Expression_list::const_iterator pexpr;
if (init != NULL)
pexpr = init->begin();
bool any_new = false;
+ Expression_list* vars = new Expression_list();
+ Expression_list* vals = new Expression_list();
for (Typed_identifier_list::const_iterator p = til->begin();
p != til->end();
++p)
@@ -1644,7 +1648,7 @@ Parse::init_vars(const Typed_identifier_list* til, Type* type,
if (init != NULL)
go_assert(pexpr != init->end());
this->init_var(*p, type, init == NULL ? NULL : *pexpr, is_coloneq,
- false, &any_new);
+ false, &any_new, vars, vals);
if (init != NULL)
++pexpr;
}
@@ -1652,6 +1656,7 @@ Parse::init_vars(const Typed_identifier_list* til, Type* type,
go_assert(pexpr == init->end());
if (is_coloneq && !any_new)
error_at(location, "variables redeclared but no variable is new");
+ this->finish_init_vars(vars, vals, location);
}
// See if we need to initialize a list of variables from a function
@@ -1674,13 +1679,15 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
Named_object* first_var = NULL;
unsigned int index = 0;
bool any_new = false;
+ Expression_list* ivars = new Expression_list();
+ Expression_list* ivals = new Expression_list();
for (Typed_identifier_list::const_iterator pv = vars->begin();
pv != vars->end();
++pv, ++index)
{
Expression* init = Expression::make_call_result(call, index);
Named_object* no = this->init_var(*pv, type, init, is_coloneq, false,
- &any_new);
+ &any_new, ivars, ivals);
if (this->gogo_->in_global_scope() && no->is_variable())
{
@@ -1700,6 +1707,8 @@ Parse::init_vars_from_call(const Typed_identifier_list* vars, Type* type,
if (is_coloneq && !any_new)
error_at(location, "variables redeclared but no variable is new");
+ this->finish_init_vars(ivars, ivals, location);
+
return true;
}
@@ -1725,7 +1734,7 @@ Parse::init_vars_from_map(const Typed_identifier_list* vars, Type* type,
Typed_identifier_list::const_iterator p = vars->begin();
Expression* init = type == NULL ? index : NULL;
Named_object* val_no = this->init_var(*p, type, init, is_coloneq,
- type == NULL, &any_new);
+ type == NULL, &any_new, NULL, NULL);
if (type == NULL && any_new && val_no->is_variable())
val_no->var_value()->set_type_from_init_tuple();
Expression* val_var = Expression::make_var_reference(val_no, location);
@@ -1735,7 +1744,7 @@ Parse::init_vars_from_map(const Typed_identifier_list* vars, Type* type,
if (var_type == NULL)
var_type = Type::lookup_bool_type();
Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false,
- &any_new);
+ &any_new, NULL, NULL);
Expression* present_var = Expression::make_var_reference(no, location);
if (is_coloneq && !any_new)
@@ -1790,7 +1799,7 @@ Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type,
Typed_identifier_list::const_iterator p = vars->begin();
Expression* init = type == NULL ? receive : NULL;
Named_object* val_no = this->init_var(*p, type, init, is_coloneq,
- type == NULL, &any_new);
+ type == NULL, &any_new, NULL, NULL);
if (type == NULL && any_new && val_no->is_variable())
val_no->var_value()->set_type_from_init_tuple();
Expression* val_var = Expression::make_var_reference(val_no, location);
@@ -1800,7 +1809,7 @@ Parse::init_vars_from_receive(const Typed_identifier_list* vars, Type* type,
if (var_type == NULL)
var_type = Type::lookup_bool_type();
Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false,
- &any_new);
+ &any_new, NULL, NULL);
Expression* received_var = Expression::make_var_reference(no, location);
if (is_coloneq && !any_new)
@@ -1857,7 +1866,7 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
if (var_type == NULL)
var_type = type_guard->type();
Named_object* val_no = this->init_var(*p, var_type, NULL, is_coloneq, false,
- &any_new);
+ &any_new, NULL, NULL);
Expression* val_var = Expression::make_var_reference(val_no, location);
++p;
@@ -1865,7 +1874,7 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
if (var_type == NULL)
var_type = Type::lookup_bool_type();
Named_object* no = this->init_var(*p, var_type, NULL, is_coloneq, false,
- &any_new);
+ &any_new, NULL, NULL);
Expression* ok_var = Expression::make_var_reference(no, location);
Expression* texpr = type_guard->expr();
@@ -1904,7 +1913,8 @@ Parse::init_vars_from_type_guard(const Typed_identifier_list* vars,
Named_object*
Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init,
- bool is_coloneq, bool type_from_init, bool* is_new)
+ bool is_coloneq, bool type_from_init, bool* is_new,
+ Expression_list* vars, Expression_list* vals)
{
Location location = tid.location();
@@ -1946,9 +1956,9 @@ Parse::init_var(const Typed_identifier& tid, Type* type, Expression* init,
// like v, ok := x.(int).
if (!type_from_init && init != NULL)
{
- Expression *v = Expression::make_var_reference(no, location);
- Statement *s = Statement::make_assignment(v, init, location);
- this->gogo_->add_statement(s);
+ go_assert(vars != NULL && vals != NULL);
+ vars->push_back(Expression::make_var_reference(no, location));
+ vals->push_back(init);
}
return no;
}
@@ -1983,6 +1993,36 @@ Parse::create_dummy_global(Type* type, Expression* init,
return this->gogo_->add_variable(buf, var);
}
+// Finish the variable initialization by executing any assignments to
+// existing variables when using :=. These must be done as a tuple
+// assignment in case of something like n, a, b := 1, b, a.
+
+void
+Parse::finish_init_vars(Expression_list* vars, Expression_list* vals,
+ Location location)
+{
+ if (vars->empty())
+ {
+ delete vars;
+ delete vals;
+ }
+ else if (vars->size() == 1)
+ {
+ go_assert(!this->gogo_->in_global_scope());
+ this->gogo_->add_statement(Statement::make_assignment(vars->front(),
+ vals->front(),
+ location));
+ delete vars;
+ delete vals;
+ }
+ else
+ {
+ go_assert(!this->gogo_->in_global_scope());
+ this->gogo_->add_statement(Statement::make_tuple_assignment(vars, vals,
+ location));
+ }
+}
+
// SimpleVarDecl = identifier ":=" Expression .
// We've already seen the identifier.
@@ -2723,7 +2763,11 @@ Parse::composite_lit(Type* type, int depth, Location location)
}
else
{
- error_at(this->location(), "expected %<,%> or %<}%>");
+ if (token->is_op(OPERATOR_SEMICOLON))
+ error_at(this->location(),
+ "need trailing comma before newline in composite literal");
+ else
+ error_at(this->location(), "expected %<,%> or %<}%>");
this->gogo_->mark_locals_used();
int depth = 0;
@@ -2911,6 +2955,8 @@ Parse::primary_expr(bool may_be_sink, bool may_be_composite_lit,
this->advance_token();
Expression* expr = this->expression(PRECEDENCE_NORMAL, false, true,
NULL);
+ if (this->peek_token()->is_op(OPERATOR_COMMA))
+ this->advance_token();
if (this->peek_token()->is_op(OPERATOR_ELLIPSIS))
{
error_at(this->location(),
@@ -3311,6 +3357,61 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
bool* is_type_switch)
{
const Token* token = this->peek_token();
+
+ // There is a complex parse for <- chan. The choices are
+ // Convert x to type <- chan int:
+ // (<- chan int)(x)
+ // Receive from (x converted to type chan <- chan int):
+ // (<- chan <- chan int (x))
+ // Convert x to type <- chan (<- chan int).
+ // (<- chan <- chan int)(x)
+ if (token->is_op(OPERATOR_CHANOP))
+ {
+ Location location = token->location();
+ if (this->advance_token()->is_keyword(KEYWORD_CHAN))
+ {
+ Expression* expr = this->primary_expr(false, may_be_composite_lit,
+ NULL);
+ if (expr->is_error_expression())
+ return expr;
+ else if (!expr->is_type_expression())
+ return Expression::make_receive(expr, location);
+ else
+ {
+ if (expr->type()->is_error_type())
+ return expr;
+
+ // We picked up "chan TYPE", but it is not a type
+ // conversion.
+ Channel_type* ct = expr->type()->channel_type();
+ if (ct == NULL)
+ {
+ // This is probably impossible.
+ error_at(location, "expected channel type");
+ return Expression::make_error(location);
+ }
+ else if (ct->may_receive())
+ {
+ // <- chan TYPE.
+ Type* t = Type::make_channel_type(false, true,
+ ct->element_type());
+ return Expression::make_type(t, location);
+ }
+ else
+ {
+ // <- chan <- TYPE. Because we skipped the leading
+ // <-, we parsed this as chan <- TYPE. With the
+ // leading <-, we parse it as <- chan (<- TYPE).
+ Type *t = this->reassociate_chan_direction(ct, location);
+ return Expression::make_type(t, location);
+ }
+ }
+ }
+
+ this->unget_token(Token::make_operator_token(OPERATOR_CHANOP, location));
+ token = this->peek_token();
+ }
+
if (token->is_op(OPERATOR_PLUS)
|| token->is_op(OPERATOR_MINUS)
|| token->is_op(OPERATOR_NOT)
@@ -3323,14 +3424,6 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
Operator op = token->op();
this->advance_token();
- if (op == OPERATOR_CHANOP
- && this->peek_token()->is_keyword(KEYWORD_CHAN))
- {
- // This is "<- chan" which must be the start of a type.
- this->unget_token(Token::make_operator_token(op, location));
- return Expression::make_type(this->type(), location);
- }
-
Expression* expr = this->unary_expr(false, may_be_composite_lit, NULL);
if (expr->is_error_expression())
;
@@ -3350,6 +3443,32 @@ Parse::unary_expr(bool may_be_sink, bool may_be_composite_lit,
is_type_switch);
}
+// This is called for the obscure case of
+// (<- chan <- chan int)(x)
+// In unary_expr we remove the leading <- and parse the remainder,
+// which gives us
+// chan <- (chan int)
+// When we add the leading <- back in, we really want
+// <- chan (<- chan int)
+// This means that we need to reassociate.
+
+Type*
+Parse::reassociate_chan_direction(Channel_type *ct, Location location)
+{
+ Channel_type* ele = ct->element_type()->channel_type();
+ if (ele == NULL)
+ {
+ error_at(location, "parse error");
+ return Type::make_error_type();
+ }
+ Type* sub = ele;
+ if (ele->may_send())
+ sub = Type::make_channel_type(false, true, ele->element_type());
+ else
+ sub = this->reassociate_chan_direction(ele, location);
+ return Type::make_channel_type(false, true, sub);
+}
+
// Statement =
// Declaration | LabeledStmt | SimpleStmt |
// GoStmt | ReturnStmt | BreakStmt | ContinueStmt | GotoStmt |
@@ -5036,7 +5155,8 @@ Parse::range_clause_decl(const Typed_identifier_list* til,
bool any_new = false;
const Typed_identifier* pti = &til->front();
- Named_object* no = this->init_var(*pti, NULL, expr, true, true, &any_new);
+ Named_object* no = this->init_var(*pti, NULL, expr, true, true, &any_new,
+ NULL, NULL);
if (any_new && no->is_variable())
no->var_value()->set_type_from_range_index();
p_range_clause->index = Expression::make_var_reference(no, location);
@@ -5047,7 +5167,7 @@ Parse::range_clause_decl(const Typed_identifier_list* til,
{
pti = &til->back();
bool is_new = false;
- no = this->init_var(*pti, NULL, expr, true, true, &is_new);
+ no = this->init_var(*pti, NULL, expr, true, true, &is_new, NULL, NULL);
if (is_new && no->is_variable())
no->var_value()->set_type_from_range_value();
if (is_new)
@@ -5337,7 +5457,8 @@ Parse::import_spec(void*)
if (!token->is_string())
{
- error_at(this->location(), "missing import package name");
+ error_at(this->location(), "import statement not a string");
+ this->advance_token();
return;
}
diff --git a/gcc/go/gofrontend/parse.h b/gcc/go/gofrontend/parse.h
index 3139f7e8908..a355b7d2b3b 100644
--- a/gcc/go/gofrontend/parse.h
+++ b/gcc/go/gofrontend/parse.h
@@ -14,6 +14,7 @@ class Named_object;
class Type;
class Typed_identifier;
class Typed_identifier_list;
+class Channel_type;
class Function_type;
class Block;
class Expression;
@@ -205,8 +206,11 @@ class Parse
Expression*, bool is_coloneq,
Location);
Named_object* init_var(const Typed_identifier&, Type*, Expression*,
- bool is_coloneq, bool type_from_init, bool* is_new);
+ bool is_coloneq, bool type_from_init, bool* is_new,
+ Expression_list* vars, Expression_list* vals);
Named_object* create_dummy_global(Type*, Expression*, Location);
+ void finish_init_vars(Expression_list* vars, Expression_list* vals,
+ Location);
void simple_var_decl_or_assignment(const std::string&, Location,
bool may_be_composite_lit,
Range_clause*, Type_switch*);
@@ -229,6 +233,7 @@ class Parse
bool expression_may_start_here();
Expression* unary_expr(bool may_be_sink, bool may_be_composite_lit,
bool* is_type_switch);
+ Type* reassociate_chan_direction(Channel_type*, Location);
Expression* qualified_expr(Expression*, Location);
Expression* id_to_expression(const std::string&, Location);
void statement(Label*);
diff --git a/gcc/go/gofrontend/statements.cc b/gcc/go/gofrontend/statements.cc
index fa7f20836ad..58057f84a56 100644
--- a/gcc/go/gofrontend/statements.cc
+++ b/gcc/go/gofrontend/statements.cc
@@ -2006,6 +2006,8 @@ Thunk_statement::do_determine_types()
void
Thunk_statement::do_check_types(Gogo*)
{
+ if (!this->call_->discarding_value())
+ return;
Call_expression* ce = this->call_->call_expression();
if (ce == NULL)
{
@@ -2471,11 +2473,15 @@ Thunk_statement::build_thunk(Gogo* gogo, const std::string& thunk_name)
Expression_statement* es =
static_cast<Expression_statement*>(call_statement);
Call_expression* ce = es->expr()->call_expression();
- go_assert(ce != NULL);
- if (may_call_recover)
- ce->set_is_deferred();
- if (recover_arg != NULL)
- ce->set_recover_arg(recover_arg);
+ if (ce == NULL)
+ go_assert(saw_errors());
+ else
+ {
+ if (may_call_recover)
+ ce->set_is_deferred();
+ if (recover_arg != NULL)
+ ce->set_recover_arg(recover_arg);
+ }
}
// That is all the thunk has to do.
@@ -3313,16 +3319,10 @@ Case_clauses::Case_clause::lower(Block* b, Temporary_statement* val_temp,
p != this->cases_->end();
++p)
{
- Expression* this_cond;
- if (val_temp == NULL)
- this_cond = *p;
- else
- {
- Expression* ref = Expression::make_temporary_reference(val_temp,
- loc);
- this_cond = Expression::make_binary(OPERATOR_EQEQ, ref, *p, loc);
- }
-
+ Expression* ref = Expression::make_temporary_reference(val_temp,
+ loc);
+ Expression* this_cond = Expression::make_binary(OPERATOR_EQEQ, ref,
+ *p, loc);
if (cond == NULL)
cond = this_cond;
else
@@ -3846,6 +3846,16 @@ Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
return new Constant_switch_statement(this->val_, this->clauses_,
this->break_label_, loc);
+ if (this->val_ != NULL
+ && !this->val_->type()->is_comparable()
+ && !Type::are_compatible_for_comparison(true, this->val_->type(),
+ Type::make_nil_type(), NULL))
+ {
+ error_at(this->val_->location(),
+ "cannot switch on value whose type that may not be compared");
+ return Statement::make_error_statement(loc);
+ }
+
Block* b = new Block(enclosing, loc);
if (this->clauses_->empty())
@@ -3856,15 +3866,12 @@ Switch_statement::do_lower(Gogo*, Named_object*, Block* enclosing,
return Statement::make_statement(val, true);
}
- Temporary_statement* val_temp;
- if (this->val_ == NULL)
- val_temp = NULL;
- else
- {
- // var val_temp VAL_TYPE = VAL
- val_temp = Statement::make_temporary(NULL, this->val_, loc);
- b->add_statement(val_temp);
- }
+ // var val_temp VAL_TYPE = VAL
+ Expression* val = this->val_;
+ if (val == NULL)
+ val = Expression::make_boolean(true, loc);
+ Temporary_statement* val_temp = Statement::make_temporary(NULL, val, loc);
+ b->add_statement(val_temp);
this->clauses_->lower(b, val_temp, this->break_label());
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index 228f3faa4a4..795a1b51026 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -54,8 +54,7 @@ get_backend_interface_fields(Gogo* gogo, Interface_type* type,
// Class Type.
Type::Type(Type_classification classification)
- : classification_(classification), btype_is_placeholder_(false),
- btype_(NULL), type_descriptor_var_(NULL)
+ : classification_(classification), btype_(NULL), type_descriptor_var_(NULL)
{
}
@@ -430,7 +429,7 @@ Type::are_identical(const Type* t1, const Type* t2, bool errors_are_identical,
case TYPE_CALL_MULTIPLE_RESULT:
if (reason != NULL)
- *reason = "invalid use of multiple value function call";
+ *reason = "invalid use of multiple-value function call";
return false;
default:
@@ -588,6 +587,9 @@ Type::are_compatible_for_comparison(bool is_equality_op, const Type *t1,
p != fields->end();
++p)
{
+ if (Gogo::is_sink_name(p->field_name()))
+ continue;
+
if (!p->type()->is_comparable())
{
if (reason != NULL)
@@ -633,8 +635,8 @@ Type::are_assignable_check_hidden(const Type* lhs, const Type* rhs,
if (rhs->is_call_multiple_result_type())
{
if (reason != NULL)
- reason->assign(_("multiple value function call in "
- "single value context"));
+ reason->assign(_("multiple-value function call in "
+ "single-value context"));
return false;
}
}
@@ -916,11 +918,7 @@ Btype*
Type::get_backend(Gogo* gogo)
{
if (this->btype_ != NULL)
- {
- if (this->btype_is_placeholder_ && gogo->named_types_are_converted())
- this->finish_backend(gogo);
- return this->btype_;
- }
+ return this->btype_;
if (this->forward_declaration_type() != NULL
|| this->named_type() != NULL)
@@ -934,20 +932,36 @@ Type::get_backend(Gogo* gogo)
// that. There is no need to use the hash table for named types, as
// named types are only identical to themselves.
- std::pair<Type*, Btype*> val(this, NULL);
+ std::pair<Type*, Type_btype_entry> val;
+ val.first = this;
+ val.second.btype = NULL;
+ val.second.is_placeholder = false;
std::pair<Type_btypes::iterator, bool> ins =
Type::type_btypes.insert(val);
- if (!ins.second && ins.first->second != NULL)
+ if (!ins.second && ins.first->second.btype != NULL)
{
- if (gogo != NULL && gogo->named_types_are_converted())
- this->btype_ = ins.first->second;
- return ins.first->second;
+ // Note that GOGO can be NULL here, but only when the GCC
+ // middle-end is asking for a frontend type. That will only
+ // happen for simple types, which should never require
+ // placeholders.
+ if (!ins.first->second.is_placeholder)
+ this->btype_ = ins.first->second.btype;
+ else if (gogo->named_types_are_converted())
+ {
+ this->finish_backend(gogo, ins.first->second.btype);
+ ins.first->second.is_placeholder = false;
+ }
+
+ return ins.first->second.btype;
}
Btype* bt = this->get_btype_without_hash(gogo);
- if (ins.first->second == NULL)
- ins.first->second = bt;
+ if (ins.first->second.btype == NULL)
+ {
+ ins.first->second.btype = bt;
+ ins.first->second.is_placeholder = false;
+ }
else
{
// We have already created a backend representation for this
@@ -955,10 +969,9 @@ Type::get_backend(Gogo* gogo)
// 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;
+ if (this->btype_ == bt)
+ this->btype_ = ins.first->second.btype;
+ bt = ins.first->second.btype;
}
return bt;
@@ -1025,6 +1038,37 @@ Type::get_backend_placeholder(Gogo* gogo)
// These are simple types that can just be created directly.
return this->get_backend(gogo);
+ case TYPE_MAP:
+ case TYPE_CHANNEL:
+ // All maps and channels have the same backend representation.
+ return this->get_backend(gogo);
+
+ case TYPE_NAMED:
+ case TYPE_FORWARD:
+ // Named types keep track of their own dependencies and manage
+ // their own placeholders.
+ return this->get_backend(gogo);
+
+ case TYPE_INTERFACE:
+ if (this->interface_type()->is_empty())
+ return Interface_type::get_backend_empty_interface_type(gogo);
+ break;
+
+ default:
+ break;
+ }
+
+ std::pair<Type*, Type_btype_entry> val;
+ val.first = this;
+ val.second.btype = NULL;
+ val.second.is_placeholder = false;
+ std::pair<Type_btypes::iterator, bool> ins =
+ Type::type_btypes.insert(val);
+ if (!ins.second && ins.first->second.btype != NULL)
+ return ins.first->second.btype;
+
+ switch (this->classification_)
+ {
case TYPE_FUNCTION:
{
Location loc = this->function_type()->location();
@@ -1067,37 +1111,36 @@ Type::get_backend_placeholder(Gogo* gogo)
}
break;
- case TYPE_MAP:
- case TYPE_CHANNEL:
- // All maps and channels have the same backend representation.
- return this->get_backend(gogo);
-
case TYPE_INTERFACE:
- if (this->interface_type()->is_empty())
- return Interface_type::get_backend_empty_interface_type(gogo);
- else
- {
- std::vector<Backend::Btyped_identifier> bfields;
- get_backend_interface_fields(gogo, this->interface_type(), true,
- &bfields);
- bt = gogo->backend()->struct_type(bfields);
- }
+ {
+ go_assert(!this->interface_type()->is_empty());
+ std::vector<Backend::Btyped_identifier> bfields;
+ get_backend_interface_fields(gogo, this->interface_type(), true,
+ &bfields);
+ bt = gogo->backend()->struct_type(bfields);
+ }
break;
- case TYPE_NAMED:
- case TYPE_FORWARD:
- // Named types keep track of their own dependencies and manage
- // their own placeholders.
- return this->get_backend(gogo);
-
case TYPE_SINK:
case TYPE_CALL_MULTIPLE_RESULT:
+ /* Note that various classifications were handled in the earlier
+ switch. */
default:
go_unreachable();
}
- this->btype_ = bt;
- this->btype_is_placeholder_ = true;
+ if (ins.first->second.btype == NULL)
+ {
+ ins.first->second.btype = bt;
+ ins.first->second.is_placeholder = true;
+ }
+ else
+ {
+ // A placeholder for this type got created along the way. Use
+ // that one and ignore the one we just built.
+ bt = ins.first->second.btype;
+ }
+
return bt;
}
@@ -1105,12 +1148,8 @@ Type::get_backend_placeholder(Gogo* gogo)
// using a placeholder type.
void
-Type::finish_backend(Gogo* gogo)
+Type::finish_backend(Gogo* gogo, Btype *placeholder)
{
- go_assert(this->btype_ != NULL);
- if (!this->btype_is_placeholder_)
- return;
-
switch (this->classification_)
{
case TYPE_ERROR:
@@ -1126,7 +1165,7 @@ Type::finish_backend(Gogo* gogo)
case TYPE_FUNCTION:
{
Btype* bt = this->do_get_backend(gogo);
- if (!gogo->backend()->set_placeholder_function_type(this->btype_, bt))
+ if (!gogo->backend()->set_placeholder_function_type(placeholder, bt))
go_assert(saw_errors());
}
break;
@@ -1134,7 +1173,7 @@ Type::finish_backend(Gogo* gogo)
case TYPE_POINTER:
{
Btype* bt = this->do_get_backend(gogo);
- if (!gogo->backend()->set_placeholder_pointer_type(this->btype_, bt))
+ if (!gogo->backend()->set_placeholder_pointer_type(placeholder, bt))
go_assert(saw_errors());
}
break;
@@ -1171,7 +1210,7 @@ Type::finish_backend(Gogo* gogo)
go_unreachable();
}
- this->btype_is_placeholder_ = false;
+ this->btype_ = placeholder;
}
// Return a pointer to the type descriptor for this type.
@@ -1295,7 +1334,8 @@ Type::type_descriptor_var_name(Gogo* gogo, Named_type* nt)
return "__go_td_" + this->mangled_name(gogo);
Named_object* no = nt->named_object();
- const Named_object* in_function = nt->in_function();
+ unsigned int index;
+ const Named_object* in_function = nt->in_function(&index);
std::string ret = "__go_tdn_";
if (nt->is_builtin())
go_assert(in_function == NULL);
@@ -1310,6 +1350,13 @@ Type::type_descriptor_var_name(Gogo* gogo, Named_type* nt)
{
ret.append(Gogo::unpack_hidden_name(in_function->name()));
ret.append(1, '.');
+ if (index > 0)
+ {
+ char buf[30];
+ snprintf(buf, sizeof buf, "%u", index);
+ ret.append(buf);
+ ret.append(1, '.');
+ }
}
}
@@ -1746,9 +1793,19 @@ Type::specific_type_functions(Gogo* gogo, Named_type* name,
{
// This name is already hidden or not as appropriate.
base_name = name->name();
- const Named_object* in_function = name->in_function();
+ unsigned int index;
+ const Named_object* in_function = name->in_function(&index);
if (in_function != NULL)
- base_name += '$' + Gogo::unpack_hidden_name(in_function->name());
+ {
+ base_name += '$' + Gogo::unpack_hidden_name(in_function->name());
+ if (index > 0)
+ {
+ char buf[30];
+ snprintf(buf, sizeof buf, "%u", index);
+ base_name += '$';
+ base_name += buf;
+ }
+ }
}
std::string hash_name = base_name + "$hash";
std::string equal_name = base_name + "$equal";
@@ -1989,10 +2046,19 @@ Type::uncommon_type_constructor(Gogo* gogo, Type* uncommon_type,
? gogo->pkgpath()
: package->pkgpath());
n.assign(pkgpath);
- if (name->in_function() != NULL)
+ unsigned int index;
+ const Named_object* in_function = name->in_function(&index);
+ if (in_function != NULL)
{
n.append(1, '.');
- n.append(Gogo::unpack_hidden_name(name->in_function()->name()));
+ n.append(Gogo::unpack_hidden_name(in_function->name()));
+ if (index > 0)
+ {
+ char buf[30];
+ snprintf(buf, sizeof buf, "%u", index);
+ n.append(1, '.');
+ n.append(buf);
+ }
}
s = Expression::make_string(n, bloc);
vals->push_back(Expression::make_unary(OPERATOR_AND, s, bloc));
@@ -2361,7 +2427,7 @@ class Error_type : public Type
protected:
bool
- do_compare_is_identity(Gogo*) const
+ do_compare_is_identity(Gogo*)
{ return false; }
Btype*
@@ -2399,7 +2465,7 @@ class Void_type : public Type
protected:
bool
- do_compare_is_identity(Gogo*) const
+ do_compare_is_identity(Gogo*)
{ return false; }
Btype*
@@ -2437,7 +2503,7 @@ class Boolean_type : public Type
protected:
bool
- do_compare_is_identity(Gogo*) const
+ do_compare_is_identity(Gogo*)
{ return true; }
Btype*
@@ -2936,8 +3002,8 @@ String_type::do_get_backend(Gogo* gogo)
// backend representation, so force it to be finished now.
if (!gogo->named_types_are_converted())
{
- pb->get_backend_placeholder(gogo);
- pb->finish_backend(gogo);
+ Btype* bt = pb->get_backend_placeholder(gogo);
+ pb->finish_backend(gogo, bt);
}
fields[0].name = "__data";
@@ -3060,7 +3126,7 @@ class Sink_type : public Type
protected:
bool
- do_compare_is_identity(Gogo*) const
+ do_compare_is_identity(Gogo*)
{ return false; }
Btype*
@@ -3938,7 +4004,7 @@ class Nil_type : public Type
protected:
bool
- do_compare_is_identity(Gogo*) const
+ do_compare_is_identity(Gogo*)
{ return false; }
Btype*
@@ -3989,7 +4055,7 @@ class Call_multiple_result_type : public Type
}
bool
- do_compare_is_identity(Gogo*) const
+ do_compare_is_identity(Gogo*)
{ return false; }
Btype*
@@ -4266,7 +4332,7 @@ Struct_type::struct_has_hidden_fields(const Named_type* within,
// comparisons.
bool
-Struct_type::do_compare_is_identity(Gogo* gogo) const
+Struct_type::do_compare_is_identity(Gogo* gogo)
{
const Struct_field_list* fields = this->fields_;
if (fields == NULL)
@@ -4276,6 +4342,9 @@ Struct_type::do_compare_is_identity(Gogo* gogo) const
pf != fields->end();
++pf)
{
+ if (Gogo::is_sink_name(pf->field_name()))
+ return false;
+
if (!pf->type()->compare_is_identity(gogo))
return false;
@@ -4295,6 +4364,16 @@ Struct_type::do_compare_is_identity(Gogo* gogo) const
return false;
offset += field_size;
}
+
+ unsigned int struct_size;
+ if (!this->backend_type_size(gogo, &struct_size))
+ return false;
+ if (offset != struct_size)
+ {
+ // Trailing padding may not be zero when on the stack.
+ return false;
+ }
+
return true;
}
@@ -4530,6 +4609,20 @@ Struct_type::method_function(const std::string& name, bool* is_ambiguous) const
return Type::method_function(this->all_methods_, name, is_ambiguous);
}
+// Return a pointer to the interface method table for this type for
+// the interface INTERFACE. IS_POINTER is true if this is for a
+// pointer to THIS.
+
+tree
+Struct_type::interface_method_table(Gogo* gogo,
+ const Interface_type* interface,
+ bool is_pointer)
+{
+ return Type::interface_method_table(gogo, this, interface, is_pointer,
+ &this->interface_method_tables_,
+ &this->pointer_interface_method_tables_);
+}
+
// 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.
@@ -4749,6 +4842,9 @@ Struct_type::write_hash_function(Gogo* gogo, Named_type*,
pf != fields->end();
++pf)
{
+ if (Gogo::is_sink_name(pf->field_name()))
+ continue;
+
if (first)
first = false;
else
@@ -4840,6 +4936,9 @@ Struct_type::write_equal_function(Gogo* gogo, Named_type* name)
pf != fields->end();
++pf, ++field_index)
{
+ if (Gogo::is_sink_name(pf->field_name()))
+ continue;
+
// Compare one field in both P1 and P2.
Expression* f1 = Expression::make_temporary_reference(p1, bloc);
f1 = Expression::make_unary(OPERATOR_MULT, f1, bloc);
@@ -4875,14 +4974,15 @@ Struct_type::write_equal_function(Gogo* gogo, Named_type* name)
void
Struct_type::do_reflection(Gogo* gogo, std::string* ret) const
{
- ret->append("struct { ");
+ ret->append("struct {");
for (Struct_field_list::const_iterator p = this->fields_->begin();
p != this->fields_->end();
++p)
{
if (p != this->fields_->begin())
- ret->append("; ");
+ ret->push_back(';');
+ ret->push_back(' ');
if (p->is_anonymous())
ret->push_back('?');
else
@@ -4915,7 +5015,10 @@ Struct_type::do_reflection(Gogo* gogo, std::string* ret) const
}
}
- ret->append(" }");
+ if (!this->fields_->empty())
+ ret->push_back(' ');
+
+ ret->push_back('}');
}
// Mangled name.
@@ -5215,7 +5318,7 @@ Array_type::do_verify()
// Whether we can use memcmp to compare this array.
bool
-Array_type::do_compare_is_identity(Gogo* gogo) const
+Array_type::do_compare_is_identity(Gogo* gogo)
{
if (this->length_ == NULL)
return false;
@@ -6815,7 +6918,8 @@ Interface_type::implements_interface(const Type* t, std::string* reason) const
std::string n = Gogo::message_name(p->name());
size_t len = 100 + n.length();
char* buf = new char[len];
- snprintf(buf, len, _("method %s%s%s requires a pointer"),
+ snprintf(buf, len,
+ _("method %s%s%s requires a pointer receiver"),
open_quote, n.c_str(), close_quote);
reason->assign(buf);
delete[] buf;
@@ -7151,7 +7255,17 @@ Interface_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
if (!p->name().empty())
{
- std::string n = Gogo::unpack_hidden_name(p->name());
+ std::string n;
+ if (!Gogo::is_hidden_name(p->name()))
+ n = p->name();
+ else
+ {
+ n = ".";
+ std::string pkgpath = Gogo::hidden_name_pkgpath(p->name());
+ n.append(Gogo::pkgpath_for_symbol(pkgpath));
+ n.append(1, '.');
+ n.append(Gogo::unpack_hidden_name(p->name()));
+ }
char buf[20];
snprintf(buf, sizeof buf, "%u_",
static_cast<unsigned int>(n.length()));
@@ -7704,32 +7818,9 @@ tree
Named_type::interface_method_table(Gogo* gogo, const Interface_type* interface,
bool is_pointer)
{
- go_assert(!interface->is_empty());
-
- Interface_method_tables** pimt = (is_pointer
- ? &this->interface_method_tables_
- : &this->pointer_interface_method_tables_);
-
- if (*pimt == NULL)
- *pimt = new Interface_method_tables(5);
-
- std::pair<const Interface_type*, tree> val(interface, NULL_TREE);
- std::pair<Interface_method_tables::iterator, bool> ins = (*pimt)->insert(val);
-
- if (ins.second)
- {
- // This is a new entry in the hash table.
- go_assert(ins.first->second == NULL_TREE);
- ins.first->second = gogo->interface_method_table_for_type(interface,
- this,
- is_pointer);
- }
-
- tree decl = ins.first->second;
- if (decl == error_mark_node)
- return error_mark_node;
- go_assert(decl != NULL_TREE && TREE_CODE(decl) == VAR_DECL);
- return build_fold_addr_expr(decl);
+ return Type::interface_method_table(gogo, this, interface, is_pointer,
+ &this->interface_method_tables_,
+ &this->pointer_interface_method_tables_);
}
// Return whether a named type has any hidden fields.
@@ -7922,7 +8013,7 @@ Named_type::do_has_pointer() const
// function.
bool
-Named_type::do_compare_is_identity(Gogo* gogo) const
+Named_type::do_compare_is_identity(Gogo* gogo)
{
// We don't use this->seen_ here because compare_is_identity may
// call base() later, and that will mess up if seen_ is set here.
@@ -8358,8 +8449,17 @@ Named_type::do_reflection(Gogo* gogo, std::string* ret) const
}
if (this->in_function_ != NULL)
{
+ ret->push_back('\t');
ret->append(Gogo::unpack_hidden_name(this->in_function_->name()));
ret->push_back('$');
+ if (this->in_function_index_ > 0)
+ {
+ char buf[30];
+ snprintf(buf, sizeof buf, "%u", this->in_function_index_);
+ ret->append(buf);
+ ret->push_back('$');
+ }
+ ret->push_back('\t');
}
ret->append(Gogo::unpack_hidden_name(this->named_object_->name()));
}
@@ -8389,6 +8489,13 @@ Named_type::do_mangled_name(Gogo* gogo, std::string* ret) const
{
name.append(Gogo::unpack_hidden_name(this->in_function_->name()));
name.append(1, '$');
+ if (this->in_function_index_ > 0)
+ {
+ char buf[30];
+ snprintf(buf, sizeof buf, "%u", this->in_function_index_);
+ name.append(buf);
+ name.append(1, '$');
+ }
}
}
name.append(Gogo::unpack_hidden_name(no->name()));
@@ -8899,6 +9006,42 @@ Type::method_function(const Methods* methods, const std::string& name,
return m;
}
+// Return a pointer to the interface method table for TYPE for the
+// interface INTERFACE.
+
+tree
+Type::interface_method_table(Gogo* gogo, Type* type,
+ const Interface_type *interface,
+ bool is_pointer,
+ Interface_method_tables** method_tables,
+ Interface_method_tables** pointer_tables)
+{
+ go_assert(!interface->is_empty());
+
+ Interface_method_tables** pimt = is_pointer ? method_tables : pointer_tables;
+
+ if (*pimt == NULL)
+ *pimt = new Interface_method_tables(5);
+
+ std::pair<const Interface_type*, tree> val(interface, NULL_TREE);
+ std::pair<Interface_method_tables::iterator, bool> ins = (*pimt)->insert(val);
+
+ if (ins.second)
+ {
+ // This is a new entry in the hash table.
+ go_assert(ins.first->second == NULL_TREE);
+ ins.first->second = gogo->interface_method_table_for_type(interface,
+ type,
+ is_pointer);
+ }
+
+ tree decl = ins.first->second;
+ if (decl == error_mark_node)
+ return error_mark_node;
+ go_assert(decl != NULL_TREE && TREE_CODE(decl) == VAR_DECL);
+ return build_fold_addr_expr(decl);
+}
+
// Look for field or method NAME for TYPE. Return an Expression for
// the field or method bound to EXPR. If there is no such field or
// method, give an appropriate error and return an error expression.
@@ -8990,7 +9133,7 @@ Type::bind_field_or_method(Gogo* gogo, const Type* type, Expression* expr,
Gogo::message_name(name).c_str(), ambig1.c_str(),
ambig2.c_str());
else if (found_pointer_method)
- error_at(location, "method requires a pointer");
+ error_at(location, "method requires a pointer receiver");
else if (nt == NULL && st == NULL && it == NULL)
error_at(location,
("reference to field %qs in object which "
diff --git a/gcc/go/gofrontend/types.h b/gcc/go/gofrontend/types.h
index a542bf71738..bdda7a4280e 100644
--- a/gcc/go/gofrontend/types.h
+++ b/gcc/go/gofrontend/types.h
@@ -576,7 +576,7 @@ class Type
// identity function which gets nothing but a pointer to the value
// and a size.
bool
- compare_is_identity(Gogo* gogo) const
+ compare_is_identity(Gogo* gogo)
{ return this->do_compare_is_identity(gogo); }
// Return a hash code for this type for the method hash table.
@@ -869,7 +869,7 @@ class Type
// Finish the backend representation of a placeholder.
void
- finish_backend(Gogo*);
+ finish_backend(Gogo*, Btype*);
// Build a type descriptor entry for this type. Return a pointer to
// it. The location is the location which causes us to need the
@@ -950,7 +950,7 @@ class Type
{ return false; }
virtual bool
- do_compare_is_identity(Gogo*) const = 0;
+ do_compare_is_identity(Gogo*) = 0;
virtual unsigned int
do_hash_for_method(Gogo*) const;
@@ -983,6 +983,19 @@ class Type
method_function(const Methods*, const std::string& name,
bool* is_ambiguous);
+ // A mapping from interfaces to the associated interface method
+ // tables for this type. This maps to a decl.
+ typedef Unordered_map_hash(const Interface_type*, tree, Type_hash_identical,
+ Type_identical) Interface_method_tables;
+
+ // Return a pointer to the interface method table for TYPE for the
+ // interface INTERFACE.
+ static tree
+ interface_method_table(Gogo* gogo, Type* type,
+ const Interface_type *interface, bool is_pointer,
+ Interface_method_tables** method_tables,
+ Interface_method_tables** pointer_tables);
+
// Return a composite literal for the type descriptor entry for a
// type.
static Expression*
@@ -1178,10 +1191,18 @@ class Type
Btype*
get_btype_without_hash(Gogo*);
+ // A backend type that may be a placeholder.
+ struct Type_btype_entry
+ {
+ Btype *btype;
+ bool is_placeholder;
+ };
+
// A mapping from Type to Btype*, used to ensure that the backend
- // representation of identical types is identical.
- typedef Unordered_map_hash(const Type*, Btype*, Type_hash_identical,
- Type_identical) Type_btypes;
+ // representation of identical types is identical. This is only
+ // used for unnamed types.
+ typedef Unordered_map_hash(const Type*, Type_btype_entry,
+ Type_hash_identical, Type_identical) Type_btypes;
static Type_btypes type_btypes;
@@ -1198,9 +1219,6 @@ class Type
// The type classification.
Type_classification classification_;
- // Whether btype_ is a placeholder type used while named types are
- // being converted.
- bool btype_is_placeholder_;
// The backend representation of the type, once it has been
// determined.
Btype* btype_;
@@ -1445,7 +1463,7 @@ class Integer_type : public Type
protected:
bool
- do_compare_is_identity(Gogo*) const
+ do_compare_is_identity(Gogo*)
{ return true; }
unsigned int
@@ -1522,7 +1540,7 @@ class Float_type : public Type
protected:
bool
- do_compare_is_identity(Gogo*) const
+ do_compare_is_identity(Gogo*)
{ return false; }
unsigned int
@@ -1591,7 +1609,7 @@ class Complex_type : public Type
protected:
bool
- do_compare_is_identity(Gogo*) const
+ do_compare_is_identity(Gogo*)
{ return false; }
unsigned int
@@ -1651,7 +1669,7 @@ class String_type : public Type
{ return true; }
bool
- do_compare_is_identity(Gogo*) const
+ do_compare_is_identity(Gogo*)
{ return false; }
Btype*
@@ -1765,7 +1783,7 @@ class Function_type : public Type
{ return true; }
bool
- do_compare_is_identity(Gogo*) const
+ do_compare_is_identity(Gogo*)
{ return false; }
unsigned int
@@ -1840,7 +1858,7 @@ class Pointer_type : public Type
{ return true; }
bool
- do_compare_is_identity(Gogo*) const
+ do_compare_is_identity(Gogo*)
{ return true; }
unsigned int
@@ -1994,7 +2012,8 @@ class Struct_type : public Type
public:
Struct_type(Struct_field_list* fields, Location location)
: Type(TYPE_STRUCT),
- fields_(fields), location_(location), all_methods_(NULL)
+ fields_(fields), location_(location), all_methods_(NULL),
+ interface_method_tables_(NULL), pointer_interface_method_tables_(NULL)
{ }
// Return the field NAME. This only looks at local fields, not at
@@ -2076,6 +2095,14 @@ class Struct_type : public Type
Method*
method_function(const std::string& name, bool* is_ambiguous) const;
+ // Return a pointer to the interface method table for this type for
+ // the interface INTERFACE. If IS_POINTER is true, set the type
+ // descriptor to a pointer to this type, otherwise set it to this
+ // type.
+ tree
+ interface_method_table(Gogo*, const Interface_type* interface,
+ bool is_pointer);
+
// Traverse just the field types of a struct type.
int
traverse_field_types(Traverse* traverse)
@@ -2117,7 +2144,7 @@ class Struct_type : public Type
do_has_pointer() const;
bool
- do_compare_is_identity(Gogo*) const;
+ do_compare_is_identity(Gogo*);
unsigned int
do_hash_for_method(Gogo*) const;
@@ -2156,6 +2183,13 @@ class Struct_type : public Type
Location location_;
// If this struct is unnamed, a list of methods.
Methods* all_methods_;
+ // A mapping from interfaces to the associated interface method
+ // tables for this type. Only used if this struct is unnamed.
+ Interface_method_tables* interface_method_tables_;
+ // A mapping from interfaces to the associated interface method
+ // tables for pointers to this type. Only used if this struct is
+ // unnamed.
+ Interface_method_tables* pointer_interface_method_tables_;
};
// The type of an array.
@@ -2243,7 +2277,7 @@ class Array_type : public Type
}
bool
- do_compare_is_identity(Gogo*) const;
+ do_compare_is_identity(Gogo*);
unsigned int
do_hash_for_method(Gogo*) const;
@@ -2336,7 +2370,7 @@ class Map_type : public Type
{ return true; }
bool
- do_compare_is_identity(Gogo*) const
+ do_compare_is_identity(Gogo*)
{ return false; }
unsigned int
@@ -2422,7 +2456,7 @@ class Channel_type : public Type
{ return true; }
bool
- do_compare_is_identity(Gogo*) const
+ do_compare_is_identity(Gogo*)
{ return true; }
unsigned int
@@ -2553,7 +2587,7 @@ class Interface_type : public Type
{ return true; }
bool
- do_compare_is_identity(Gogo*) const
+ do_compare_is_identity(Gogo*)
{ return false; }
unsigned int
@@ -2623,8 +2657,8 @@ class Named_type : public Type
public:
Named_type(Named_object* named_object, Type* type, Location location)
: Type(TYPE_NAMED),
- named_object_(named_object), in_function_(NULL), type_(type),
- local_methods_(NULL), all_methods_(NULL),
+ named_object_(named_object), in_function_(NULL), in_function_index_(0),
+ type_(type), local_methods_(NULL), all_methods_(NULL),
interface_method_tables_(NULL), pointer_interface_method_tables_(NULL),
location_(location), named_btype_(NULL), dependencies_(),
is_visible_(true), is_error_(false), is_placeholder_(false),
@@ -2651,13 +2685,19 @@ class Named_type : public Type
// Return the function in which this type is defined. This will
// return NULL for a type defined in global scope.
const Named_object*
- in_function() const
- { return this->in_function_; }
+ in_function(unsigned int *pindex) const
+ {
+ *pindex = this->in_function_index_;
+ return this->in_function_;
+ }
// Set the function in which this type is defined.
void
- set_in_function(Named_object* f)
- { this->in_function_ = f; }
+ set_in_function(Named_object* f, unsigned int index)
+ {
+ this->in_function_ = f;
+ this->in_function_index_ = index;
+ }
// Return the name of the type.
const std::string&
@@ -2830,7 +2870,7 @@ class Named_type : public Type
do_has_pointer() const;
bool
- do_compare_is_identity(Gogo*) const;
+ do_compare_is_identity(Gogo*);
unsigned int
do_hash_for_method(Gogo*) const;
@@ -2855,16 +2895,13 @@ class Named_type : public Type
void
create_placeholder(Gogo*);
- // A mapping from interfaces to the associated interface method
- // tables for this type. This maps to a decl.
- typedef Unordered_map_hash(const Interface_type*, tree, Type_hash_identical,
- Type_identical) Interface_method_tables;
-
// A pointer back to the Named_object for this type.
Named_object* named_object_;
// If this type is defined in a function, a pointer back to the
// function in which it is defined.
Named_object* in_function_;
+ // The index of this type in IN_FUNCTION_.
+ unsigned int in_function_index_;
// The actual type.
Type* type_;
// The list of methods defined for this type. Any named type can
@@ -2917,7 +2954,7 @@ class Named_type : public Type
// function exits.
mutable bool seen_;
// Like seen_, but used only by do_compare_is_identity.
- mutable bool seen_in_compare_is_identity_;
+ bool seen_in_compare_is_identity_;
// Like seen_, but used only by do_get_backend.
bool seen_in_get_backend_;
};
@@ -2972,7 +3009,7 @@ class Forward_declaration_type : public Type
{ return this->real_type()->has_pointer(); }
bool
- do_compare_is_identity(Gogo* gogo) const
+ do_compare_is_identity(Gogo* gogo)
{ return this->real_type()->compare_is_identity(gogo); }
unsigned int
diff --git a/gcc/go/lang.opt b/gcc/go/lang.opt
index eb9ed9a63a0..22197a71e3d 100644
--- a/gcc/go/lang.opt
+++ b/gcc/go/lang.opt
@@ -61,6 +61,10 @@ fgo-prefix=
Go Joined RejectNegative
-fgo-prefix=<string> Set package-specific prefix for exported Go names
+fgo-relative-import-path=
+Go Joined RejectNegative
+-fgo-relative-import-path=<path> Treat a relative import as relative to path
+
frequire-return-statement
Go Var(go_require_return_statement) Init(1) Warning
Functions which return values must end with return statements