aboutsummaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend/expressions.cc
diff options
context:
space:
mode:
Diffstat (limited to 'gcc/go/gofrontend/expressions.cc')
-rw-r--r--gcc/go/gofrontend/expressions.cc587
1 files changed, 394 insertions, 193 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 5409d26..ddb1d91 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -408,7 +408,14 @@ Expression::convert_type_to_interface(Type* lhs_type, Expression* rhs,
{
// We are assigning a non-pointer value to the interface; the
// interface gets a copy of the value in the heap if it escapes.
- if (rhs->is_constant())
+
+ // An exception is &global if global is notinheap, which is a
+ // pointer value but not a direct-iface type and we can't simply
+ // take its address.
+ bool is_address = (rhs->unary_expression() != NULL
+ && rhs->unary_expression()->op() == OPERATOR_AND);
+
+ if (rhs->is_constant() && !is_address)
obj = Expression::make_unary(OPERATOR_AND, rhs, location);
else
{
@@ -1427,7 +1434,7 @@ Sink_expression::do_get_backend(Translate_context* context)
Bstatement* decl;
this->bvar_ =
gogo->backend()->temporary_variable(fn_ctx, context->bblock(), bt, NULL,
- false, loc, &decl);
+ 0, loc, &decl);
Bexpression* var_ref =
gogo->backend()->var_expression(this->bvar_, loc);
var_ref = gogo->backend()->compound_expression(decl, var_ref, loc);
@@ -1724,10 +1731,12 @@ Func_descriptor_expression::do_get_backend(Translate_context* context)
if (no->is_function() && no->func_value()->is_referenced_by_inline())
is_hidden = false;
+ unsigned int flags = 0;
+ if (is_hidden)
+ flags |= Backend::variable_is_hidden;
bvar = context->backend()->immutable_struct(bname.name(),
bname.optional_asm_name(),
- is_hidden, false,
- btype, bloc);
+ flags, btype, bloc);
Expression_list* vals = new Expression_list();
vals->push_back(Expression::make_func_code_reference(this->fn_, bloc));
Expression* init =
@@ -1736,8 +1745,7 @@ Func_descriptor_expression::do_get_backend(Translate_context* context)
bcontext.set_is_const();
Bexpression* binit = init->get_backend(&bcontext);
context->backend()->immutable_struct_set_init(bvar, bname.name(),
- is_hidden, false, btype,
- bloc, binit);
+ flags, btype, bloc, binit);
}
this->dvar_ = bvar;
@@ -3865,11 +3873,12 @@ Type_conversion_expression::do_traverse(Traverse* traverse)
return TRAVERSE_CONTINUE;
}
-// Convert to a constant at lowering time.
+// Convert to a constant at lowering time. Also lower conversions
+// from slice to pointer-to-array, as they can panic.
Expression*
Type_conversion_expression::do_lower(Gogo*, Named_object*,
- Statement_inserter*, int)
+ Statement_inserter* inserter, int)
{
Type* type = this->type_;
Expression* val = this->expr_;
@@ -3957,6 +3966,57 @@ Type_conversion_expression::do_lower(Gogo*, Named_object*,
}
}
+ if (type->points_to() != NULL
+ && type->points_to()->array_type() != NULL
+ && !type->points_to()->is_slice_type()
+ && val->type()->is_slice_type()
+ && Type::are_identical(type->points_to()->array_type()->element_type(),
+ val->type()->array_type()->element_type(),
+ 0, NULL))
+ {
+ Temporary_statement* val_temp = NULL;
+ if (!val->is_multi_eval_safe())
+ {
+ val_temp = Statement::make_temporary(val->type(), NULL, location);
+ inserter->insert(val_temp);
+ val = Expression::make_set_and_use_temporary(val_temp, val,
+ location);
+ }
+
+ Type* int_type = Type::lookup_integer_type("int");
+ Temporary_statement* vallen_temp =
+ Statement::make_temporary(int_type, NULL, location);
+ inserter->insert(vallen_temp);
+
+ Expression* arrlen = type->points_to()->array_type()->length();
+ Expression* vallen =
+ Expression::make_slice_info(val, Expression::SLICE_INFO_LENGTH,
+ location);
+ vallen = Expression::make_set_and_use_temporary(vallen_temp, vallen,
+ location);
+ Expression* cond = Expression::make_binary(OPERATOR_GT, arrlen, vallen,
+ location);
+
+ vallen = Expression::make_temporary_reference(vallen_temp, location);
+ Expression* panic = Runtime::make_call(Runtime::PANIC_SLICE_CONVERT,
+ location, 2, arrlen, vallen);
+
+ Expression* nil = Expression::make_nil(location);
+ Expression* check = Expression::make_conditional(cond, panic, nil,
+ location);
+
+ if (val_temp == NULL)
+ val = val->copy();
+ else
+ val = Expression::make_temporary_reference(val_temp, location);
+ Expression* ptr =
+ Expression::make_slice_info(val, Expression::SLICE_INFO_VALUE_POINTER,
+ location);
+ ptr = Expression::make_unsafe_cast(type, ptr, location);
+
+ return Expression::make_compound(check, ptr, location);
+ }
+
return this;
}
@@ -5280,12 +5340,14 @@ Unary_expression::do_get_backend(Translate_context* context)
copy_to_heap = (context->function() != NULL
|| context->is_const());
}
+ unsigned int flags = (Backend::variable_is_hidden
+ | Backend::variable_address_is_taken);
+ if (copy_to_heap)
+ flags |= Backend::variable_is_constant;
Bvariable* implicit =
- gogo->backend()->implicit_variable(var_name, "", btype, true,
- copy_to_heap, false, 0);
+ gogo->backend()->implicit_variable(var_name, "", btype, flags, 0);
gogo->backend()->implicit_variable_set_init(implicit, var_name, btype,
- true, copy_to_heap, false,
- bexpr);
+ flags, bexpr);
bexpr = gogo->backend()->var_expression(implicit, loc);
// If we are not copying a slice initializer to the heap,
@@ -5307,22 +5369,24 @@ Unary_expression::do_get_backend(Translate_context* context)
&& this->expr_->is_static_initializer())
{
std::string var_name(gogo->initializer_name());
+ unsigned int flags = (Backend::variable_is_hidden
+ | Backend::variable_address_is_taken);
Bvariable* decl =
- gogo->backend()->immutable_struct(var_name, "", true, false,
- btype, loc);
- gogo->backend()->immutable_struct_set_init(decl, var_name, true,
- false, btype, loc, bexpr);
+ gogo->backend()->immutable_struct(var_name, "", flags, btype, loc);
+ gogo->backend()->immutable_struct_set_init(decl, var_name, flags,
+ btype, loc, bexpr);
bexpr = gogo->backend()->var_expression(decl, loc);
}
else if (this->expr_->is_constant())
{
std::string var_name(gogo->initializer_name());
+ unsigned int flags = (Backend::variable_is_hidden
+ | Backend::variable_is_constant
+ | Backend::variable_address_is_taken);
Bvariable* decl =
- gogo->backend()->implicit_variable(var_name, "", btype,
- true, true, false, 0);
+ gogo->backend()->implicit_variable(var_name, "", btype, flags, 0);
gogo->backend()->implicit_variable_set_init(decl, var_name, btype,
- true, true, false,
- bexpr);
+ flags, bexpr);
bexpr = gogo->backend()->var_expression(decl, loc);
}
@@ -8247,12 +8311,16 @@ Builtin_call_expression::Builtin_call_expression(Gogo* gogo,
this->code_ = BUILTIN_REAL;
else if (name == "recover")
this->code_ = BUILTIN_RECOVER;
+ else if (name == "Add")
+ this->code_ = BUILTIN_ADD;
else if (name == "Alignof")
this->code_ = BUILTIN_ALIGNOF;
else if (name == "Offsetof")
this->code_ = BUILTIN_OFFSETOF;
else if (name == "Sizeof")
this->code_ = BUILTIN_SIZEOF;
+ else if (name == "Slice")
+ this->code_ = BUILTIN_SLICE;
else
go_unreachable();
}
@@ -8689,6 +8757,119 @@ Builtin_call_expression::do_flatten(Gogo* gogo, Named_object* function,
return Runtime::make_call(code, loc, 3, e1, e2, e3);
}
+
+ case BUILTIN_ADD:
+ {
+ Expression* ptr = this->args()->front();
+ Type* uintptr_type = Type::lookup_integer_type("uintptr");
+ ptr = Expression::make_cast(uintptr_type, ptr, loc);
+ Expression* len = this->args()->back();
+ len = Expression::make_cast(uintptr_type, len, loc);
+ Expression* add = Expression::make_binary(OPERATOR_PLUS, ptr, len,
+ loc);
+ return Expression::make_cast(this->args()->front()->type(), add, loc);
+ }
+
+ case BUILTIN_SLICE:
+ {
+ Expression* ptr = this->args()->front();
+ Temporary_statement* ptr_temp = NULL;
+ if (!ptr->is_multi_eval_safe())
+ {
+ ptr_temp = Statement::make_temporary(NULL, ptr, loc);
+ inserter->insert(ptr_temp);
+ ptr = Expression::make_temporary_reference(ptr_temp, loc);
+ }
+
+ Expression* len = this->args()->back();
+ Temporary_statement* len_temp = NULL;
+ if (!len->is_multi_eval_safe())
+ {
+ len_temp = Statement::make_temporary(NULL, len, loc);
+ inserter->insert(len_temp);
+ len = Expression::make_temporary_reference(len_temp, loc);
+ }
+
+ bool fits_in_int;
+ Numeric_constant nc;
+ if (this->args()->back()->numeric_constant_value(&nc))
+ {
+ // We gave an error for constants that don't fit in int in
+ // check_types.
+ fits_in_int = true;
+ }
+ else
+ {
+ Integer_type* itype = this->args()->back()->type()->integer_type();
+ go_assert(itype != NULL);
+ int ebits = itype->bits();
+ int intbits =
+ Type::lookup_integer_type("int")->integer_type()->bits();
+
+ // We can treat ebits == intbits as small even for an
+ // unsigned integer type, because we will convert the
+ // value to int and then reject it in the runtime if it is
+ // negative.
+
+ fits_in_int = ebits <= intbits;
+ }
+
+ Runtime::Function code = (fits_in_int
+ ? Runtime::UNSAFESLICE
+ : Runtime::UNSAFESLICE64);
+ Expression* td =
+ Expression::make_type_descriptor(ptr->type()->points_to(), loc);
+ Expression* check = Runtime::make_call(code, loc, 3,
+ td, ptr, len);
+
+ if (ptr_temp == NULL)
+ ptr = ptr->copy();
+ else
+ ptr = Expression::make_temporary_reference(ptr_temp, loc);
+ Expression* nil = Expression::make_nil(loc);
+ nil = Expression::make_cast(ptr->type(), nil, loc);
+ Expression* is_nil = Expression::make_binary(OPERATOR_EQEQ, ptr, nil,
+ loc);
+
+ if (len_temp == NULL)
+ len = len->copy();
+ else
+ len = Expression::make_temporary_reference(len_temp, loc);
+ Expression* zero = Expression::make_integer_ul(0, len->type(), loc);
+ Expression* is_zero = Expression::make_binary(OPERATOR_EQEQ, len, zero,
+ loc);
+
+ Expression* cond = Expression::make_binary(OPERATOR_ANDAND, is_nil,
+ is_zero, loc);
+
+ Type* slice_type = Type::make_array_type(ptr->type()->points_to(),
+ NULL);
+ nil = Expression::make_nil(loc);
+ Expression* nil_slice = Expression::make_cast(slice_type, nil, loc);
+
+ if (ptr_temp == NULL)
+ ptr = ptr->copy();
+ else
+ ptr = Expression::make_temporary_reference(ptr_temp, loc);
+
+ if (len_temp == NULL)
+ len = len->copy();
+ else
+ len = Expression::make_temporary_reference(len_temp, loc);
+
+ Expression* cap;
+ if (len_temp == NULL)
+ cap = len->copy();
+ else
+ cap = Expression::make_temporary_reference(len_temp, loc);
+
+ Expression* slice = Expression::make_slice_value(slice_type, ptr,
+ len, cap, loc);
+
+ slice = Expression::make_conditional(cond, nil_slice, slice, loc);
+
+ return Expression::make_compound(check, slice, loc);
+ }
}
return this;
@@ -9169,7 +9350,7 @@ Builtin_call_expression::flatten_append(Gogo* gogo, Named_object* function,
ref2 = Expression::make_cast(uint_type, ref2, loc);
cond = Expression::make_binary(OPERATOR_GT, ref, ref2, loc);
zero = Expression::make_integer_ul(0, int_type, loc);
- call = Expression::make_conditional(cond, call, zero, loc);
+ call = Expression::make_conditional(cond, zero, call, loc);
}
}
else
@@ -9776,9 +9957,11 @@ Builtin_call_expression::do_discarding_value()
case BUILTIN_MAKE:
case BUILTIN_NEW:
case BUILTIN_REAL:
+ case BUILTIN_ADD:
case BUILTIN_ALIGNOF:
case BUILTIN_OFFSETOF:
case BUILTIN_SIZEOF:
+ case BUILTIN_SLICE:
this->unused_value_error();
return false;
@@ -9885,6 +10068,18 @@ Builtin_call_expression::do_type()
t = Type::make_error_type();
return t;
}
+
+ case BUILTIN_ADD:
+ return Type::make_pointer_type(Type::make_void_type());
+
+ case BUILTIN_SLICE:
+ const Expression_list* args = this->args();
+ if (args == NULL || args->size() != 2)
+ return Type::make_error_type();
+ Type* pt = args->front()->type()->points_to();
+ if (pt == NULL)
+ return Type::make_error_type();
+ return Type::make_array_type(pt, NULL);
}
}
@@ -9949,6 +10144,28 @@ Builtin_call_expression::do_determine_type(const Type_context* context)
is_print = false;
break;
+ case BUILTIN_ADD:
+ case BUILTIN_SLICE:
+ // Both unsafe.Add and unsafe.Slice take two arguments, and the
+ // second arguments defaults to "int".
+ if (args != NULL && args->size() == 2)
+ {
+ if (this->code_ == BUILTIN_SLICE)
+ args->front()->determine_type_no_context();
+ else
+ {
+ Type* pointer = Type::make_pointer_type(Type::make_void_type());
+ Type_context subcontext(pointer, false);
+ args->front()->determine_type(&subcontext);
+ }
+ Type* int_type = Type::lookup_integer_type("int");
+ Type_context subcontext(int_type, false);
+ args->back()->determine_type(&subcontext);
+ return;
+ }
+ is_print = false;
+ break;
+
default:
is_print = false;
break;
@@ -10348,6 +10565,78 @@ Builtin_call_expression::do_check_types(Gogo*)
}
break;
+ case BUILTIN_ADD:
+ case BUILTIN_SLICE:
+ {
+ Numeric_constant nc;
+ unsigned long v;
+ const Expression_list* args = this->args();
+ if (args == NULL || args->size() < 2)
+ this->report_error(_("not enough arguments"));
+ else if (args->size() > 2)
+ this->report_error(_("too many arguments"));
+ else if (args->front()->is_error_expression()
+ || args->front()->type()->is_error()
+ || args->back()->is_error_expression()
+ || args->back()->type()->is_error())
+ this->set_is_error();
+ else if (args->back()->type()->integer_type() == NULL
+ && (!args->back()->type()->is_abstract()
+ || !args->back()->numeric_constant_value(&nc)
+ || (nc.to_unsigned_long(&v)
+ == Numeric_constant::NC_UL_NOTINT)))
+ {
+ if (this->code_ == BUILTIN_ADD)
+ go_error_at(args->back()->location(), "non-integer offset");
+ else
+ go_error_at(args->back()->location(), "non-integer size");
+ }
+ else if (this->code_ == BUILTIN_ADD)
+ {
+ Type* pointer_type =
+ Type::make_pointer_type(Type::make_void_type());
+ std::string reason;
+ if (!Type::are_assignable(pointer_type, args->front()->type(),
+ &reason))
+ {
+ if (reason.empty())
+ go_error_at(args->front()->location(),
+ "argument 1 has incompatible type");
+ else
+ go_error_at(args->front()->location(),
+ "argument 1 has incompatible type (%s)",
+ reason.c_str());
+ this->set_is_error();
+ }
+ }
+ else
+ {
+ if (args->front()->type()->points_to() == NULL)
+ {
+ go_error_at(args->front()->location(),
+ "argument 1 must be a pointer");
+ this->set_is_error();
+ }
+
+ unsigned int int_bits =
+ Type::lookup_integer_type("int")->integer_type()->bits();
+
+ mpz_t ival;
+ if (args->back()->numeric_constant_value(&nc) && nc.to_int(&ival))
+ {
+ if (mpz_sgn(ival) < 0
+ || mpz_sizeinbase(ival, 2) >= int_bits)
+ {
+ go_error_at(args->back()->location(),
+ "slice length out of range");
+ this->set_is_error();
+ }
+ mpz_clear(ival);
+ }
+ }
+ }
+ break;
+
default:
go_unreachable();
}
@@ -10392,6 +10681,8 @@ Builtin_call_expression::do_get_backend(Translate_context* context)
case BUILTIN_INVALID:
case BUILTIN_NEW:
case BUILTIN_MAKE:
+ case BUILTIN_ADD:
+ case BUILTIN_SLICE:
go_unreachable();
case BUILTIN_LEN:
@@ -10755,6 +11046,14 @@ Builtin_call_expression::do_export(Export_function_body* efb) const
// A trailing space lets us reliably identify the end of the number.
efb->write_c_string(" ");
}
+ else if (this->code_ == BUILTIN_ADD || this->code_ == BUILTIN_SLICE)
+ {
+ char buf[50];
+ snprintf(buf, sizeof buf, "<p%d>%s", efb->unsafe_package_index(),
+ (this->code_ == BUILTIN_ADD ? "Add" : "Slice"));
+ efb->write_c_string(buf);
+ this->export_arguments(efb);
+ }
else
{
const char *s = NULL;
@@ -10910,12 +11209,23 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
{
Location loc = this->location();
+ if (this->is_error_expression())
+ return Expression::make_error(loc);
+
// A type cast can look like a function call.
if (this->fn_->is_type_expression()
&& this->args_ != NULL
&& this->args_->size() == 1)
- return Expression::make_cast(this->fn_->type(), this->args_->front(),
- loc);
+ {
+ if (this->expected_result_count_ != 0
+ && this->expected_result_count_ != 1)
+ {
+ this->report_error(_("type conversion result count mismatch"));
+ return Expression::make_error(loc);
+ }
+ 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
@@ -11028,6 +11338,7 @@ Call_expression::do_lower(Gogo* gogo, Named_object* function,
// We always pass a pointer when calling a method, except for
// direct interface types when calling a value method.
if (!first_arg->type()->is_error()
+ && first_arg->type()->points_to() == NULL
&& !first_arg->type()->is_direct_iface_type())
{
first_arg = Expression::make_unary(OPERATOR_AND, first_arg, loc);
@@ -11306,12 +11617,10 @@ Call_expression::intrinsify(Gogo* gogo,
// sync/atomic functions and runtime/internal/atomic functions
// are very similar. In order not to duplicate code, we just
// redirect to the latter and let the code below to handle them.
- // In case there is no equivalent functions (slight variance
- // in types), we just make an artificial name (begin with '$').
// Note: no StorePointer, SwapPointer, and CompareAndSwapPointer,
// as they need write barriers.
if (name == "LoadInt32")
- name = "$Loadint32";
+ name = "Loadint32";
else if (name == "LoadInt64")
name = "Loadint64";
else if (name == "LoadUint32")
@@ -11323,9 +11632,9 @@ Call_expression::intrinsify(Gogo* gogo,
else if (name == "LoadPointer")
name = "Loadp";
else if (name == "StoreInt32")
- name = "$Storeint32";
+ name = "Storeint32";
else if (name == "StoreInt64")
- name = "$Storeint64";
+ name = "Storeint64";
else if (name == "StoreUint32")
name = "Store";
else if (name == "StoreUint64")
@@ -11333,7 +11642,7 @@ Call_expression::intrinsify(Gogo* gogo,
else if (name == "StoreUintptr")
name = "Storeuintptr";
else if (name == "AddInt32")
- name = "$Xaddint32";
+ name = "Xaddint32";
else if (name == "AddInt64")
name = "Xaddint64";
else if (name == "AddUint32")
@@ -11343,9 +11652,9 @@ Call_expression::intrinsify(Gogo* gogo,
else if (name == "AddUintptr")
name = "Xadduintptr";
else if (name == "SwapInt32")
- name = "$Xchgint32";
+ name = "Xchgint32";
else if (name == "SwapInt64")
- name = "$Xchgint64";
+ name = "Xchgint64";
else if (name == "SwapUint32")
name = "Xchg";
else if (name == "SwapUint64")
@@ -11353,9 +11662,9 @@ Call_expression::intrinsify(Gogo* gogo,
else if (name == "SwapUintptr")
name = "Xchguintptr";
else if (name == "CompareAndSwapInt32")
- name = "$Casint32";
+ name = "Casint32";
else if (name == "CompareAndSwapInt64")
- name = "$Casint64";
+ name = "Casint64";
else if (name == "CompareAndSwapUint32")
name = "Cas";
else if (name == "CompareAndSwapUint64")
@@ -11591,7 +11900,7 @@ Call_expression::intrinsify(Gogo* gogo,
if ((name == "Load" || name == "Load64" || name == "Loadint64" || name == "Loadp"
|| name == "Loaduint" || name == "Loaduintptr" || name == "LoadAcq"
- || name == "$Loadint32")
+ || name == "Loadint32")
&& this->args_ != NULL && this->args_->size() == 1)
{
if (int_size < 8 && (name == "Load64" || name == "Loadint64"))
@@ -11611,7 +11920,7 @@ Call_expression::intrinsify(Gogo* gogo,
code = Runtime::ATOMIC_LOAD_8;
res_type = uint64_type;
}
- else if (name == "$Loadint32")
+ else if (name == "Loadint32")
{
code = Runtime::ATOMIC_LOAD_4;
res_type = int32_type;
@@ -11658,10 +11967,10 @@ Call_expression::intrinsify(Gogo* gogo,
if ((name == "Store" || name == "Store64" || name == "StorepNoWB"
|| name == "Storeuintptr" || name == "StoreRel"
- || name == "$Storeint32" || name == "$Storeint64")
+ || name == "Storeint32" || name == "Storeint64")
&& this->args_ != NULL && this->args_->size() == 2)
{
- if (int_size < 8 && (name == "Store64" || name == "$Storeint64"))
+ if (int_size < 8 && (name == "Store64" || name == "Storeint64"))
return NULL;
Runtime::Function code;
@@ -11671,9 +11980,9 @@ Call_expression::intrinsify(Gogo* gogo,
code = Runtime::ATOMIC_STORE_4;
else if (name == "Store64")
code = Runtime::ATOMIC_STORE_8;
- else if (name == "$Storeint32")
+ else if (name == "Storeint32")
code = Runtime::ATOMIC_STORE_4;
- else if (name == "$Storeint64")
+ else if (name == "Storeint64")
code = Runtime::ATOMIC_STORE_8;
else if (name == "Storeuintptr")
code = (ptr_size == 8 ? Runtime::ATOMIC_STORE_8 : Runtime::ATOMIC_STORE_4);
@@ -11695,7 +12004,7 @@ Call_expression::intrinsify(Gogo* gogo,
}
if ((name == "Xchg" || name == "Xchg64" || name == "Xchguintptr"
- || name == "$Xchgint32" || name == "$Xchgint64")
+ || name == "Xchgint32" || name == "Xchgint64")
&& this->args_ != NULL && this->args_->size() == 2)
{
if (int_size < 8 && (name == "Xchg64" || name == "Xchgint64"))
@@ -11713,12 +12022,12 @@ Call_expression::intrinsify(Gogo* gogo,
code = Runtime::ATOMIC_EXCHANGE_8;
res_type = uint64_type;
}
- else if (name == "$Xchgint32")
+ else if (name == "Xchgint32")
{
code = Runtime::ATOMIC_EXCHANGE_4;
res_type = int32_type;
}
- else if (name == "$Xchgint64")
+ else if (name == "Xchgint64")
{
code = Runtime::ATOMIC_EXCHANGE_8;
res_type = int64_type;
@@ -11741,10 +12050,10 @@ Call_expression::intrinsify(Gogo* gogo,
if ((name == "Cas" || name == "Cas64" || name == "Casuintptr"
|| name == "Casp1" || name == "CasRel"
- || name == "$Casint32" || name == "$Casint64")
+ || name == "Casint32" || name == "Casint64")
&& this->args_ != NULL && this->args_->size() == 3)
{
- if (int_size < 8 && (name == "Cas64" || name == "$Casint64"))
+ if (int_size < 8 && (name == "Cas64" || name == "Casint64"))
return NULL;
Runtime::Function code;
@@ -11763,9 +12072,9 @@ Call_expression::intrinsify(Gogo* gogo,
code = Runtime::ATOMIC_COMPARE_EXCHANGE_4;
else if (name == "Cas64")
code = Runtime::ATOMIC_COMPARE_EXCHANGE_8;
- else if (name == "$Casint32")
+ else if (name == "Casint32")
code = Runtime::ATOMIC_COMPARE_EXCHANGE_4;
- else if (name == "$Casint64")
+ else if (name == "Casint64")
code = Runtime::ATOMIC_COMPARE_EXCHANGE_8;
else if (name == "Casuintptr")
code = (ptr_size == 8
@@ -11793,7 +12102,7 @@ Call_expression::intrinsify(Gogo* gogo,
}
if ((name == "Xadd" || name == "Xadd64" || name == "Xaddint64"
- || name == "Xadduintptr" || name == "$Xaddint32")
+ || name == "Xadduintptr" || name == "Xaddint32")
&& this->args_ != NULL && this->args_->size() == 2)
{
if (int_size < 8 && (name == "Xadd64" || name == "Xaddint64"))
@@ -11811,7 +12120,7 @@ Call_expression::intrinsify(Gogo* gogo,
code = Runtime::ATOMIC_ADD_FETCH_8;
res_type = uint64_type;
}
- else if (name == "$Xaddint32")
+ else if (name == "Xaddint32")
{
code = Runtime::ATOMIC_ADD_FETCH_4;
res_type = int32_type;
@@ -14888,7 +15197,9 @@ Allocation_expression::do_get_backend(Translate_context* context)
: gogo->backend()->zero_expression(btype));
Bvariable* temp =
gogo->backend()->temporary_variable(fndecl, context->bblock(), btype,
- init, true, loc, &decl);
+ init,
+ Backend::variable_address_is_taken,
+ loc, &decl);
Bexpression* ret = gogo->backend()->var_expression(temp, loc);
ret = gogo->backend()->address_expression(ret, loc);
ret = gogo->backend()->compound_expression(decl, ret, loc);
@@ -15140,44 +15451,6 @@ Struct_construction_expression::do_copy()
return ret;
}
-// Flatten a struct construction expression. Store the values into
-// temporaries in case they need interface conversion.
-
-Expression*
-Struct_construction_expression::do_flatten(Gogo*, Named_object*,
- Statement_inserter* inserter)
-{
- if (this->vals() == NULL)
- return this;
-
- // If this is a constant struct, we don't need temporaries.
- if (this->is_constant_struct() || this->is_static_initializer())
- return this;
-
- Location loc = this->location();
- for (Expression_list::iterator pv = this->vals()->begin();
- pv != this->vals()->end();
- ++pv)
- {
- if (*pv != NULL)
- {
- if ((*pv)->is_error_expression() || (*pv)->type()->is_error_type())
- {
- go_assert(saw_errors());
- return Expression::make_error(loc);
- }
- if (!(*pv)->is_multi_eval_safe())
- {
- Temporary_statement* temp =
- Statement::make_temporary(NULL, *pv, loc);
- inserter->insert(temp);
- *pv = Expression::make_temporary_reference(temp, loc);
- }
- }
- }
- return this;
-}
-
// Make implicit type conversions explicit.
void
@@ -15440,50 +15713,6 @@ Array_construction_expression::do_check_types(Gogo*)
}
}
-// Flatten an array construction expression. Store the values into
-// temporaries in case they need interface conversion.
-
-Expression*
-Array_construction_expression::do_flatten(Gogo*, Named_object*,
- Statement_inserter* inserter)
-{
- if (this->is_error_expression())
- {
- go_assert(saw_errors());
- return this;
- }
-
- if (this->vals() == NULL)
- return this;
-
- // If this is a constant array, we don't need temporaries.
- if (this->is_constant_array() || this->is_static_initializer())
- return this;
-
- Location loc = this->location();
- for (Expression_list::iterator pv = this->vals()->begin();
- pv != this->vals()->end();
- ++pv)
- {
- if (*pv != NULL)
- {
- if ((*pv)->is_error_expression() || (*pv)->type()->is_error_type())
- {
- go_assert(saw_errors());
- return Expression::make_error(loc);
- }
- if (!(*pv)->is_multi_eval_safe())
- {
- Temporary_statement* temp =
- Statement::make_temporary(NULL, *pv, loc);
- inserter->insert(temp);
- *pv = Expression::make_temporary_reference(temp, loc);
- }
- }
- }
- return this;
-}
-
// Make implicit type conversions explicit.
void
@@ -15752,14 +15981,14 @@ Slice_construction_expression::create_array_val()
// the new temp statement.
Expression*
-Slice_construction_expression::do_flatten(Gogo* gogo, Named_object* no,
+Slice_construction_expression::do_flatten(Gogo*, Named_object*,
Statement_inserter* inserter)
{
if (this->type()->array_type() == NULL)
- return NULL;
-
- // Base class flattening first
- this->Array_construction_expression::do_flatten(gogo, no, inserter);
+ {
+ go_assert(saw_errors());
+ return Expression::make_error(this->location());
+ }
// Create a stack-allocated storage temp if storage won't escape
if (!this->storage_escapes_
@@ -15768,7 +15997,7 @@ Slice_construction_expression::do_flatten(Gogo* gogo, Named_object* no,
{
Location loc = this->location();
this->array_val_ = this->create_array_val();
- go_assert(this->array_val_);
+ go_assert(this->array_val_ != NULL);
Temporary_statement* temp =
Statement::make_temporary(this->valtype_, this->array_val_, loc);
inserter->insert(temp);
@@ -17238,7 +17467,9 @@ Heap_expression::do_get_backend(Translate_context* context)
Bfunction* fndecl = fn->func_value()->get_or_make_decl(gogo, fn);
Bvariable* space_temp =
gogo->backend()->temporary_variable(fndecl, context->bblock(), btype,
- space, true, loc, &decl);
+ space,
+ Backend::variable_address_is_taken,
+ loc, &decl);
Btype* expr_btype = etype->get_backend(gogo);
Bexpression* bexpr = this->expr_->get_backend(context);
@@ -17259,8 +17490,9 @@ Heap_expression::do_get_backend(Translate_context* context)
Bstatement* edecl;
Bvariable* btemp =
gogo->backend()->temporary_variable(fndecl, context->bblock(),
- expr_btype, bexpr, true, loc,
- &edecl);
+ expr_btype, bexpr,
+ Backend::variable_address_is_taken,
+ loc, &edecl);
Bexpression* btempref = gogo->backend()->var_expression(btemp,
loc);
space = gogo->backend()->var_expression(space_temp, loc);
@@ -17802,49 +18034,7 @@ Expression::make_type_info(Type* type, Type_info type_info)
return new Type_info_expression(type, type_info);
}
-// An expression that evaluates to some characteristic of a slice.
-// This is used when indexing, bound-checking, or nil checking a slice.
-
-class Slice_info_expression : public Expression
-{
- public:
- Slice_info_expression(Expression* slice, Slice_info slice_info,
- Location location)
- : Expression(EXPRESSION_SLICE_INFO, location),
- slice_(slice), slice_info_(slice_info)
- { }
-
- protected:
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*)
- { }
-
- Expression*
- do_copy()
- {
- return new Slice_info_expression(this->slice_->copy(), this->slice_info_,
- this->location());
- }
-
- Bexpression*
- do_get_backend(Translate_context* context);
-
- void
- do_dump_expression(Ast_dump_context*) const;
-
- void
- do_issue_nil_check()
- { this->slice_->issue_nil_check(); }
-
- private:
- // The slice for which we are getting information.
- Expression* slice_;
- // What information we want.
- Slice_info slice_info_;
-};
+// Slice_info_expression.
// Return the type of the slice info.
@@ -18448,12 +18638,20 @@ Interface_mtable_expression::do_get_backend(Translate_context* context)
else
m = st->method_function(p->name(), &is_ambiguous);
go_assert(m != NULL);
- Named_object* no =
- (this->is_pointer_
- && this->type_->is_direct_iface_type()
- && m->is_value_method()
- ? m->iface_stub_object()
- : m->named_object());
+
+ // See the comment in Type::method_constructor.
+ bool use_direct_iface_stub = false;
+ if (m->is_value_method()
+ && this->is_pointer_
+ && this->type_->is_direct_iface_type())
+ use_direct_iface_stub = true;
+ if (!m->is_value_method()
+ && this->is_pointer_
+ && !this->type_->in_heap())
+ use_direct_iface_stub = true;
+ Named_object* no = (use_direct_iface_stub
+ ? m->iface_stub_object()
+ : m->named_object());
go_assert(no->is_function() || no->is_function_declaration());
@@ -18478,10 +18676,13 @@ Interface_mtable_expression::do_get_backend(Translate_context* context)
Bexpression* ctor =
gogo->backend()->constructor_expression(btype, ctor_bexprs, loc);
- this->bvar_ = gogo->backend()->immutable_struct(mangled_name, "", false,
- !is_public, btype, loc);
- gogo->backend()->immutable_struct_set_init(this->bvar_, mangled_name, false,
- !is_public, btype, loc, ctor);
+ unsigned int flags = 0;
+ if (!is_public)
+ flags |= Backend::variable_is_hidden;
+ this->bvar_ = gogo->backend()->immutable_struct(mangled_name, "", flags,
+ btype, loc);
+ gogo->backend()->immutable_struct_set_init(this->bvar_, mangled_name, flags,
+ btype, loc, ctor);
return gogo->backend()->var_expression(this->bvar_, loc);
}