+ error_at(first_arg->location(), "expected type");
+ this->set_is_error();
+ return Expression::make_error(this->location());
+ }
+ Type* type = first_arg->type();
+
+ bool is_slice = false;
+ bool is_map = false;
+ bool is_chan = false;
+ if (type->is_slice_type())
+ is_slice = true;
+ else if (type->map_type() != NULL)
+ is_map = true;
+ else if (type->channel_type() != NULL)
+ is_chan = true;
+ else
+ {
+ this->report_error(_("invalid type for make function"));
+ return Expression::make_error(this->location());
+ }
+
+ ++parg;
+ Expression* len_arg;
+ if (parg == args->end())
+ {
+ if (is_slice)
+ {
+ this->report_error(_("length required when allocating a slice"));
+ return Expression::make_error(this->location());
+ }
+
+ mpz_t zval;
+ mpz_init_set_ui(zval, 0);
+ len_arg = Expression::make_integer(&zval, NULL, loc);
+ mpz_clear(zval);
+ }
+ else
+ {
+ len_arg = *parg;
+ if (!this->check_int_value(len_arg))
+ {
+ this->report_error(_("bad size for make"));
+ return Expression::make_error(this->location());
+ }
+ ++parg;
+ }
+
+ Expression* cap_arg = NULL;
+ if (is_slice && parg != args->end())
+ {
+ cap_arg = *parg;
+ if (!this->check_int_value(cap_arg))
+ {
+ this->report_error(_("bad capacity when making slice"));
+ return Expression::make_error(this->location());
+ }
+ ++parg;
+ }
+
+ if (parg != args->end())
+ {
+ this->report_error(_("too many arguments to make"));
+ return Expression::make_error(this->location());
+ }
+
+ Location type_loc = first_arg->location();
+ Expression* type_arg;
+ if (is_slice || is_chan)
+ type_arg = Expression::make_type_descriptor(type, type_loc);
+ else if (is_map)
+ type_arg = Expression::make_map_descriptor(type->map_type(), type_loc);
+ else
+ go_unreachable();
+
+ Expression* call;
+ if (is_slice)
+ {
+ if (cap_arg == NULL)
+ call = Runtime::make_call(Runtime::MAKESLICE1, loc, 2, type_arg,
+ len_arg);
+ else
+ call = Runtime::make_call(Runtime::MAKESLICE2, loc, 3, type_arg,
+ len_arg, cap_arg);
+ }
+ else if (is_map)
+ call = Runtime::make_call(Runtime::MAKEMAP, loc, 2, type_arg, len_arg);
+ else if (is_chan)
+ call = Runtime::make_call(Runtime::MAKECHAN, loc, 2, type_arg, len_arg);
+ else
+ go_unreachable();
+
+ return Expression::make_unsafe_cast(type, call, loc);
+}
+
+// Return whether an expression has an integer value. Report an error
+// if not. This is used when handling calls to the predeclared make
+// function.
+
+bool
+Builtin_call_expression::check_int_value(Expression* e)
+{
+ if (e->type()->integer_type() != NULL)
+ return true;
+
+ // Check for a floating point constant with integer value.
+ mpfr_t fval;
+ mpfr_init(fval);
+
+ Type* dummy;
+ if (e->float_constant_value(fval, &dummy) && mpfr_integer_p(fval))
+ {
+ mpz_t ival;
+ mpz_init(ival);
+
+ bool ok = false;
+
+ mpfr_clear_overflow();
+ mpfr_clear_erangeflag();
+ mpfr_get_z(ival, fval, GMP_RNDN);
+ if (!mpfr_overflow_p()
+ && !mpfr_erangeflag_p()
+ && mpz_sgn(ival) >= 0)
+ {
+ Named_type* ntype = Type::lookup_integer_type("int");
+ Integer_type* inttype = ntype->integer_type();
+ mpz_t max;
+ mpz_init_set_ui(max, 1);
+ mpz_mul_2exp(max, max, inttype->bits() - 1);
+ ok = mpz_cmp(ival, max) < 0;
+ mpz_clear(max);
+ }
+ mpz_clear(ival);
+
+ if (ok)
+ {
+ mpfr_clear(fval);
+ return true;
+ }
+ }
+
+ mpfr_clear(fval);
+
+ return false;
+}
+
+// Return the type of the real or imag functions, given the type of
+// the argument. We need to map complex to float, complex64 to
+// float32, and complex128 to float64, so it has to be done by name.
+// This returns NULL if it can't figure out the type.
+
+Type*
+Builtin_call_expression::real_imag_type(Type* arg_type)
+{
+ if (arg_type == NULL || arg_type->is_abstract())
+ return NULL;
+ Named_type* nt = arg_type->named_type();
+ if (nt == NULL)
+ return NULL;
+ while (nt->real_type()->named_type() != NULL)
+ nt = nt->real_type()->named_type();
+ if (nt->name() == "complex64")
+ return Type::lookup_float_type("float32");
+ else if (nt->name() == "complex128")
+ return Type::lookup_float_type("float64");
+ else
+ return NULL;
+}
+
+// Return the type of the complex function, given the type of one of the
+// argments. Like real_imag_type, we have to map by name.
+
+Type*
+Builtin_call_expression::complex_type(Type* arg_type)
+{
+ if (arg_type == NULL || arg_type->is_abstract())
+ return NULL;
+ Named_type* nt = arg_type->named_type();
+ if (nt == NULL)
+ return NULL;
+ while (nt->real_type()->named_type() != NULL)
+ nt = nt->real_type()->named_type();
+ if (nt->name() == "float32")
+ return Type::lookup_complex_type("complex64");
+ else if (nt->name() == "float64")
+ return Type::lookup_complex_type("complex128");
+ else
+ return NULL;
+}
+
+// Return a single argument, or NULL if there isn't one.
+
+Expression*
+Builtin_call_expression::one_arg() const
+{
+ const Expression_list* args = this->args();
+ if (args->size() != 1)
+ return NULL;
+ 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.
+
+bool
+Builtin_call_expression::do_is_constant() const
+{
+ switch (this->code_)
+ {
+ case BUILTIN_LEN:
+ case BUILTIN_CAP:
+ {
+ if (this->seen_)