bool issued_error)
{
std::string reason;
- bool ok;
- if (this->are_hidden_fields_ok_)
- ok = Type::are_assignable_hidden_ok(parameter_type, argument_type,
- &reason);
- else
- ok = Type::are_assignable(parameter_type, argument_type, &reason);
- if (!ok)
+ if (!Type::are_assignable(parameter_type, argument_type, &reason))
{
if (!issued_error)
{
go_assert(this->args_ != NULL && !this->args_->empty());
Type* rtype = fntype->receiver()->type();
Expression* first_arg = this->args_->front();
- // The language permits copying hidden fields for a method
- // receiver. We dereference the values since receivers are
- // always passed as pointers.
+ // We dereference the values since receivers are always passed
+ // as pointers.
std::string reason;
- if (!Type::are_assignable_hidden_ok(rtype->deref(),
- first_arg->type()->deref(),
- &reason))
+ if (!Type::are_assignable(rtype->deref(), first_arg->type()->deref(),
+ &reason))
{
if (reason.empty())
this->report_error(_("incompatible type for receiver"));
: Expression(EXPRESSION_CALL, location),
fn_(fn), args_(args), type_(NULL), results_(NULL), call_(NULL),
call_temp_(NULL), expected_result_count_(0), is_varargs_(is_varargs),
- are_hidden_fields_ok_(false), varargs_are_lowered_(false),
- types_are_determined_(false), is_deferred_(false), issued_error_(false)
+ varargs_are_lowered_(false), types_are_determined_(false),
+ is_deferred_(false), issued_error_(false)
{ }
// The function to call.
set_varargs_are_lowered()
{ this->varargs_are_lowered_ = true; }
- // Note that it is OK for this call to set hidden fields when
- // passing arguments.
- void
- set_hidden_fields_are_ok()
- { this->are_hidden_fields_ok_ = true; }
-
// Whether this call is being deferred.
bool
is_deferred() const
size_t expected_result_count_;
// True if the last argument is a varargs argument (f(a...)).
bool is_varargs_;
- // True if this statement may pass hidden fields in the arguments.
- // This is used for generated method stubs.
- bool are_hidden_fields_ok_;
// True if varargs have already been lowered.
bool varargs_are_lowered_;
// True if types have been determined.
if (this->type_ != NULL && this->init_ != NULL)
{
std::string reason;
- bool ok;
- if (this->are_hidden_fields_ok_)
- ok = Type::are_assignable_hidden_ok(this->type_, this->init_->type(),
- &reason);
- else
- ok = Type::are_assignable(this->type_, this->init_->type(), &reason);
- if (!ok)
+ if (!Type::are_assignable(this->type_, this->init_->type(), &reason))
{
if (reason.empty())
error_at(this->location(), "incompatible types in assignment");
Assignment_statement(Expression* lhs, Expression* rhs,
Location location)
: Statement(STATEMENT_ASSIGNMENT, location),
- lhs_(lhs), rhs_(rhs), are_hidden_fields_ok_(false)
+ lhs_(lhs), rhs_(rhs)
{ }
- // Note that it is OK for this assignment statement to set hidden
- // fields.
- void
- set_hidden_fields_are_ok()
- { this->are_hidden_fields_ok_ = true; }
-
protected:
int
do_traverse(Traverse* traverse);
Expression* lhs_;
// Right hand side--the rvalue.
Expression* rhs_;
- // True if this statement may set hidden fields in the assignment
- // statement. This is used for generated method stubs.
- bool are_hidden_fields_ok_;
};
// Traversal.
}
std::string reason;
- bool ok;
- if (this->are_hidden_fields_ok_)
- ok = Type::are_assignable_hidden_ok(lhs_type, rhs_type, &reason);
- else
- ok = Type::are_assignable(lhs_type, rhs_type, &reason);
- if (!ok)
+ if (!Type::are_assignable(lhs_type, rhs_type, &reason))
{
if (reason.empty())
error_at(this->location(), "incompatible types in assignment");
Tuple_assignment_statement(Expression_list* lhs, Expression_list* rhs,
Location location)
: Statement(STATEMENT_TUPLE_ASSIGNMENT, location),
- lhs_(lhs), rhs_(rhs), are_hidden_fields_ok_(false)
+ lhs_(lhs), rhs_(rhs)
{ }
- // Note that it is OK for this assignment statement to set hidden
- // fields.
- void
- set_hidden_fields_are_ok()
- { this->are_hidden_fields_ok_ = true; }
-
protected:
int
do_traverse(Traverse* traverse);
Expression_list* lhs_;
// Right hand side--a list of rvalues.
Expression_list* rhs_;
- // True if this statement may set hidden fields in the assignment
- // statement. This is used for generated method stubs.
- bool are_hidden_fields_ok_;
};
// Traversal.
Temporary_statement* temp = Statement::make_temporary((*plhs)->type(),
*prhs, loc);
- if (this->are_hidden_fields_ok_)
- temp->set_hidden_fields_are_ok();
b->add_statement(temp);
temps.push_back(temp);
continue;
Expression* ref = Expression::make_temporary_reference(*ptemp, loc);
- Statement* s = Statement::make_assignment(*plhs, ref, loc);
- if (this->are_hidden_fields_ok_)
- {
- Assignment_statement* as = static_cast<Assignment_statement*>(s);
- as->set_hidden_fields_are_ok();
- }
- b->add_statement(s);
+ b->add_statement(Statement::make_assignment(*plhs, ref, loc));
++ptemp;
}
go_assert(ptemp == temps.end() || saw_errors());
e->determine_type(&type_context);
std::string reason;
- bool ok;
- if (this->are_hidden_fields_ok_)
- ok = Type::are_assignable_hidden_ok(rvtype, e->type(), &reason);
- else
- ok = Type::are_assignable(rvtype, e->type(), &reason);
- if (ok)
+ if (Type::are_assignable(rvtype, e->type(), &reason))
{
Expression* ve = Expression::make_var_reference(rv, e->location());
lhs->push_back(ve);
;
else if (lhs->size() == 1)
{
- Statement* s = Statement::make_assignment(lhs->front(), rhs->front(),
- loc);
- if (this->are_hidden_fields_ok_)
- {
- Assignment_statement* as = static_cast<Assignment_statement*>(s);
- as->set_hidden_fields_are_ok();
- }
- b->add_statement(s);
+ b->add_statement(Statement::make_assignment(lhs->front(), rhs->front(),
+ loc));
delete lhs;
delete rhs;
}
else
- {
- Statement* s = Statement::make_tuple_assignment(lhs, rhs, loc);
- if (this->are_hidden_fields_ok_)
- {
- Tuple_assignment_statement* tas =
- static_cast<Tuple_assignment_statement*>(s);
- tas->set_hidden_fields_are_ok();
- }
- b->add_statement(s);
- }
+ b->add_statement(Statement::make_tuple_assignment(lhs, rhs, loc));
b->add_statement(this);
public:
Temporary_statement(Type* type, Expression* init, Location location)
: Statement(STATEMENT_TEMPORARY, location),
- type_(type), init_(init), bvariable_(NULL), are_hidden_fields_ok_(false),
- is_address_taken_(false)
+ type_(type), init_(init), bvariable_(NULL), is_address_taken_(false)
{ }
// Return the type of the temporary variable.
init() const
{ return this->init_; }
- // Note that it is OK for this statement to set hidden fields.
- void
- set_hidden_fields_are_ok()
- { this->are_hidden_fields_ok_ = true; }
-
// Record that something takes the address of this temporary
// variable.
void
Expression* init_;
// The backend representation of the temporary variable.
Bvariable* bvariable_;
- // True if this statement may set hidden fields when assigning the
- // value to the temporary. This is used for generated method stubs.
- bool are_hidden_fields_ok_;
// True if something takes the address of this temporary variable.
bool is_address_taken_;
};
public:
Return_statement(Expression_list* vals, Location location)
: Statement(STATEMENT_RETURN, location),
- vals_(vals), are_hidden_fields_ok_(false), is_lowered_(false)
+ vals_(vals), is_lowered_(false)
{ }
// The list of values being returned. This may be NULL.
vals() const
{ return this->vals_; }
- // Note that it is OK for this return statement to set hidden
- // fields.
- void
- set_hidden_fields_are_ok()
- { this->are_hidden_fields_ok_ = true; }
-
protected:
int
do_traverse(Traverse* traverse)
private:
// Return values. This may be NULL.
Expression_list* vals_;
- // True if this statement may pass hidden fields in the return
- // value. This is used for generated method stubs.
- bool are_hidden_fields_ok_;
// True if this statement has been lowered.
bool is_lowered_;
};
}
// Return true if a value with type RHS may be assigned to a variable
-// with type LHS. If CHECK_HIDDEN_FIELDS is true, check whether any
-// hidden fields are modified. If REASON is not NULL, set *REASON to
-// the reason the types are not assignable.
+// with type LHS. If REASON is not NULL, set *REASON to the reason
+// the types are not assignable.
bool
-Type::are_assignable_check_hidden(const Type* lhs, const Type* rhs,
- bool check_hidden_fields,
- std::string* reason)
+Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason)
{
// Do some checks first. Make sure the types are defined.
if (rhs != NULL && !rhs->is_undefined())
}
}
- if (lhs != NULL && !lhs->is_undefined())
- {
- // Any value may be assigned to the blank identifier.
- if (lhs->is_sink_type())
- return true;
-
- // All fields of a struct must be exported, or the assignment
- // must be in the same package.
- if (check_hidden_fields && rhs != NULL && !rhs->is_undefined())
- {
- if (lhs->has_hidden_fields(NULL, reason)
- || rhs->has_hidden_fields(NULL, reason))
- return false;
- }
- }
+ // Any value may be assigned to the blank identifier.
+ if (lhs != NULL
+ && !lhs->is_undefined()
+ && lhs->is_sink_type())
+ return true;
// Identical types are assignable.
if (Type::are_identical(lhs, rhs, true, reason))
return false;
}
-// Return true if a value with type RHS may be assigned to a variable
-// with type LHS. If REASON is not NULL, set *REASON to the reason
-// the types are not assignable.
-
-bool
-Type::are_assignable(const Type* lhs, const Type* rhs, std::string* reason)
-{
- return Type::are_assignable_check_hidden(lhs, rhs, false, reason);
-}
-
-// Like are_assignable but don't check for hidden fields.
-
-bool
-Type::are_assignable_hidden_ok(const Type* lhs, const Type* rhs,
- std::string* reason)
-{
- return Type::are_assignable_check_hidden(lhs, rhs, false, reason);
-}
-
// Return true if a value with type RHS may be converted to type LHS.
// If REASON is not NULL, set *REASON to the reason the types are not
// convertible.
return false;
}
-// Return whether this type has any hidden fields. This is only a
-// possibility for a few types.
-
-bool
-Type::has_hidden_fields(const Named_type* within, std::string* reason) const
-{
- switch (this->forwarded()->classification_)
- {
- case TYPE_NAMED:
- return this->named_type()->named_type_has_hidden_fields(reason);
- case TYPE_STRUCT:
- return this->struct_type()->struct_has_hidden_fields(within, reason);
- case TYPE_ARRAY:
- return this->array_type()->array_has_hidden_fields(within, reason);
- default:
- return false;
- }
-}
-
// Return a hash code for the type to be used for method lookup.
unsigned int
return true;
}
-// Whether this struct type has any hidden fields.
-
-bool
-Struct_type::struct_has_hidden_fields(const Named_type* within,
- std::string* reason) const
-{
- const Struct_field_list* fields = this->fields();
- if (fields == NULL)
- return false;
- const Package* within_package = (within == NULL
- ? NULL
- : within->named_object()->package());
- for (Struct_field_list::const_iterator pf = fields->begin();
- pf != fields->end();
- ++pf)
- {
- if (within_package != NULL
- && !pf->is_anonymous()
- && Gogo::is_hidden_name(pf->field_name()))
- {
- if (reason != NULL)
- {
- std::string within_name = within->named_object()->message_name();
- std::string name = Gogo::message_name(pf->field_name());
- size_t bufsize = 200 + within_name.length() + name.length();
- char* buf = new char[bufsize];
- snprintf(buf, bufsize,
- _("implicit assignment of %s%s%s hidden field %s%s%s"),
- open_quote, within_name.c_str(), close_quote,
- open_quote, name.c_str(), close_quote);
- reason->assign(buf);
- delete[] buf;
- }
- return true;
- }
-
- if (pf->type()->has_hidden_fields(within, reason))
- return true;
- }
-
- return false;
-}
-
// Whether comparisons of this struct type are simple identity
// comparisons.
&this->pointer_interface_method_tables_);
}
-// Return whether a named type has any hidden fields.
-
-bool
-Named_type::named_type_has_hidden_fields(std::string* reason) const
-{
- if (this->seen_)
- return false;
- this->seen_ = true;
- bool ret = this->type_->has_hidden_fields(this, reason);
- this->seen_ = false;
- return ret;
-}
-
// Look for a use of a complete type within another type. This is
// used to check that we don't try to use a type within itself.
go_assert(func != NULL);
Call_expression* call = Expression::make_call(func, arguments, is_varargs,
location);
- call->set_hidden_fields_are_ok();
- Statement* s = Statement::make_return_from_call(call, location);
- Return_statement* retstat = s->return_statement();
- if (retstat != NULL)
- {
- // We can return values with hidden fields from a stub. This is
- // necessary if the method is itself hidden.
- retstat->set_hidden_fields_are_ok();
- }
- gogo->add_statement(s);
+ gogo->add_statement(Statement::make_return_from_call(call, location));
}
// Apply FIELD_INDEXES to EXPR. The field indexes have to be applied
static bool
are_assignable(const Type* lhs, const Type* rhs, std::string* reason);
- // Return true if a value with type RHS is assignable to a variable
- // with type LHS, ignoring any assignment of hidden fields
- // (unexported fields of a type imported from another package).
- // This is like the are_assignable method.
- static bool
- are_assignable_hidden_ok(const Type* lhs, const Type* rhs,
- std::string* reason);
-
// Return true if a value with type RHS may be converted to type
// LHS. If this returns false, and REASON is not NULL, it sets
// *REASON.
static bool
are_convertible(const Type* lhs, const Type* rhs, std::string* reason);
- // Whether this type has any hidden fields which are not visible in
- // the current compilation, such as a field whose name begins with a
- // lower case letter in a struct imported from a different package.
- // WITHIN is not NULL if we are looking at fields in a named type.
- bool
- has_hidden_fields(const Named_type* within, std::string* reason) const;
-
// Return true if values of this type can be compared using an
// identity function which gets nothing but a pointer to the value
// and a size.
: NULL);
}
- // Support for are_assignable and are_assignable_hidden_ok.
- static bool
- are_assignable_check_hidden(const Type* lhs, const Type* rhs,
- bool check_hidden_fields, std::string* reason);
-
// Map unnamed types to type descriptor decls.
typedef Unordered_map_hash(const Type*, Bvariable*, Type_hash_identical,
Type_identical) Type_descriptor_vars;
bool
is_identical(const Struct_type* t, bool errors_are_identical) const;
- // Whether this struct type has any hidden fields. This returns
- // true if any fields have hidden names, or if any non-pointer
- // anonymous fields have types with hidden fields.
- bool
- struct_has_hidden_fields(const Named_type* within, std::string*) const;
-
// Return whether NAME is a local field which is not exported. This
// is only used for better error reporting.
bool
bool
is_identical(const Array_type* t, bool errors_are_identical) const;
- // Whether this type has any hidden fields.
- bool
- array_has_hidden_fields(const Named_type* within, std::string* reason) const
- { return this->element_type_->has_hidden_fields(within, reason); }
-
// Return an expression for the pointer to the values in an array.
Expression*
get_value_pointer(Gogo*, Expression* array) const;
Expression*
interface_method_table(Interface_type* interface, bool is_pointer);
- // Whether this type has any hidden fields.
- bool
- named_type_has_hidden_fields(std::string* reason) const;
-
// Note that a type must be converted to the backend representation
// before we convert this type.
void
bool is_circular_;
// Whether this type has been verified.
bool is_verified_;
- // In a recursive operation such as has_hidden_fields, this flag is
- // used to prevent infinite recursion when a type refers to itself.
- // This is mutable because it is always reset to false when the
- // function exits.
+ // In a recursive operation such as has_pointer, this flag is used
+ // to prevent infinite recursion when a type refers to itself. This
+ // is mutable because it is always reset to false when the function
+ // exits.
mutable bool seen_;
// Like seen_, but used only by do_compare_is_identity.
bool seen_in_compare_is_identity_;