From: Ian Lance Taylor <iant@golang.org>
To: gcc-patches <gcc-patches@gcc.gnu.org>,
"gofrontend-dev@googlegroups.com"
<gofrontend-dev@googlegroups.com>
Subject: Go patch committed: Add size threshold for nil checks
Date: Fri, 01 Dec 2017 23:18:00 -0000 [thread overview]
Message-ID: <CAOyqgcUrno4i+97jstXsPo4Dmao3kVHsEa0gvRCj-hEj7uj0Dw@mail.gmail.com> (raw)
[-- Attachment #1: Type: text/plain, Size: 872 bytes --]
This patch to the Go frontend by Than McIntosh adds a new control
variable to the Gogo class that stores the size threshold for nil
checks. This value can be used to control the policy for deciding when
a given deference operation needs a check and when it does not. A size
threshold of -1 means that every potentially faulting dereference
needs an explicit check (and branch to error call). A size threshold
of K (where K > 0) means that if the size of the object being
dereferenced is >= K, then we need a check. Currently for gccgo we
keep the same policy: do a nil check for an offset more than 4096.
Bootstrapped and ran Go testsuite on x86_64-pc-linux-gnu. Committed
to mainline.
Ian
2017-12-01 Than McIntosh <thanm@google.com>
* go-c.h (go_create_gogo_args): Add nil_check_size_threshold
field.
* go-lang.c (go_langhook_init): Set nil_check_size_threshold.
[-- Attachment #2: patch.txt --]
[-- Type: text/plain, Size: 31465 bytes --]
Index: gcc/go/go-c.h
===================================================================
--- gcc/go/go-c.h (revision 254090)
+++ gcc/go/go-c.h (working copy)
@@ -47,6 +47,7 @@ struct go_create_gogo_args
bool check_divide_overflow;
bool compiling_runtime;
int debug_escape_level;
+ int64_t nil_check_size_threshold;
};
extern void go_create_gogo (const struct go_create_gogo_args*);
Index: gcc/go/go-lang.c
===================================================================
--- gcc/go/go-lang.c (revision 254090)
+++ gcc/go/go-lang.c (working copy)
@@ -112,6 +112,7 @@ go_langhook_init (void)
args.check_divide_overflow = go_check_divide_overflow;
args.compiling_runtime = go_compiling_runtime;
args.debug_escape_level = go_debug_escape_level;
+ args.nil_check_size_threshold = 4096;
args.linemap = go_get_linemap();
args.backend = go_get_backend();
go_create_gogo (&args);
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE (revision 255266)
+++ gcc/go/gofrontend/MERGE (working copy)
@@ -1,4 +1,4 @@
-0d6b3abcbfe04949db947081651a503ceb12fe6e
+8cd42a3e9e0e618bb09e67be73f7d2f2477a0faa
The first line of this file holds the git revision number of the last
merge done from the gofrontend repository.
Index: gcc/go/gofrontend/expressions.cc
===================================================================
--- gcc/go/gofrontend/expressions.cc (revision 254748)
+++ gcc/go/gofrontend/expressions.cc (working copy)
@@ -290,7 +290,7 @@ Expression::get_interface_type_descripto
Expression::make_interface_info(rhs, INTERFACE_INFO_METHODS, location);
Expression* descriptor =
- Expression::make_unary(OPERATOR_MULT, mtable, location);
+ Expression::make_dereference(mtable, NIL_CHECK_NOT_NEEDED, location);
descriptor = Expression::make_field_reference(descriptor, 0, location);
Expression* nil = Expression::make_nil(location);
@@ -393,7 +393,8 @@ Expression::convert_interface_to_type(Ty
{
obj = Expression::make_unsafe_cast(Type::make_pointer_type(lhs_type), obj,
location);
- obj = Expression::make_unary(OPERATOR_MULT, obj, location);
+ obj = Expression::make_dereference(obj, NIL_CHECK_NOT_NEEDED,
+ location);
}
return Expression::make_compound(check_iface, obj, location);
}
@@ -3842,24 +3843,20 @@ Unary_expression::do_flatten(Gogo* gogo,
&& !this->expr_->is_variable())
{
go_assert(this->expr_->type()->points_to() != NULL);
- Type* ptype = this->expr_->type()->points_to();
- if (!ptype->is_void_type())
+ switch (this->requires_nil_check(gogo))
{
- int64_t s;
- bool ok = ptype->backend_type_size(gogo, &s);
- if (!ok)
+ case NIL_CHECK_ERROR_ENCOUNTERED:
{
go_assert(saw_errors());
return Expression::make_error(this->location());
}
- if (s >= 4096 || this->issue_nil_check_)
- {
- Temporary_statement* temp =
- Statement::make_temporary(NULL, this->expr_, location);
- inserter->insert(temp);
- this->expr_ =
- Expression::make_temporary_reference(temp, location);
- }
+ case NIL_CHECK_NOT_NEEDED:
+ break;
+ case NIL_CHECK_NEEDED:
+ this->create_temp_ = true;
+ break;
+ case NIL_CHECK_DEFAULT:
+ go_unreachable();
}
}
@@ -3960,6 +3957,41 @@ Unary_expression::base_is_static_initial
return false;
}
+// Return whether this dereference expression requires an explicit nil
+// check. If we are dereferencing the pointer to a large struct
+// (greater than the specified size threshold), we need to check for
+// nil. We don't bother to check for small structs because we expect
+// the system to crash on a nil pointer dereference. However, if we
+// know the address of this expression is being taken, we must always
+// check for nil.
+Unary_expression::Nil_check_classification
+Unary_expression::requires_nil_check(Gogo* gogo)
+{
+ go_assert(this->op_ == OPERATOR_MULT);
+ go_assert(this->expr_->type()->points_to() != NULL);
+
+ if (this->issue_nil_check_ == NIL_CHECK_NEEDED)
+ return NIL_CHECK_NEEDED;
+ else if (this->issue_nil_check_ == NIL_CHECK_NOT_NEEDED)
+ return NIL_CHECK_NOT_NEEDED;
+
+ Type* ptype = this->expr_->type()->points_to();
+ int64_t type_size = -1;
+ if (!ptype->is_void_type())
+ {
+ bool ok = ptype->backend_type_size(gogo, &type_size);
+ if (!ok)
+ return NIL_CHECK_ERROR_ENCOUNTERED;
+ }
+
+ int64_t size_cutoff = gogo->nil_check_size_threshold();
+ if (size_cutoff == -1 || (type_size != -1 && type_size >= size_cutoff))
+ this->issue_nil_check_ = NIL_CHECK_NEEDED;
+ else
+ this->issue_nil_check_ = NIL_CHECK_NOT_NEEDED;
+ return this->issue_nil_check_;
+}
+
// Apply unary opcode OP to UNC, setting NC. Return true if this
// could be done, false if not. On overflow, issues an error and sets
// *ISSUED_ERROR.
@@ -4408,43 +4440,42 @@ Unary_expression::do_get_backend(Transla
{
go_assert(this->expr_->type()->points_to() != NULL);
- // If we are dereferencing the pointer to a large struct, we
- // need to check for nil. We don't bother to check for small
- // structs because we expect the system to crash on a nil
- // pointer dereference. However, if we know the address of this
- // expression is being taken, we must always check for nil.
-
+ bool known_valid = false;
Type* ptype = this->expr_->type()->points_to();
Btype* pbtype = ptype->get_backend(gogo);
- if (!ptype->is_void_type())
- {
- int64_t s;
- bool ok = ptype->backend_type_size(gogo, &s);
- if (!ok)
+ switch (this->requires_nil_check(gogo))
+ {
+ case NIL_CHECK_NOT_NEEDED:
+ break;
+ case NIL_CHECK_ERROR_ENCOUNTERED:
{
go_assert(saw_errors());
return gogo->backend()->error_expression();
}
- if (s >= 4096 || this->issue_nil_check_)
- {
+ case NIL_CHECK_NEEDED:
+ {
go_assert(this->expr_->is_variable());
Bexpression* nil =
- Expression::make_nil(loc)->get_backend(context);
+ Expression::make_nil(loc)->get_backend(context);
Bexpression* compare =
gogo->backend()->binary_expression(OPERATOR_EQEQ, bexpr,
nil, loc);
Bexpression* crash =
- gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE,
- loc)->get_backend(context);
+ gogo->runtime_error(RUNTIME_ERROR_NIL_DEREFERENCE,
+ loc)->get_backend(context);
Bfunction* bfn = context->function()->func_value()->get_decl();
bexpr = gogo->backend()->conditional_expression(bfn, btype,
compare,
crash, bexpr,
loc);
-
- }
- }
- ret = gogo->backend()->indirect_expression(pbtype, bexpr, false, loc);
+ known_valid = true;
+ break;
+ }
+ case NIL_CHECK_DEFAULT:
+ go_unreachable();
+ }
+ ret = gogo->backend()->indirect_expression(pbtype, bexpr,
+ known_valid, loc);
}
break;
@@ -4529,6 +4560,19 @@ Expression::make_unary(Operator op, Expr
return new Unary_expression(op, expr, location);
}
+Expression*
+Expression::make_dereference(Expression* ptr,
+ Nil_check_classification docheck,
+ Location location)
+{
+ Expression* deref = Expression::make_unary(OPERATOR_MULT, ptr, location);
+ if (docheck == NIL_CHECK_NEEDED)
+ deref->unary_expression()->set_requires_nil_check(true);
+ else if (docheck == NIL_CHECK_NOT_NEEDED)
+ deref->unary_expression()->set_requires_nil_check(false);
+ return deref;
+}
+
// If this is an indirection through a pointer, return the expression
// being pointed through. Otherwise return this.
@@ -6829,7 +6873,7 @@ Bound_method_expression::create_thunk(Go
// Field 0 of the closure is the function code pointer, field 1 is
// the value on which to invoke the method.
Expression* arg = Expression::make_var_reference(cp, loc);
- arg = Expression::make_unary(OPERATOR_MULT, arg, loc);
+ arg = Expression::make_dereference(arg, NIL_CHECK_NOT_NEEDED, loc);
arg = Expression::make_field_reference(arg, 1, loc);
Expression* bme = Expression::make_bound_method(arg, method, fn, loc);
@@ -6893,7 +6937,8 @@ bme_check_nil(const Method::Field_indexe
Expression::make_nil(loc),
loc);
cond = Expression::make_binary(OPERATOR_OROR, cond, n, loc);
- *ref = Expression::make_unary(OPERATOR_MULT, *ref, loc);
+ *ref = Expression::make_dereference(*ref, Expression::NIL_CHECK_DEFAULT,
+ loc);
go_assert((*ref)->type()->struct_type() == stype);
}
*ref = Expression::make_field_reference(*ref, field_indexes->field_index,
@@ -6948,7 +6993,7 @@ Bound_method_expression::do_flatten(Gogo
Expression* val = expr;
if (fntype->receiver()->type()->points_to() == NULL
&& val->type()->points_to() != NULL)
- val = Expression::make_unary(OPERATOR_MULT, val, loc);
+ val = Expression::make_dereference(val, NIL_CHECK_DEFAULT, loc);
// Note that we are ignoring this->expr_type_ here. The thunk will
// expect a closure whose second field has type this->expr_type_ (if
@@ -8919,7 +8964,8 @@ Builtin_call_expression::do_get_backend(
arg_type = arg_type->points_to();
go_assert(arg_type->array_type() != NULL
&& !arg_type->is_slice_type());
- arg = Expression::make_unary(OPERATOR_MULT, arg, location);
+ arg = Expression::make_dereference(arg, NIL_CHECK_DEFAULT,
+ location);
}
Type* int_type = Type::lookup_integer_type("int");
@@ -8953,8 +8999,9 @@ Builtin_call_expression::do_get_backend(
arg, nil, location);
Expression* zero = Expression::make_integer_ul(0, int_type,
location);
- Expression* indir = Expression::make_unary(OPERATOR_MULT,
- arg, location);
+ Expression* indir =
+ Expression::make_dereference(arg, NIL_CHECK_NOT_NEEDED,
+ location);
val = Expression::make_conditional(cmp, zero, indir, location);
}
else
@@ -8995,8 +9042,9 @@ Builtin_call_expression::do_get_backend(
arg, nil, location);
Expression* zero = Expression::make_integer_ul(0, int_type,
location);
- Expression* indir = Expression::make_unary(OPERATOR_MULT,
- parg, location);
+ Expression* indir =
+ Expression::make_dereference(parg, NIL_CHECK_NOT_NEEDED,
+ location);
val = Expression::make_conditional(cmp, zero, indir, location);
}
else
@@ -10274,7 +10322,7 @@ Call_expression::do_get_backend(Translat
Type::make_pointer_type(
Type::make_pointer_type(Type::make_void_type()));
fn = Expression::make_unsafe_cast(pfntype, this->fn_, location);
- fn = Expression::make_unary(OPERATOR_MULT, fn, location);
+ fn = Expression::make_dereference(fn, NIL_CHECK_NOT_NEEDED, location);
}
else
{
@@ -10532,8 +10580,8 @@ Index_expression::do_lower(Gogo*, Named_
&& type->points_to()->array_type() != NULL
&& !type->points_to()->is_slice_type())
{
- Expression* deref = Expression::make_unary(OPERATOR_MULT, left,
- location);
+ Expression* deref =
+ Expression::make_dereference(left, NIL_CHECK_DEFAULT, location);
// For an ordinary index into the array, the pointer will be
// dereferenced. For a slice it will not--the resulting slice
@@ -11297,7 +11345,8 @@ String_index_expression::do_get_backend(
Location loc = this->location();
Expression* string_arg = this->string_;
if (this->string_->type()->points_to() != NULL)
- string_arg = Expression::make_unary(OPERATOR_MULT, this->string_, loc);
+ string_arg = Expression::make_dereference(this->string_,
+ NIL_CHECK_NOT_NEEDED, loc);
Expression* bad_index = Expression::check_bounds(this->start_, loc);
@@ -11531,8 +11580,9 @@ Map_index_expression::do_get_backend(Tra
go_assert(this->value_pointer_ != NULL
&& this->value_pointer_->is_variable());
- Expression* val = Expression::make_unary(OPERATOR_MULT, this->value_pointer_,
- this->location());
+ Expression* val = Expression::make_dereference(this->value_pointer_,
+ NIL_CHECK_NOT_NEEDED,
+ this->location());
return val->get_backend(context);
}
@@ -11768,7 +11818,7 @@ Interface_field_reference_expression::ge
Expression* ref = this->expr_;
Location loc = this->location();
if (ref->type()->points_to() != NULL)
- ref = Expression::make_unary(OPERATOR_MULT, ref, loc);
+ ref = Expression::make_dereference(ref, NIL_CHECK_DEFAULT, loc);
Expression* mtable =
Expression::make_interface_info(ref, INTERFACE_INFO_METHODS, loc);
@@ -11778,7 +11828,8 @@ Interface_field_reference_expression::ge
unsigned int index;
const Struct_field* field = mtable_type->find_local_field(name, &index);
go_assert(field != NULL);
- mtable = Expression::make_unary(OPERATOR_MULT, mtable, loc);
+
+ mtable = Expression::make_dereference(mtable, NIL_CHECK_NOT_NEEDED, loc);
return Expression::make_field_reference(mtable, index, loc);
}
@@ -11790,7 +11841,8 @@ Interface_field_reference_expression::ge
{
Expression* expr = this->expr_;
if (expr->type()->points_to() != NULL)
- expr = Expression::make_unary(OPERATOR_MULT, expr, this->location());
+ expr = Expression::make_dereference(expr, NIL_CHECK_DEFAULT,
+ this->location());
return Expression::make_interface_info(expr, INTERFACE_INFO_OBJECT,
this->location());
}
@@ -11963,7 +12015,7 @@ Interface_field_reference_expression::cr
// Field 0 of the closure is the function code pointer, field 1 is
// the value on which to invoke the method.
Expression* arg = Expression::make_var_reference(cp, loc);
- arg = Expression::make_unary(OPERATOR_MULT, arg, loc);
+ arg = Expression::make_dereference(arg, NIL_CHECK_NOT_NEEDED, loc);
arg = Expression::make_field_reference(arg, 1, loc);
Expression *ifre = Expression::make_interface_field_reference(arg, name,
Index: gcc/go/gofrontend/expressions.h
===================================================================
--- gcc/go/gofrontend/expressions.h (revision 254748)
+++ gcc/go/gofrontend/expressions.h (working copy)
@@ -506,6 +506,23 @@ class Expression
static Expression*
make_backend(Bexpression*, Type*, Location);
+ enum Nil_check_classification
+ {
+ // Use the default policy for deciding if this deref needs a check.
+ NIL_CHECK_DEFAULT,
+ // An explicit check is required for this dereference operation.
+ NIL_CHECK_NEEDED,
+ // No check needed for this dereference operation.
+ NIL_CHECK_NOT_NEEDED,
+ // A type error or error construct was encountered when determining
+ // whether this deref needs an explicit check.
+ NIL_CHECK_ERROR_ENCOUNTERED
+ };
+
+ // Make a dereference expression.
+ static Expression*
+ make_dereference(Expression*, Nil_check_classification, Location);
+
// Return the expression classification.
Expression_classification
classification() const
@@ -1730,7 +1747,8 @@ class Unary_expression : public Expressi
Unary_expression(Operator op, Expression* expr, Location location)
: Expression(EXPRESSION_UNARY, location),
op_(op), escapes_(true), create_temp_(false), is_gc_root_(false),
- is_slice_init_(false), expr_(expr), issue_nil_check_(false)
+ is_slice_init_(false), expr_(expr),
+ issue_nil_check_(NIL_CHECK_DEFAULT)
{ }
// Return the operator.
@@ -1792,6 +1810,17 @@ class Unary_expression : public Expressi
static Expression*
do_import(Import*);
+ // Declare that this deref does or does not require an explicit nil check.
+ void
+ set_requires_nil_check(bool needed)
+ {
+ go_assert(this->op_ == OPERATOR_MULT);
+ if (needed)
+ this->issue_nil_check_ = NIL_CHECK_NEEDED;
+ else
+ this->issue_nil_check_ = NIL_CHECK_NOT_NEEDED;
+ }
+
protected:
int
do_traverse(Traverse* traverse)
@@ -1847,12 +1876,20 @@ class Unary_expression : public Expressi
void
do_issue_nil_check()
- { this->issue_nil_check_ = (this->op_ == OPERATOR_MULT); }
+ {
+ if (this->op_ == OPERATOR_MULT)
+ this->set_requires_nil_check(true);
+ }
private:
static bool
base_is_static_initializer(Expression*);
+ // Return a determination as to whether this dereference expression
+ // requires a nil check.
+ Nil_check_classification
+ requires_nil_check(Gogo*);
+
// The unary operator to apply.
Operator op_;
// Normally true. False if this is an address expression which does
@@ -1874,7 +1911,7 @@ class Unary_expression : public Expressi
Expression* expr_;
// Whether or not to issue a nil check for this expression if its address
// is being taken.
- bool issue_nil_check_;
+ Nil_check_classification issue_nil_check_;
};
// A binary expression.
Index: gcc/go/gofrontend/go.cc
===================================================================
--- gcc/go/gofrontend/go.cc (revision 254090)
+++ gcc/go/gofrontend/go.cc (working copy)
@@ -41,6 +41,7 @@ go_create_gogo(const struct go_create_go
if (args->c_header != NULL)
::gogo->set_c_header(args->c_header);
::gogo->set_debug_escape_level(args->debug_escape_level);
+ ::gogo->set_nil_check_size_threshold(args->nil_check_size_threshold);
}
// Parse the input files.
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc (revision 254748)
+++ gcc/go/gofrontend/gogo.cc (working copy)
@@ -55,6 +55,7 @@ Gogo::Gogo(Backend* backend, Linemap* li
check_divide_overflow_(true),
compiling_runtime_(false),
debug_escape_level_(0),
+ nil_check_size_threshold_(4096),
verify_types_(),
interface_types_(),
specific_type_functions_(),
@@ -5567,7 +5568,10 @@ Function::build(Gogo* gogo, Named_object
vars.push_back(bvar);
Expression* parm_ref =
Expression::make_var_reference(parm_no, loc);
- parm_ref = Expression::make_unary(OPERATOR_MULT, parm_ref, loc);
+ parm_ref =
+ Expression::make_dereference(parm_ref,
+ Expression::NIL_CHECK_DEFAULT,
+ loc);
if ((*p)->var_value()->is_in_heap())
parm_ref = Expression::make_heap_expression(parm_ref, loc);
var_inits.push_back(parm_ref->get_backend(&context));
Index: gcc/go/gofrontend/gogo.h
===================================================================
--- gcc/go/gofrontend/gogo.h (revision 255062)
+++ gcc/go/gofrontend/gogo.h (working copy)
@@ -318,6 +318,20 @@ class Gogo
set_debug_escape_level(int level)
{ this->debug_escape_level_ = level; }
+ // Return the size threshold used to determine whether to issue
+ // a nil-check for a given pointer dereference. A threshold of -1
+ // implies that all potentially faulting dereference ops should
+ // be nil-checked. A positive threshold of N implies that a deref
+ // of *P where P has size less than N doesn't need a nil check.
+ int64_t
+ nil_check_size_threshold() const
+ { return this->nil_check_size_threshold_; }
+
+ // Set the nil-check size threshold, as described above.
+ void
+ set_nil_check_size_threshold(int64_t bytes)
+ { this->nil_check_size_threshold_ = bytes; }
+
// Import a package. FILENAME is the file name argument, LOCAL_NAME
// is the local name to give to the package. If LOCAL_NAME is empty
// the declarations are added to the global scope.
@@ -1025,6 +1039,8 @@ class Gogo
// The level of escape analysis debug information to emit, from the
// -fgo-debug-escape option.
int debug_escape_level_;
+ // Nil-check size threshhold.
+ int64_t nil_check_size_threshold_;
// A list of types to verify.
std::vector<Type*> verify_types_;
// A list of interface types defined while parsing.
Index: gcc/go/gofrontend/parse.cc
===================================================================
--- gcc/go/gofrontend/parse.cc (revision 255062)
+++ gcc/go/gofrontend/parse.cc (working copy)
@@ -2745,14 +2745,17 @@ Parse::enclosing_var_reference(Named_obj
Expression* closure_ref = Expression::make_var_reference(closure,
location);
- closure_ref = Expression::make_unary(OPERATOR_MULT, closure_ref, location);
+ closure_ref =
+ Expression::make_dereference(closure_ref,
+ Expression::NIL_CHECK_DEFAULT,
+ location);
// The closure structure holds pointers to the variables, so we need
// to introduce an indirection.
Expression* e = Expression::make_field_reference(closure_ref,
ins.first->index(),
location);
- e = Expression::make_unary(OPERATOR_MULT, e, location);
+ e = Expression::make_dereference(e, Expression::NIL_CHECK_DEFAULT, location);
return Expression::make_enclosing_var_reference(e, var, location);
}
Index: gcc/go/gofrontend/statements.cc
===================================================================
--- gcc/go/gofrontend/statements.cc (revision 254983)
+++ gcc/go/gofrontend/statements.cc (working copy)
@@ -315,7 +315,8 @@ Variable_declaration_statement::do_get_b
if (binit != NULL)
{
Expression* e = Expression::make_temporary_reference(temp, loc);
- e = Expression::make_unary(OPERATOR_MULT, e, loc);
+ e = Expression::make_dereference(e, Expression::NIL_CHECK_NOT_NEEDED,
+ loc);
Bexpression* be = e->get_backend(context);
set = context->backend()->assignment_statement(bfunction, be, binit, loc);
}
@@ -740,7 +741,9 @@ Assignment_statement::do_lower(Gogo*, Na
a1, a2, a3);
Type* ptrval_type = Type::make_pointer_type(mt->val_type());
call = Expression::make_cast(ptrval_type, call, loc);
- Expression* indir = Expression::make_unary(OPERATOR_MULT, call, loc);
+ Expression* indir =
+ Expression::make_dereference(call, Expression::NIL_CHECK_NOT_NEEDED,
+ loc);
ref = Expression::make_temporary_reference(val_temp, loc);
b->add_statement(Statement::make_assignment(indir, ref, loc));
@@ -1292,7 +1295,8 @@ Tuple_map_assignment_statement::do_lower
// val = *val__ptr_temp
ref = Expression::make_temporary_reference(val_ptr_temp, loc);
- Expression* ind = Expression::make_unary(OPERATOR_MULT, ref, loc);
+ Expression* ind =
+ Expression::make_dereference(ref, Expression::NIL_CHECK_NOT_NEEDED, loc);
s = Statement::make_assignment(this->val_, ind, loc);
b->add_statement(s);
@@ -2367,8 +2371,10 @@ Thunk_statement::build_thunk(Gogo* gogo,
// ones used in build_struct.
Expression* thunk_parameter = Expression::make_var_reference(named_parameter,
location);
- thunk_parameter = Expression::make_unary(OPERATOR_MULT, thunk_parameter,
- location);
+ thunk_parameter =
+ Expression::make_dereference(thunk_parameter,
+ Expression::NIL_CHECK_NOT_NEEDED,
+ location);
Interface_field_reference_expression* interface_method =
ce->fn()->interface_field_reference_expression();
@@ -2421,8 +2427,10 @@ Thunk_statement::build_thunk(Gogo* gogo,
{
Expression* thunk_param =
Expression::make_var_reference(named_parameter, location);
- thunk_param =
- Expression::make_unary(OPERATOR_MULT, thunk_param, location);
+ thunk_param =
+ Expression::make_dereference(thunk_param,
+ Expression::NIL_CHECK_NOT_NEEDED,
+ location);
param = Expression::make_field_reference(thunk_param,
next_index,
location);
@@ -5837,7 +5845,8 @@ For_range_statement::lower_range_map(Gog
Expression* lhs = Expression::make_temporary_reference(index_temp, loc);
Expression* rhs = Expression::make_temporary_reference(hiter, loc);
rhs = Expression::make_field_reference(ref, 0, loc);
- rhs = Expression::make_unary(OPERATOR_MULT, ref, loc);
+ rhs = Expression::make_dereference(ref, Expression::NIL_CHECK_NOT_NEEDED,
+ loc);
Statement* set = Statement::make_assignment(lhs, rhs, loc);
iter_init->add_statement(set);
@@ -5846,7 +5855,8 @@ For_range_statement::lower_range_map(Gog
lhs = Expression::make_temporary_reference(value_temp, loc);
rhs = Expression::make_temporary_reference(hiter, loc);
rhs = Expression::make_field_reference(rhs, 1, loc);
- rhs = Expression::make_unary(OPERATOR_MULT, rhs, loc);
+ rhs = Expression::make_dereference(rhs, Expression::NIL_CHECK_NOT_NEEDED,
+ loc);
set = Statement::make_assignment(lhs, rhs, loc);
iter_init->add_statement(set);
}
Index: gcc/go/gofrontend/types.cc
===================================================================
--- gcc/go/gofrontend/types.cc (revision 255266)
+++ gcc/go/gofrontend/types.cc (working copy)
@@ -2215,10 +2215,10 @@ Type::write_named_equal(Gogo* gogo, Name
// Compare the values for equality.
Expression* t1 = Expression::make_temporary_reference(p1, bloc);
- t1 = Expression::make_unary(OPERATOR_MULT, t1, bloc);
+ t1 = Expression::make_dereference(t1, Expression::NIL_CHECK_NOT_NEEDED, bloc);
Expression* t2 = Expression::make_temporary_reference(p2, bloc);
- t2 = Expression::make_unary(OPERATOR_MULT, t2, bloc);
+ t2 = Expression::make_dereference(t2, Expression::NIL_CHECK_NOT_NEEDED, bloc);
Expression* cond = Expression::make_binary(OPERATOR_EQEQ, t1, t2, bloc);
@@ -5911,7 +5911,9 @@ Struct_type::field_reference_depth(Expre
Expression* here = Expression::make_field_reference(struct_expr, i,
location);
if (pf->type()->points_to() != NULL)
- here = Expression::make_unary(OPERATOR_MULT, here, location);
+ here = Expression::make_dereference(here,
+ Expression::NIL_CHECK_DEFAULT,
+ location);
while (sub->expr() != NULL)
{
sub = sub->expr()->deref()->field_reference_expression();
@@ -6342,11 +6344,13 @@ Struct_type::write_equal_function(Gogo*
// Compare one field in both P1 and P2.
Expression* f1 = Expression::make_temporary_reference(p1, bloc);
- f1 = Expression::make_unary(OPERATOR_MULT, f1, bloc);
+ f1 = Expression::make_dereference(f1, Expression::NIL_CHECK_DEFAULT,
+ bloc);
f1 = Expression::make_field_reference(f1, field_index, bloc);
Expression* f2 = Expression::make_temporary_reference(p2, bloc);
- f2 = Expression::make_unary(OPERATOR_MULT, f2, bloc);
+ f2 = Expression::make_dereference(f2, Expression::NIL_CHECK_DEFAULT,
+ bloc);
f2 = Expression::make_field_reference(f2, field_index, bloc);
Expression* cond = Expression::make_binary(OPERATOR_NOTEQ, f1, f2, bloc);
@@ -7193,12 +7197,12 @@ Array_type::write_equal_function(Gogo* g
// Compare element in P1 and P2.
Expression* e1 = Expression::make_temporary_reference(p1, bloc);
- e1 = Expression::make_unary(OPERATOR_MULT, e1, bloc);
+ e1 = Expression::make_dereference(e1, Expression::NIL_CHECK_DEFAULT, bloc);
ref = Expression::make_temporary_reference(index, bloc);
e1 = Expression::make_array_index(e1, ref, NULL, NULL, bloc);
Expression* e2 = Expression::make_temporary_reference(p2, bloc);
- e2 = Expression::make_unary(OPERATOR_MULT, e2, bloc);
+ e2 = Expression::make_dereference(e2, Expression::NIL_CHECK_DEFAULT, bloc);
ref = Expression::make_temporary_reference(index, bloc);
e2 = Expression::make_array_index(e2, ref, NULL, NULL, bloc);
@@ -11219,7 +11223,8 @@ Type::apply_field_indexes(Expression* ex
if (expr->type()->struct_type() == NULL)
{
go_assert(expr->type()->points_to() != NULL);
- expr = Expression::make_unary(OPERATOR_MULT, expr, location);
+ expr = Expression::make_dereference(expr, Expression::NIL_CHECK_DEFAULT,
+ location);
go_assert(expr->type()->struct_type() == stype);
}
return Expression::make_field_reference(expr, field_indexes->field_index,
@@ -11323,7 +11328,8 @@ Type::bind_field_or_method(Gogo* gogo, c
&& type->points_to() != NULL
&& type->points_to()->points_to() != NULL)
{
- expr = Expression::make_unary(OPERATOR_MULT, expr, location);
+ expr = Expression::make_dereference(expr, Expression::NIL_CHECK_DEFAULT,
+ location);
type = type->points_to();
if (type->deref()->is_error_type())
return Expression::make_error(location);
@@ -11356,8 +11362,9 @@ Type::bind_field_or_method(Gogo* gogo, c
return Expression::make_error(location);
}
go_assert(type->points_to() != NULL);
- expr = Expression::make_unary(OPERATOR_MULT, expr,
- location);
+ expr = Expression::make_dereference(expr,
+ Expression::NIL_CHECK_DEFAULT,
+ location);
go_assert(expr->type()->struct_type() == st);
}
ret = st->field_reference(expr, name, location);
Index: gcc/go/gofrontend/wb.cc
===================================================================
--- gcc/go/gofrontend/wb.cc (revision 254748)
+++ gcc/go/gofrontend/wb.cc (working copy)
@@ -417,7 +417,8 @@ Gogo::assign_with_write_barrier(Function
rhs = Expression::make_temporary_reference(rhs_temp, loc);
}
- Expression* indir = Expression::make_unary(OPERATOR_MULT, lhs, loc);
+ Expression* indir =
+ Expression::make_dereference(lhs, Expression::NIL_CHECK_DEFAULT, loc);
Statement* assign = Statement::make_assignment(indir, rhs, loc);
lhs = Expression::make_temporary_reference(lhs_temp, loc);
reply other threads:[~2017-12-01 23:18 UTC|newest]
Thread overview: [no followups] expand[flat|nested] mbox.gz Atom feed
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=CAOyqgcUrno4i+97jstXsPo4Dmao3kVHsEa0gvRCj-hEj7uj0Dw@mail.gmail.com \
--to=iant@golang.org \
--cc=gcc-patches@gcc.gnu.org \
--cc=gofrontend-dev@googlegroups.com \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for read-only IMAP folder(s) and NNTP newsgroup(s).