class Gogo;
class Translate_context;
class Traverse;
+class Statement_inserter;
class Type;
struct Type_context;
class Function_type;
class Interface_field_reference_expression;
class Type_guard_expression;
class Receive_expression;
-class Send_expression;
class Named_object;
class Export;
class Import;
class Temporary_statement;
class Label;
+class Ast_dump_context;
+class String_dump;
// The base class for all expressions.
EXPRESSION_FIELD_REFERENCE,
EXPRESSION_INTERFACE_FIELD_REFERENCE,
EXPRESSION_ALLOCATION,
- EXPRESSION_MAKE,
EXPRESSION_TYPE_GUARD,
EXPRESSION_CONVERSION,
+ EXPRESSION_UNSAFE_CONVERSION,
EXPRESSION_STRUCT_CONSTRUCTION,
EXPRESSION_FIXED_ARRAY_CONSTRUCTION,
EXPRESSION_OPEN_ARRAY_CONSTRUCTION,
EXPRESSION_COMPOSITE_LITERAL,
EXPRESSION_HEAP_COMPOSITE,
EXPRESSION_RECEIVE,
- EXPRESSION_SEND,
EXPRESSION_TYPE_DESCRIPTOR,
EXPRESSION_TYPE_INFO,
EXPRESSION_STRUCT_FIELD_OFFSET,
+ EXPRESSION_MAP_DESCRIPTOR,
EXPRESSION_LABEL_ADDR
};
// Make a reference to a temporary variable. Temporary variables
// are always created by a single statement, which is what we use to
// refer to them.
- static Expression*
+ static Temporary_reference_expression*
make_temporary_reference(Temporary_statement*, source_location);
// Make a sink expression--a reference to the blank identifier _.
// Make an expression which is a method bound to its first
// parameter.
static Bound_method_expression*
- make_bound_method(Expression* object, Expression* method, source_location);
+ make_bound_method(Expression* object, Named_object* method, source_location);
// Make an index or slice expression. This is a parser expression
// which represents LEFT[START:END]. END may be NULL, meaning an
static Expression*
make_allocation(Type*, source_location);
- // Make a call to the builtin function make.
- static Expression*
- make_make(Type*, Expression_list*, source_location);
-
// Make a type guard expression.
static Expression*
make_type_guard(Expression*, Type*, source_location);
static Expression*
make_cast(Type*, Expression*, source_location);
+ // Make an unsafe type cast expression. This is only used when
+ // passing parameter to builtin functions that are part of the Go
+ // runtime.
+ static Expression*
+ make_unsafe_cast(Type*, Expression*, source_location);
+
// Make a composite literal. The DEPTH parameter is how far down we
// are in a list of composite literals with omitted types.
static Expression*
static Receive_expression*
make_receive(Expression* channel, source_location);
- // Make a send expression.
- static Send_expression*
- make_send(Expression* channel, Expression* val, source_location);
-
- // Make an expression which evaluates to the type descriptor of a
- // type.
+ // Make an expression which evaluates to the address of the type
+ // descriptor for TYPE.
static Expression*
make_type_descriptor(Type* type, source_location);
static Expression*
make_struct_field_offset(Struct_type*, const Struct_field*);
+ // Make an expression which evaluates to the address of the map
+ // descriptor for TYPE.
+ static Expression*
+ make_map_descriptor(Map_type* type, source_location);
+
// Make an expression which evaluates to the address of an unnamed
// label.
static Expression*
// This is called by the parser if the value of this expression is
// being discarded. This issues warnings about computed values
- // being unused, and handles send expressions which act differently
- // depending upon whether the value is used.
+ // being unused.
void
discarding_value()
{ this->do_discarding_value(); }
traverse_subexpressions(Traverse*);
// Lower an expression. This is called immediately after parsing.
- // IOTA_VALUE is the value that we should give to any iota
- // expressions. This function must resolve expressions which could
- // not be fully parsed into their final form. It returns the same
- // Expression or a new one.
+ // FUNCTION is the function we are in; it will be NULL for an
+ // expression initializing a global variable. INSERTER may be used
+ // to insert statements before the statement or initializer
+ // containing this expression; it is normally used to create
+ // temporary variables. IOTA_VALUE is the value that we should give
+ // to any iota expressions. This function must resolve expressions
+ // which could not be fully parsed into their final form. It
+ // returns the same Expression or a new one.
Expression*
- lower(Gogo* gogo, Named_object* function, int iota_value)
- { return this->do_lower(gogo, function, iota_value); }
+ lower(Gogo* gogo, Named_object* function, Statement_inserter* inserter,
+ int iota_value)
+ { return this->do_lower(gogo, function, inserter, iota_value); }
// Determine the real type of an expression with abstract integer,
// floating point, or complex type. TYPE_CONTEXT describes the
static tree
check_bounds(tree val, tree bound_type, tree sofar, source_location);
+ // Dump an expression to a dump constext.
+ void
+ dump_expression(Ast_dump_context*) const;
+
protected:
// May be implemented by child class: traverse the expressions.
virtual int
// Return a lowered expression.
virtual Expression*
- do_lower(Gogo*, Named_object*, int)
+ do_lower(Gogo*, Named_object*, Statement_inserter*, int)
{ return this; }
// Return whether this is a constant expression.
void
report_error(const char*);
+ // Child class implements dumping to a dump context.
+ virtual void
+ do_dump_expression(Ast_dump_context*) const = 0;
+
private:
// Convert to the desired statement classification, or return NULL.
// This is a controlled dynamic cast.
protected:
virtual Expression*
- do_lower(Gogo*, Named_object*, int) = 0;
+ do_lower(Gogo*, Named_object*, Statement_inserter*, int) = 0;
Type*
- do_type()
- { gcc_unreachable(); }
+ do_type();
void
do_determine_type(const Type_context*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
void
do_check_types(Gogo*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
tree
do_get_tree(Translate_context*)
- { gcc_unreachable(); }
+ { go_unreachable(); }
};
// An expression which is simply a variable.
named_object() const
{ return this->variable_; }
- // Return the name of the variable.
- const std::string&
- name() const;
-
protected:
Expression*
- do_lower(Gogo*, Named_object*, int);
+ do_lower(Gogo*, Named_object*, Statement_inserter*, int);
Type*
do_type();
void
- do_determine_type(const Type_context*)
- { }
+ do_determine_type(const Type_context*);
Expression*
do_copy()
tree
do_get_tree(Translate_context*);
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
private:
// The variable we are referencing.
Named_object* variable_;
Temporary_reference_expression(Temporary_statement* statement,
source_location location)
: Expression(EXPRESSION_TEMPORARY_REFERENCE, location),
- statement_(statement)
+ statement_(statement), is_lvalue_(false)
{ }
+ // Indicate that this reference appears on the left hand side of an
+ // assignment statement.
+ void
+ set_is_lvalue()
+ { this->is_lvalue_ = true; }
+
protected:
Type*
do_type();
tree
do_get_tree(Translate_context*);
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
private:
// The statement where the temporary variable is defined.
Temporary_statement* statement_;
+ // Whether this reference appears on the left hand side of an
+ // assignment statement.
+ bool is_lvalue_;
};
// A string expression.
tree
do_get_tree(Translate_context*);
+ // Write string literal to a string dump.
+ static void
+ export_string(String_dump* exp, const String_expression* str);
+
void
do_export(Export*) const;
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
private:
// The string value. This is immutable.
const std::string val_;
do_traverse(Traverse* traverse);
Expression*
- do_lower(Gogo*, Named_object*, int);
+ do_lower(Gogo*, Named_object*, Statement_inserter*, int);
bool
do_is_constant() const
void
do_export(Export*) const;
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
private:
// The binary operator to apply.
Operator op_;
Call_expression(Expression* fn, Expression_list* args, bool is_varargs,
source_location location)
: Expression(EXPRESSION_CALL, location),
- fn_(fn), args_(args), type_(NULL), tree_(NULL), is_varargs_(is_varargs),
- is_value_discarded_(false), varargs_are_lowered_(false),
- is_deferred_(false)
+ fn_(fn), args_(args), type_(NULL), results_(NULL), tree_(NULL),
+ is_varargs_(is_varargs), are_hidden_fields_ok_(false),
+ varargs_are_lowered_(false), types_are_determined_(false),
+ is_deferred_(false), issued_error_(false)
{ }
// The function to call.
size_t
result_count() const;
+ // Return the temporary variable which holds result I. This is only
+ // valid after the expression has been lowered, and is only valid
+ // for calls which return multiple results.
+ Temporary_statement*
+ result(size_t i) const;
+
// Return whether this is a call to the predeclared function
// recover.
bool
is_varargs() const
{ return this->is_varargs_; }
+ // Note that varargs have already been lowered.
+ void
+ 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
set_is_deferred()
{ this->is_deferred_ = true; }
+ // We have found an error with this call expression; return true if
+ // we should report it.
+ bool
+ issue_error();
+
protected:
int
do_traverse(Traverse*);
virtual Expression*
- do_lower(Gogo*, Named_object*, int);
+ do_lower(Gogo*, Named_object*, Statement_inserter*, int);
void
do_discarding_value()
- { this->is_value_discarded_ = true; }
+ { }
virtual Type*
do_type();
{ this->args_ = args; }
// Let a builtin expression lower varargs.
- Expression*
- lower_varargs(Gogo*, Named_object* function, Type* varargs_type,
- size_t param_count);
+ void
+ lower_varargs(Gogo*, Named_object* function, Statement_inserter* inserter,
+ Type* varargs_type, size_t param_count);
- private:
+ // Let a builtin expression check whether types have been
+ // determined.
bool
- is_compatible_varargs_argument(Named_object*, Expression*, Type*, bool*);
+ determining_types();
+
+ void
+ do_dump_expression(Ast_dump_context*) const;
+ private:
bool
check_argument_type(int, const Type*, const Type*, source_location, bool);
tree
- bound_method_function(Translate_context*, Bound_method_expression*, tree*);
-
- tree
interface_method_function(Translate_context*,
Interface_field_reference_expression*,
tree*);
+ tree
+ set_results(Translate_context*, tree);
+
// The function to call.
Expression* fn_;
// The arguments to pass. This may be NULL if there are no
Expression_list* args_;
// The type of the expression, to avoid recomputing it.
Type* type_;
+ // The list of temporaries which will hold the results if the
+ // function returns a tuple.
+ std::vector<Temporary_statement*>* results_;
// The tree for the call, used for a call which returns a tuple.
tree tree_;
// True if the last argument is a varargs argument (f(a...)).
bool is_varargs_;
- // True if the value is being discarded.
- bool is_value_discarded_;
+ // 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.
+ bool types_are_determined_;
// True if the call is an argument to a defer statement.
bool is_deferred_;
+ // True if we reported an error about a mismatch between call
+ // results and uses. This is to avoid producing multiple errors
+ // when there are multiple Call_result_expressions.
+ bool issued_error_;
};
// An expression which represents a pointer to a function.
named_object() const
{ return this->function_; }
- // Return the name of the function.
- const std::string&
- name() const;
-
// Return the closure for this function. This will return NULL if
// the function has no closure, which is the normal case.
Expression*
do_copy()
{
return Expression::make_func_reference(this->function_,
- this->closure_->copy(),
+ (this->closure_ == NULL
+ ? NULL
+ : this->closure_->copy()),
this->location());
}
tree
do_get_tree(Translate_context*);
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
private:
// The function itself.
Named_object* function_;
protected:
Expression*
- do_lower(Gogo*, Named_object*, int);
+ do_lower(Gogo*, Named_object*, Statement_inserter*, int);
Expression*
do_copy()
{ return new Unknown_expression(this->named_object_, this->location()); }
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
private:
// The unknown name.
Named_object* named_object_;
set_is_lvalue()
{ this->is_lvalue_ = true; }
+ // Dump an index expression, i.e. an expression of the form
+ // expr[expr] or expr[expr:expr], to a dump context.
+ static void
+ dump_index_expression(Ast_dump_context*, const Expression* expr,
+ const Expression* start, const Expression* end);
+
protected:
int
do_traverse(Traverse*);
Expression*
- do_lower(Gogo*, Named_object*, int);
+ do_lower(Gogo*, Named_object*, Statement_inserter*, int);
Expression*
do_copy()
this->location());
}
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
private:
// The expression being indexed.
Expression* left_;
tree
do_get_tree(Translate_context*);
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
private:
// The map we are looking into.
Expression* map_;
class Bound_method_expression : public Expression
{
public:
- Bound_method_expression(Expression* expr, Expression* method,
+ Bound_method_expression(Expression* expr, Named_object* method,
source_location location)
: Expression(EXPRESSION_BOUND_METHOD, location),
expr_(expr), expr_type_(NULL), method_(method)
first_argument_type() const
{ return this->expr_type_; }
- // Return the reference to the method function.
- Expression*
+ // Return the method function.
+ Named_object*
method()
{ return this->method_; }
Expression*
do_copy()
{
- return new Bound_method_expression(this->expr_->copy(),
- this->method_->copy(),
+ return new Bound_method_expression(this->expr_->copy(), this->method_,
this->location());
}
tree
do_get_tree(Translate_context*);
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
private:
// The object used to find the method. This is passed to the method
// as the first argument.
// NULL in the normal case, non-NULL when using a method from an
// anonymous field which does not require a stub.
Type* expr_type_;
- // The method itself. This is a Func_expression.
- Expression* method_;
+ // The method itself.
+ Named_object* method_;
};
// A reference to a field in a struct.
void
set_struct_expression(Expression* expr)
{
- gcc_assert(this->expr_ == NULL);
+ go_assert(this->expr_ == NULL);
this->expr_ = expr;
}
tree
do_get_tree(Translate_context*);
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
private:
// The expression we are looking into. This should have a type of
// struct.
tree
do_get_tree(Translate_context*);
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
private:
// The expression for the interface object. This should have a type
// of interface or pointer to interface.
tree
do_get_tree(Translate_context*);
+ void
+ do_dump_expression(Ast_dump_context*) const;
+
private:
// The expression to convert.
Expression* expr_;
public:
Receive_expression(Expression* channel, source_location location)
: Expression(EXPRESSION_RECEIVE, location),
- channel_(channel), is_value_discarded_(false), for_select_(false)
+ channel_(channel), for_select_(false)
{ }
// Return the channel.
void
do_discarding_value()
- { this->is_value_discarded_ = true; }
+ { }
Type*
do_type();
tree
do_get_tree(Translate_context*);
- private:
- // The channel from which we are receiving.
- Expression* channel_;
- // Whether the value is being discarded.
- bool is_value_discarded_;
- // Whether this is for a select statement.
- bool for_select_;
-};
-
-// A send expression.
-
-class Send_expression : public Expression
-{
- public:
- Send_expression(Expression* channel, Expression* val,
- source_location location)
- : Expression(EXPRESSION_SEND, location),
- channel_(channel), val_(val), is_value_discarded_(false),
- for_select_(false)
- { }
-
- // Note that this is for a select statement.
- void
- set_for_select()
- { this->for_select_ = true; }
-
- protected:
- int
- do_traverse(Traverse* traverse);
-
- void
- do_discarding_value()
- { this->is_value_discarded_ = true; }
-
- Type*
- do_type();
-
- void
- do_determine_type(const Type_context*);
-
void
- do_check_types(Gogo*);
-
- Expression*
- do_copy()
- {
- return Expression::make_send(this->channel_->copy(), this->val_->copy(),
- this->location());
- }
-
- bool
- do_must_eval_in_order() const
- { return true; }
-
- tree
- do_get_tree(Translate_context*);
+ do_dump_expression(Ast_dump_context*) const;
private:
- // The channel on which to send the value.
+ // The channel from which we are receiving.
Expression* channel_;
- // The value to send.
- Expression* val_;
- // Whether the value is being discarded.
- bool is_value_discarded_;
// Whether this is for a select statement.
bool for_select_;
};