summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-11-11 17:49:10 +0000
committerian <ian@138bc75d-0d04-0410-961f-82ee72b054a4>2013-11-11 17:49:10 +0000
commit56080003ab9fddd8f96e2d17958362d450ec4047 (patch)
tree8b4f326394f2f25564ed77844fae26c6a03636e8
parent86669a0739a00da2ee218abda9d66a48010db120 (diff)
downloadgcc-56080003ab9fddd8f96e2d17958362d450ec4047.tar.gz
compiler: Support Go 1.2 nil checks.
git-svn-id: svn+ssh://gcc.gnu.org/svn/gcc/trunk@204679 138bc75d-0d04-0410-961f-82ee72b054a4
-rw-r--r--gcc/go/gofrontend/expressions.cc24
-rw-r--r--gcc/go/gofrontend/expressions.h17
-rw-r--r--gcc/go/gofrontend/types.cc3
3 files changed, 38 insertions, 6 deletions
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index aefb51cec5e..e26bf353e00 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -3633,7 +3633,8 @@ class Unary_expression : public Expression
public:
Unary_expression(Operator op, Expression* expr, Location location)
: Expression(EXPRESSION_UNARY, location),
- op_(op), escapes_(true), create_temp_(false), expr_(expr)
+ op_(op), escapes_(true), create_temp_(false), expr_(expr),
+ issue_nil_check_(false)
{ }
// Return the operator.
@@ -3719,6 +3720,10 @@ class Unary_expression : public Expression
void
do_dump_expression(Ast_dump_context*) const;
+ void
+ do_issue_nil_check()
+ { this->issue_nil_check_ = (this->op_ == OPERATOR_MULT); }
+
private:
// The unary operator to apply.
Operator op_;
@@ -3730,6 +3735,9 @@ class Unary_expression : public Expression
bool create_temp_;
// The operand.
Expression* expr_;
+ // Whether or not to issue a nil check for this expression if its address
+ // is being taken.
+ bool issue_nil_check_;
};
// If we are taking the address of a composite literal, and the
@@ -4107,7 +4115,10 @@ Unary_expression::do_check_types(Gogo*)
this->report_error(_("invalid operand for unary %<&%>"));
}
else
- this->expr_->address_taken(this->escapes_);
+ {
+ this->expr_->address_taken(this->escapes_);
+ this->expr_->issue_nil_check();
+ }
break;
case OPERATOR_MULT:
@@ -4277,12 +4288,13 @@ Unary_expression::do_get_tree(Translate_context* context)
// 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.
+ // pointer dereference. However, if we know the address of this
+ // expression is being taken, we must always check for nil.
tree target_type_tree = TREE_TYPE(TREE_TYPE(expr));
if (!VOID_TYPE_P(target_type_tree))
{
HOST_WIDE_INT s = int_size_in_bytes(target_type_tree);
- if (s == -1 || s >= 4096)
+ if (s == -1 || s >= 4096 || this->issue_nil_check_)
{
if (!DECL_P(expr))
expr = save_expr(expr);
@@ -10402,6 +10414,10 @@ class Array_index_expression : public Expression
do_address_taken(bool escapes)
{ this->array_->address_taken(escapes); }
+ void
+ do_issue_nil_check()
+ { this->array_->issue_nil_check(); }
+
tree
do_get_tree(Translate_context*);
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index a94330dc4d7..47ce4c0a1e5 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -613,6 +613,11 @@ class Expression
address_taken(bool escapes)
{ this->do_address_taken(escapes); }
+ // Note that a nil check must be issued for this expression.
+ void
+ issue_nil_check()
+ { this->do_issue_nil_check(); }
+
// Return whether this expression must be evaluated in order
// according to the order of evaluation rules. This is basically
// true of all expressions with side-effects.
@@ -742,6 +747,11 @@ class Expression
do_address_taken(bool)
{ }
+ // Child class implements issuing a nil check if the address is taken.
+ virtual void
+ do_issue_nil_check()
+ { }
+
// Child class implements whether this expression must be evaluated
// in order.
virtual bool
@@ -1721,6 +1731,9 @@ class Index_expression : public Parser_expression
void
do_dump_expression(Ast_dump_context*) const;
+ void
+ do_issue_nil_check()
+ { this->left_->issue_nil_check(); }
private:
// The expression being indexed.
Expression* left_;
@@ -2011,6 +2024,10 @@ class Field_reference_expression : public Expression
do_address_taken(bool escapes)
{ this->expr_->address_taken(escapes); }
+ void
+ do_issue_nil_check()
+ { this->expr_->issue_nil_check(); }
+
tree
do_get_tree(Translate_context*);
diff --git a/gcc/go/gofrontend/types.cc b/gcc/go/gofrontend/types.cc
index ea68c43714b..551e97a7b6d 100644
--- a/gcc/go/gofrontend/types.cc
+++ b/gcc/go/gofrontend/types.cc
@@ -8847,8 +8847,7 @@ Type::add_local_methods_for_type(const Named_type* nt,
bool is_value_method = (is_embedded_pointer
|| !Type::method_expects_pointer(no));
Method* m = new Named_method(no, field_indexes, depth, is_value_method,
- (needs_stub_method
- || (depth > 0 && is_value_method)));
+ (needs_stub_method || depth > 0));
if (!(*methods)->insert(no->name(), m))
delete m;
}