diff options
Diffstat (limited to 'gcc-4.9/gcc/go/gofrontend/expressions.h')
-rw-r--r-- | gcc-4.9/gcc/go/gofrontend/expressions.h | 2488 |
1 files changed, 2488 insertions, 0 deletions
diff --git a/gcc-4.9/gcc/go/gofrontend/expressions.h b/gcc-4.9/gcc/go/gofrontend/expressions.h new file mode 100644 index 000000000..99a0d0720 --- /dev/null +++ b/gcc-4.9/gcc/go/gofrontend/expressions.h @@ -0,0 +1,2488 @@ +// expressions.h -- Go frontend expression handling. -*- C++ -*- + +// Copyright 2009 The Go Authors. All rights reserved. +// Use of this source code is governed by a BSD-style +// license that can be found in the LICENSE file. + +#ifndef GO_EXPRESSIONS_H +#define GO_EXPRESSIONS_H + +#include <mpfr.h> + +#include "operator.h" + +class Gogo; +class Translate_context; +class Traverse; +class Statement_inserter; +class Type; +class Method; +struct Type_context; +class Integer_type; +class Float_type; +class Complex_type; +class Function_type; +class Map_type; +class Struct_type; +class Struct_field; +class Expression_list; +class Var_expression; +class Temporary_reference_expression; +class Set_and_use_temporary_expression; +class String_expression; +class Binary_expression; +class Call_expression; +class Func_expression; +class Func_descriptor_expression; +class Unknown_expression; +class Index_expression; +class Map_index_expression; +class Bound_method_expression; +class Field_reference_expression; +class Interface_field_reference_expression; +class Type_guard_expression; +class Receive_expression; +class Numeric_constant; +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. + +class Expression +{ + public: + // The types of expressions. + enum Expression_classification + { + EXPRESSION_ERROR, + EXPRESSION_TYPE, + EXPRESSION_UNARY, + EXPRESSION_BINARY, + EXPRESSION_CONST_REFERENCE, + EXPRESSION_VAR_REFERENCE, + EXPRESSION_TEMPORARY_REFERENCE, + EXPRESSION_SET_AND_USE_TEMPORARY, + EXPRESSION_SINK, + EXPRESSION_FUNC_REFERENCE, + EXPRESSION_FUNC_DESCRIPTOR, + EXPRESSION_FUNC_CODE_REFERENCE, + EXPRESSION_UNKNOWN_REFERENCE, + EXPRESSION_BOOLEAN, + EXPRESSION_STRING, + EXPRESSION_INTEGER, + EXPRESSION_FLOAT, + EXPRESSION_COMPLEX, + EXPRESSION_NIL, + EXPRESSION_IOTA, + EXPRESSION_CALL, + EXPRESSION_CALL_RESULT, + EXPRESSION_BOUND_METHOD, + EXPRESSION_INDEX, + EXPRESSION_ARRAY_INDEX, + EXPRESSION_STRING_INDEX, + EXPRESSION_MAP_INDEX, + EXPRESSION_SELECTOR, + EXPRESSION_FIELD_REFERENCE, + EXPRESSION_INTERFACE_FIELD_REFERENCE, + EXPRESSION_ALLOCATION, + EXPRESSION_TYPE_GUARD, + EXPRESSION_CONVERSION, + EXPRESSION_UNSAFE_CONVERSION, + EXPRESSION_STRUCT_CONSTRUCTION, + EXPRESSION_FIXED_ARRAY_CONSTRUCTION, + EXPRESSION_OPEN_ARRAY_CONSTRUCTION, + EXPRESSION_MAP_CONSTRUCTION, + EXPRESSION_COMPOSITE_LITERAL, + EXPRESSION_HEAP_COMPOSITE, + EXPRESSION_RECEIVE, + EXPRESSION_TYPE_DESCRIPTOR, + EXPRESSION_TYPE_INFO, + EXPRESSION_SLICE_INFO, + EXPRESSION_INTERFACE_INFO, + EXPRESSION_STRUCT_FIELD_OFFSET, + EXPRESSION_MAP_DESCRIPTOR, + EXPRESSION_LABEL_ADDR, + EXPRESSION_CONDITIONAL + }; + + Expression(Expression_classification, Location); + + virtual ~Expression(); + + // Make an error expression. This is used when a parse error occurs + // to prevent cascading errors. + static Expression* + make_error(Location); + + // Make an expression which is really a type. This is used during + // parsing. + static Expression* + make_type(Type*, Location); + + // Make a unary expression. + static Expression* + make_unary(Operator, Expression*, Location); + + // Make a binary expression. + static Expression* + make_binary(Operator, Expression*, Expression*, Location); + + // Make a reference to a constant in an expression. + static Expression* + make_const_reference(Named_object*, Location); + + // Make a reference to a variable in an expression. + static Expression* + make_var_reference(Named_object*, Location); + + // 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 Temporary_reference_expression* + make_temporary_reference(Temporary_statement*, Location); + + // Make an expressions which sets a temporary variable and then + // evaluates to a reference to that temporary variable. This is + // used to set a temporary variable while retaining the order of + // evaluation. + static Set_and_use_temporary_expression* + make_set_and_use_temporary(Temporary_statement*, Expression*, Location); + + // Make a sink expression--a reference to the blank identifier _. + static Expression* + make_sink(Location); + + // Make a reference to a function in an expression. This returns a + // pointer to the struct holding the address of the function + // followed by any closed-over variables. + static Expression* + make_func_reference(Named_object*, Expression* closure, Location); + + // Make a function descriptor, an immutable struct with a single + // field that points to the function code. This may only be used + // with functions that do not have closures. FN is the function for + // which we are making the descriptor. + static Func_descriptor_expression* + make_func_descriptor(Named_object* fn); + + // Make a reference to the code of a function. This is used to set + // descriptor and closure fields. + static Expression* + make_func_code_reference(Named_object*, Location); + + // Make a reference to an unknown name. In a correct program this + // will always be lowered to a real const/var/func reference. + static Unknown_expression* + make_unknown_reference(Named_object*, Location); + + // Make a constant bool expression. + static Expression* + make_boolean(bool val, Location); + + // Make a constant string expression. + static Expression* + make_string(const std::string&, Location); + + // Make a character constant expression. TYPE should be NULL for an + // abstract type. + static Expression* + make_character(const mpz_t*, Type*, Location); + + // Make a constant integer expression. TYPE should be NULL for an + // abstract type. + static Expression* + make_integer(const mpz_t*, Type*, Location); + + // Make a constant float expression. TYPE should be NULL for an + // abstract type. + static Expression* + make_float(const mpfr_t*, Type*, Location); + + // Make a constant complex expression. TYPE should be NULL for an + // abstract type. + static Expression* + make_complex(const mpfr_t* real, const mpfr_t* imag, Type*, Location); + + // Make a nil expression. + static Expression* + make_nil(Location); + + // Make an iota expression. This is used for the predeclared + // constant iota. + static Expression* + make_iota(); + + // Make a call expression. + static Call_expression* + make_call(Expression* func, Expression_list* args, bool is_varargs, + Location); + + // Make a reference to a specific result of a call expression which + // returns a tuple. + static Expression* + make_call_result(Call_expression*, unsigned int index); + + // Make an expression which is a method bound to its first + // parameter. METHOD is the method being called, FUNCTION is the + // function to call. + static Bound_method_expression* + make_bound_method(Expression* object, const Method* method, + Named_object* function, Location); + + // Make an index or slice expression. This is a parser expression + // which represents LEFT[START:END:CAP]. END may be NULL, meaning an + // index rather than a slice. CAP may be NULL, meaning we use the default + // capacity of LEFT. At parse time we may not know the type of LEFT. + // After parsing this is lowered to an array index, a string index, + // or a map index. + static Expression* + make_index(Expression* left, Expression* start, Expression* end, + Expression* cap, Location); + + // Make an array index expression. END may be NULL, in which case + // this is an lvalue. CAP may be NULL, in which case it defaults + // to cap(ARRAY). + static Expression* + make_array_index(Expression* array, Expression* start, Expression* end, + Expression* cap, Location); + + // Make a string index expression. END may be NULL. This is never + // an lvalue. + static Expression* + make_string_index(Expression* string, Expression* start, Expression* end, + Location); + + // Make a map index expression. This is an lvalue. + static Map_index_expression* + make_map_index(Expression* map, Expression* val, Location); + + // Make a selector. This is a parser expression which represents + // LEFT.NAME. At parse time we may not know the type of the left + // hand side. + static Expression* + make_selector(Expression* left, const std::string& name, Location); + + // Make a reference to a field in a struct. + static Field_reference_expression* + make_field_reference(Expression*, unsigned int field_index, Location); + + // Make a reference to a field of an interface, with an associated + // object. + static Expression* + make_interface_field_reference(Expression*, const std::string&, + Location); + + // Make an allocation expression. + static Expression* + make_allocation(Type*, Location); + + // Make a type guard expression. + static Expression* + make_type_guard(Expression*, Type*, Location); + + // Make a type cast expression. + static Expression* + make_cast(Type*, Expression*, 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*, Location); + + // Make a composite literal. The DEPTH parameter is how far down we + // are in a list of composite literals with omitted types. HAS_KEYS + // is true if the expression list has keys alternating with values. + // ALL_ARE_NAMES is true if all the keys could be struct field + // names. + static Expression* + make_composite_literal(Type*, int depth, bool has_keys, Expression_list*, + bool all_are_names, Location); + + // Make a struct composite literal. + static Expression* + make_struct_composite_literal(Type*, Expression_list*, Location); + + // Make a slice composite literal. + static Expression* + make_slice_composite_literal(Type*, Expression_list*, Location); + + // Take a composite literal and allocate it on the heap. + static Expression* + make_heap_composite(Expression*, Location); + + // Make a receive expression. VAL is NULL for a unary receive. + static Receive_expression* + make_receive(Expression* channel, Location); + + // Make an expression which evaluates to the address of the type + // descriptor for TYPE. + static Expression* + make_type_descriptor(Type* type, Location); + + // Make an expression which evaluates to some characteristic of a + // type. These are only used for type descriptors, so there is no + // location parameter. + enum Type_info + { + // The size of a value of the type. + TYPE_INFO_SIZE, + // The required alignment of a value of the type. + TYPE_INFO_ALIGNMENT, + // The required alignment of a value of the type when used as a + // field in a struct. + TYPE_INFO_FIELD_ALIGNMENT + }; + + static Expression* + make_type_info(Type* type, Type_info); + + // Make an expression that evaluates to some characteristic of a + // slice. For simplicity, the enum values must match the field indexes + // in the underlying struct. + enum Slice_info + { + // The underlying data of the slice. + SLICE_INFO_VALUE_POINTER, + // The length of the slice. + SLICE_INFO_LENGTH, + // The capacity of the slice. + SLICE_INFO_CAPACITY + }; + + static Expression* + make_slice_info(Expression* slice, Slice_info, Location); + + + // Make an expression that evaluates to some characteristic of a + // interface. For simplicity, the enum values must match the field indexes + // of a non-empty interface in the underlying struct. + enum Interface_info + { + // The methods of an interface. + INTERFACE_INFO_METHODS, + // The first argument to pass to an interface method. + INTERFACE_INFO_OBJECT + }; + + static Expression* + make_interface_info(Expression* iface, Interface_info, Location); + + // Make an expression which evaluates to the offset of a field in a + // struct. This is only used for type descriptors, so there is no + // location parameter. + 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, Location); + + // Make an expression which evaluates to the address of an unnamed + // label. + static Expression* + make_label_addr(Label*, Location); + + // Make a conditional expression. + static Expression* + make_conditional(Expression*, Expression*, Expression*, Location); + + // Return the expression classification. + Expression_classification + classification() const + { return this->classification_; } + + // Return the location of the expression. + Location + location() const + { return this->location_; } + + // Return whether this is a constant expression. + bool + is_constant() const + { return this->do_is_constant(); } + + // Return whether this is an immutable expression. + bool + is_immutable() const + { return this->do_is_immutable(); } + + // If this is not a numeric constant, return false. If it is one, + // return true, and set VAL to hold the value. + bool + numeric_constant_value(Numeric_constant* val) const + { return this->do_numeric_constant_value(val); } + + // If this is not a constant expression with string type, return + // false. If it is one, return true, and set VAL to the value. + bool + string_constant_value(std::string* val) const + { return this->do_string_constant_value(val); } + + // This is called if the value of this expression is being + // discarded. This issues warnings about computed values being + // unused. This returns true if all is well, false if it issued an + // error message. + bool + discarding_value() + { return this->do_discarding_value(); } + + // Return whether this is an error expression. + bool + is_error_expression() const + { return this->classification_ == EXPRESSION_ERROR; } + + // Return whether this expression really represents a type. + bool + is_type_expression() const + { return this->classification_ == EXPRESSION_TYPE; } + + // If this is a variable reference, return the Var_expression + // structure. Otherwise, return NULL. This is a controlled dynamic + // cast. + Var_expression* + var_expression() + { return this->convert<Var_expression, EXPRESSION_VAR_REFERENCE>(); } + + const Var_expression* + var_expression() const + { return this->convert<const Var_expression, EXPRESSION_VAR_REFERENCE>(); } + + // If this is a reference to a temporary variable, return the + // Temporary_reference_expression. Otherwise, return NULL. + Temporary_reference_expression* + temporary_reference_expression() + { + return this->convert<Temporary_reference_expression, + EXPRESSION_TEMPORARY_REFERENCE>(); + } + + // If this is a set-and-use-temporary, return the + // Set_and_use_temporary_expression. Otherwise, return NULL. + Set_and_use_temporary_expression* + set_and_use_temporary_expression() + { + return this->convert<Set_and_use_temporary_expression, + EXPRESSION_SET_AND_USE_TEMPORARY>(); + } + + // Return whether this is a sink expression. + bool + is_sink_expression() const + { return this->classification_ == EXPRESSION_SINK; } + + // If this is a string expression, return the String_expression + // structure. Otherwise, return NULL. + String_expression* + string_expression() + { return this->convert<String_expression, EXPRESSION_STRING>(); } + + // Return whether this is the expression nil. + bool + is_nil_expression() const + { return this->classification_ == EXPRESSION_NIL; } + + // If this is an indirection through a pointer, return the + // expression being pointed through. Otherwise return this. + Expression* + deref(); + + // If this is a binary expression, return the Binary_expression + // structure. Otherwise return NULL. + Binary_expression* + binary_expression() + { return this->convert<Binary_expression, EXPRESSION_BINARY>(); } + + // If this is a call expression, return the Call_expression + // structure. Otherwise, return NULL. This is a controlled dynamic + // cast. + Call_expression* + call_expression() + { return this->convert<Call_expression, EXPRESSION_CALL>(); } + + // If this is an expression which refers to a function, return the + // Func_expression structure. Otherwise, return NULL. + Func_expression* + func_expression() + { return this->convert<Func_expression, EXPRESSION_FUNC_REFERENCE>(); } + + const Func_expression* + func_expression() const + { return this->convert<const Func_expression, EXPRESSION_FUNC_REFERENCE>(); } + + // If this is an expression which refers to an unknown name, return + // the Unknown_expression structure. Otherwise, return NULL. + Unknown_expression* + unknown_expression() + { return this->convert<Unknown_expression, EXPRESSION_UNKNOWN_REFERENCE>(); } + + const Unknown_expression* + unknown_expression() const + { + return this->convert<const Unknown_expression, + EXPRESSION_UNKNOWN_REFERENCE>(); + } + + // If this is an index expression, return the Index_expression + // structure. Otherwise, return NULL. + Index_expression* + index_expression() + { return this->convert<Index_expression, EXPRESSION_INDEX>(); } + + // If this is an expression which refers to indexing in a map, + // return the Map_index_expression structure. Otherwise, return + // NULL. + Map_index_expression* + map_index_expression() + { return this->convert<Map_index_expression, EXPRESSION_MAP_INDEX>(); } + + // If this is a bound method expression, return the + // Bound_method_expression structure. Otherwise, return NULL. + Bound_method_expression* + bound_method_expression() + { return this->convert<Bound_method_expression, EXPRESSION_BOUND_METHOD>(); } + + // If this is a reference to a field in a struct, return the + // Field_reference_expression structure. Otherwise, return NULL. + Field_reference_expression* + field_reference_expression() + { + return this->convert<Field_reference_expression, + EXPRESSION_FIELD_REFERENCE>(); + } + + // If this is a reference to a field in an interface, return the + // Interface_field_reference_expression structure. Otherwise, + // return NULL. + Interface_field_reference_expression* + interface_field_reference_expression() + { + return this->convert<Interface_field_reference_expression, + EXPRESSION_INTERFACE_FIELD_REFERENCE>(); + } + + // If this is a type guard expression, return the + // Type_guard_expression structure. Otherwise, return NULL. + Type_guard_expression* + type_guard_expression() + { return this->convert<Type_guard_expression, EXPRESSION_TYPE_GUARD>(); } + + // If this is a receive expression, return the Receive_expression + // structure. Otherwise, return NULL. + Receive_expression* + receive_expression() + { return this->convert<Receive_expression, EXPRESSION_RECEIVE>(); } + + // Return true if this is a composite literal. + bool + is_composite_literal() const; + + // Return true if this is a composite literal which is not constant. + bool + is_nonconstant_composite_literal() const; + + // Return true if this is a variable or temporary variable. + bool + is_variable() const; + + // Return true if this is a reference to a local variable. + bool + is_local_variable() const; + + // Make the builtin function descriptor type, so that it can be + // converted. + static void + make_func_descriptor_type(); + + // Traverse an expression. + static int + traverse(Expression**, Traverse*); + + // Traverse subexpressions of this expression. + int + traverse_subexpressions(Traverse*); + + // Lower an expression. This is called immediately after parsing. + // 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, Statement_inserter* inserter, + int iota_value) + { return this->do_lower(gogo, function, inserter, iota_value); } + + // Flatten an expression. This is called after order_evaluation. + // 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. 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* + flatten(Gogo* gogo, Named_object* function, Statement_inserter* inserter) + { return this->do_flatten(gogo, function, inserter); } + + // Determine the real type of an expression with abstract integer, + // floating point, or complex type. TYPE_CONTEXT describes the + // expected type. + void + determine_type(const Type_context*); + + // Check types in an expression. + void + check_types(Gogo* gogo) + { this->do_check_types(gogo); } + + // Determine the type when there is no context. + void + determine_type_no_context(); + + // Return the current type of the expression. This may be changed + // by determine_type. + Type* + type() + { return this->do_type(); } + + // Return a copy of an expression. + Expression* + copy() + { return this->do_copy(); } + + // Return whether the expression is addressable--something which may + // be used as the operand of the unary & operator. + bool + is_addressable() const + { return this->do_is_addressable(); } + + // Note that we are taking the address of this expression. ESCAPES + // is true if this address escapes the current function. + void + 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. + bool + must_eval_in_order() const + { return this->do_must_eval_in_order(); } + + // Return whether subexpressions of this expression must be + // evaluated in order. This is true of index expressions and + // pointer indirections. This sets *SKIP to the number of + // subexpressions to skip during traversing, as index expressions + // only requiring moving the index, not the array. + bool + must_eval_subexpressions_in_order(int* skip) const + { + *skip = 0; + return this->do_must_eval_subexpressions_in_order(skip); + } + + // Return the tree for this expression. + tree + get_tree(Translate_context*); + + // Return a tree handling any conversions which must be done during + // assignment. + static tree + convert_for_assignment(Translate_context*, Type* lhs_type, Type* rhs_type, + tree rhs_tree, Location location); + + // Return a tree converting a value of one interface type to another + // interface type. If FOR_TYPE_GUARD is true this is for a type + // assertion. + static tree + convert_interface_to_interface(Translate_context*, Type* lhs_type, + Type* rhs_type, tree rhs_tree, + bool for_type_guard, Location); + + // Return a backend expression implementing the comparison LEFT OP RIGHT. + // TYPE is the type of both sides. + static Bexpression* + comparison(Translate_context*, Type* result_type, Operator op, + Expression* left, Expression* right, Location); + + // Return the backend expression for the numeric constant VAL. + static Bexpression* + backend_numeric_constant_expression(Translate_context*, + Numeric_constant* val); + + // Export the expression. This is only used for constants. It will + // be used for things like values of named constants and sizes of + // arrays. + void + export_expression(Export* exp) const + { this->do_export(exp); } + + // Import an expression. + static Expression* + import_expression(Import*); + + // Return a tree which checks that VAL, of arbitrary integer type, + // is non-negative and is not more than the maximum value of + // BOUND_TYPE. If SOFAR is not NULL, it is or'red into the result. + // The return value may be NULL if SOFAR is NULL. + static tree + check_bounds(tree val, tree bound_type, tree sofar, 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 + do_traverse(Traverse*); + + // Return a lowered expression. + virtual Expression* + do_lower(Gogo*, Named_object*, Statement_inserter*, int) + { return this; } + + // Return a flattened expression. + virtual Expression* + do_flatten(Gogo*, Named_object*, Statement_inserter*) + { return this; } + + + // Return whether this is a constant expression. + virtual bool + do_is_constant() const + { return false; } + + // Return whether this is an immutable expression. + virtual bool + do_is_immutable() const + { return false; } + + // Return whether this is a constant expression of numeric type, and + // set the Numeric_constant to the value. + virtual bool + do_numeric_constant_value(Numeric_constant*) const + { return false; } + + // Return whether this is a constant expression of string type, and + // set VAL to the value. + virtual bool + do_string_constant_value(std::string*) const + { return false; } + + // Called by the parser if the value is being discarded. + virtual bool + do_discarding_value(); + + // Child class holds type. + virtual Type* + do_type() = 0; + + // Child class implements determining type information. + virtual void + do_determine_type(const Type_context*) = 0; + + // Child class implements type checking if needed. + virtual void + do_check_types(Gogo*) + { } + + // Child class implements copying. + virtual Expression* + do_copy() = 0; + + // Child class implements whether the expression is addressable. + virtual bool + do_is_addressable() const + { return false; } + + // Child class implements taking the address of an expression. + virtual void + 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 + do_must_eval_in_order() const + { return false; } + + // Child class implements whether this expressions requires that + // subexpressions be evaluated in order. The child implementation + // may set *SKIP if it should be non-zero. + virtual bool + do_must_eval_subexpressions_in_order(int* /* skip */) const + { return false; } + + // Child class implements conversion to tree. + virtual tree + do_get_tree(Translate_context*) = 0; + + // Child class implements export. + virtual void + do_export(Export*) const; + + // For children to call to give an error for an unused value. + void + unused_value_error(); + + // For children to call when they detect that they are in error. + void + set_is_error(); + + // For children to call to report an error conveniently. + 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. + template<typename Expression_class, + Expression_classification expr_classification> + Expression_class* + convert() + { + return (this->classification_ == expr_classification + ? static_cast<Expression_class*>(this) + : NULL); + } + + template<typename Expression_class, + Expression_classification expr_classification> + const Expression_class* + convert() const + { + return (this->classification_ == expr_classification + ? static_cast<const Expression_class*>(this) + : NULL); + } + + static tree + convert_type_to_interface(Translate_context*, Type*, Type*, tree, + Location); + + static tree + get_interface_type_descriptor(Translate_context*, Type*, tree, + Location); + + static tree + convert_interface_to_type(Translate_context*, Type*, Type*, tree, + Location); + + // The expression classification. + Expression_classification classification_; + // The location in the input file. + Location location_; +}; + +// A list of Expressions. + +class Expression_list +{ + public: + Expression_list() + : entries_() + { } + + // Return whether the list is empty. + bool + empty() const + { return this->entries_.empty(); } + + // Return the number of entries in the list. + size_t + size() const + { return this->entries_.size(); } + + // Add an entry to the end of the list. + void + push_back(Expression* expr) + { this->entries_.push_back(expr); } + + void + append(Expression_list* add) + { this->entries_.insert(this->entries_.end(), add->begin(), add->end()); } + + // Reserve space in the list. + void + reserve(size_t size) + { this->entries_.reserve(size); } + + // Traverse the expressions in the list. + int + traverse(Traverse*); + + // Copy the list. + Expression_list* + copy(); + + // Return true if the list contains an error expression. + bool + contains_error() const; + + // Retrieve an element by index. + Expression*& + at(size_t i) + { return this->entries_.at(i); } + + // Return the first and last elements. + Expression*& + front() + { return this->entries_.front(); } + + Expression* + front() const + { return this->entries_.front(); } + + Expression*& + back() + { return this->entries_.back(); } + + Expression* + back() const + { return this->entries_.back(); } + + // Iterators. + + typedef std::vector<Expression*>::iterator iterator; + typedef std::vector<Expression*>::const_iterator const_iterator; + + iterator + begin() + { return this->entries_.begin(); } + + const_iterator + begin() const + { return this->entries_.begin(); } + + iterator + end() + { return this->entries_.end(); } + + const_iterator + end() const + { return this->entries_.end(); } + + // Erase an entry. + void + erase(iterator p) + { this->entries_.erase(p); } + + private: + std::vector<Expression*> entries_; +}; + +// An abstract base class for an expression which is only used by the +// parser, and is lowered in the lowering pass. + +class Parser_expression : public Expression +{ + public: + Parser_expression(Expression_classification classification, + Location location) + : Expression(classification, location) + { } + + protected: + virtual Expression* + do_lower(Gogo*, Named_object*, Statement_inserter*, int) = 0; + + Type* + do_type(); + + void + do_determine_type(const Type_context*) + { go_unreachable(); } + + void + do_check_types(Gogo*) + { go_unreachable(); } + + tree + do_get_tree(Translate_context*) + { go_unreachable(); } +}; + +// An expression which is simply a variable. + +class Var_expression : public Expression +{ + public: + Var_expression(Named_object* variable, Location location) + : Expression(EXPRESSION_VAR_REFERENCE, location), + variable_(variable) + { } + + // Return the variable. + Named_object* + named_object() const + { return this->variable_; } + + protected: + Expression* + do_lower(Gogo*, Named_object*, Statement_inserter*, int); + + Type* + do_type(); + + void + do_determine_type(const Type_context*); + + Expression* + do_copy() + { return this; } + + bool + do_is_addressable() const + { return true; } + + void + do_address_taken(bool); + + tree + do_get_tree(Translate_context*); + + void + do_dump_expression(Ast_dump_context*) const; + + private: + // The variable we are referencing. + Named_object* variable_; +}; + +// A reference to a temporary variable. + +class Temporary_reference_expression : public Expression +{ + public: + Temporary_reference_expression(Temporary_statement* statement, + Location location) + : Expression(EXPRESSION_TEMPORARY_REFERENCE, location), + statement_(statement), is_lvalue_(false) + { } + + // The temporary that this expression refers to. + Temporary_statement* + statement() const + { return this->statement_; } + + // 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(); + + void + do_determine_type(const Type_context*) + { } + + Expression* + do_copy() + { return make_temporary_reference(this->statement_, this->location()); } + + bool + do_is_addressable() const + { return true; } + + void + do_address_taken(bool); + + 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_; +}; + +// Set and use a temporary variable. + +class Set_and_use_temporary_expression : public Expression +{ + public: + Set_and_use_temporary_expression(Temporary_statement* statement, + Expression* expr, Location location) + : Expression(EXPRESSION_SET_AND_USE_TEMPORARY, location), + statement_(statement), expr_(expr) + { } + + // Return the temporary. + Temporary_statement* + temporary() const + { return this->statement_; } + + // Return the expression. + Expression* + expression() const + { return this->expr_; } + + protected: + int + do_traverse(Traverse* traverse) + { return Expression::traverse(&this->expr_, traverse); } + + Type* + do_type(); + + void + do_determine_type(const Type_context*); + + Expression* + do_copy() + { + return make_set_and_use_temporary(this->statement_, this->expr_, + this->location()); + } + + bool + do_is_addressable() const + { return true; } + + void + do_address_taken(bool); + + 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_; + // The expression to assign to the temporary. + Expression* expr_; +}; + +// A string expression. + +class String_expression : public Expression +{ + public: + String_expression(const std::string& val, Location location) + : Expression(EXPRESSION_STRING, location), + val_(val), type_(NULL) + { } + + const std::string& + val() const + { return this->val_; } + + static Expression* + do_import(Import*); + + protected: + bool + do_is_constant() const + { return true; } + + bool + do_is_immutable() const + { return true; } + + bool + do_string_constant_value(std::string* val) const + { + *val = this->val_; + return true; + } + + Type* + do_type(); + + void + do_determine_type(const Type_context*); + + Expression* + do_copy() + { return this; } + + 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_; + // The type as determined by context. + Type* type_; +}; + +// A binary expression. + +class Binary_expression : public Expression +{ + public: + Binary_expression(Operator op, Expression* left, Expression* right, + Location location) + : Expression(EXPRESSION_BINARY, location), + op_(op), left_(left), right_(right), type_(NULL) + { } + + // Return the operator. + Operator + op() + { return this->op_; } + + // Return the left hand expression. + Expression* + left() + { return this->left_; } + + // Return the right hand expression. + Expression* + right() + { return this->right_; } + + // Apply binary opcode OP to LEFT_NC and RIGHT_NC, setting NC. + // Return true if this could be done, false if not. Issue errors at + // LOCATION as appropriate. + static bool + eval_constant(Operator op, Numeric_constant* left_nc, + Numeric_constant* right_nc, Location location, + Numeric_constant* nc); + + // Compare constants LEFT_NC and RIGHT_NC according to OP, setting + // *RESULT. Return true if this could be done, false if not. Issue + // errors at LOCATION as appropriate. + static bool + compare_constant(Operator op, Numeric_constant* left_nc, + Numeric_constant* right_nc, Location location, + bool* result); + + static Expression* + do_import(Import*); + + // Report an error if OP can not be applied to TYPE. Return whether + // it can. OTYPE is the type of the other operand. + static bool + check_operator_type(Operator op, Type* type, Type* otype, Location); + + protected: + int + do_traverse(Traverse* traverse); + + Expression* + do_lower(Gogo*, Named_object*, Statement_inserter*, int); + + Expression* + do_flatten(Gogo*, Named_object*, Statement_inserter*); + + bool + do_is_constant() const + { return this->left_->is_constant() && this->right_->is_constant(); } + + bool + do_numeric_constant_value(Numeric_constant*) const; + + bool + do_discarding_value(); + + Type* + do_type(); + + void + do_determine_type(const Type_context*); + + void + do_check_types(Gogo*); + + Expression* + do_copy() + { + return Expression::make_binary(this->op_, this->left_->copy(), + this->right_->copy(), this->location()); + } + + tree + do_get_tree(Translate_context*); + + void + do_export(Export*) const; + + void + do_dump_expression(Ast_dump_context*) const; + + private: + static bool + operation_type(Operator op, Type* left_type, Type* right_type, + Type** result_type); + + static bool + cmp_to_bool(Operator op, int cmp); + + static bool + eval_integer(Operator op, const Numeric_constant*, const Numeric_constant*, + Location, Numeric_constant*); + + static bool + eval_float(Operator op, const Numeric_constant*, const Numeric_constant*, + Location, Numeric_constant*); + + static bool + eval_complex(Operator op, const Numeric_constant*, const Numeric_constant*, + Location, Numeric_constant*); + + static bool + compare_integer(const Numeric_constant*, const Numeric_constant*, int*); + + static bool + compare_float(const Numeric_constant*, const Numeric_constant *, int*); + + static bool + compare_complex(const Numeric_constant*, const Numeric_constant*, int*); + + Expression* + lower_struct_comparison(Gogo*, Statement_inserter*); + + Expression* + lower_array_comparison(Gogo*, Statement_inserter*); + + Expression* + lower_interface_value_comparison(Gogo*, Statement_inserter*); + + Expression* + lower_compare_to_memcmp(Gogo*, Statement_inserter*); + + Expression* + operand_address(Statement_inserter*, Expression*); + + // The binary operator to apply. + Operator op_; + // The left hand side operand. + Expression* left_; + // The right hand side operand. + Expression* right_; + // The type of a comparison operation. + Type* type_; +}; + +// A call expression. The go statement needs to dig inside this. + +class Call_expression : public Expression +{ + public: + Call_expression(Expression* fn, Expression_list* args, bool is_varargs, + Location location) + : Expression(EXPRESSION_CALL, location), + 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. + Expression* + fn() const + { return this->fn_; } + + // The arguments. + Expression_list* + args() + { return this->args_; } + + const Expression_list* + args() const + { return this->args_; } + + // Get the function type. + Function_type* + get_function_type() const; + + // Return the number of values this call will return. + 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_recover_call() const; + + // Set the argument for a call to recover. + void + set_recover_arg(Expression*); + + // Whether the last argument is a varargs argument (f(a...)). + 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 + { return this->is_deferred_; } + + // Note that the call is being deferred. + void + 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*, Statement_inserter*, int); + + bool + do_discarding_value() + { return true; } + + virtual Type* + do_type(); + + virtual void + do_determine_type(const Type_context*); + + virtual void + do_check_types(Gogo*); + + Expression* + do_copy() + { + return Expression::make_call(this->fn_->copy(), + (this->args_ == NULL + ? NULL + : this->args_->copy()), + this->is_varargs_, this->location()); + } + + bool + do_must_eval_in_order() const; + + virtual tree + do_get_tree(Translate_context*); + + virtual bool + do_is_recover_call() const; + + virtual void + do_set_recover_arg(Expression*); + + // Let a builtin expression change the argument list. + void + set_args(Expression_list* args) + { this->args_ = args; } + + // Let a builtin expression lower varargs. + void + lower_varargs(Gogo*, Named_object* function, Statement_inserter* inserter, + Type* varargs_type, size_t param_count); + + // Let a builtin expression check whether types have been + // determined. + bool + determining_types(); + + void + do_dump_expression(Ast_dump_context*) const; + + private: + bool + check_argument_type(int, const Type*, const Type*, Location, bool); + + Expression* + interface_method_function(Interface_field_reference_expression*, + Expression**); + + tree + set_results(Translate_context*, tree); + + // The function to call. + Expression* fn_; + // The arguments to pass. This may be NULL if there are no + // arguments. + 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 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. + +class Func_expression : public Expression +{ + public: + Func_expression(Named_object* function, Expression* closure, + Location location) + : Expression(EXPRESSION_FUNC_REFERENCE, location), + function_(function), closure_(closure) + { } + + // Return the object associated with the function. + Named_object* + named_object() const + { return this->function_; } + + // Return the closure for this function. This will return NULL if + // the function has no closure, which is the normal case. + Expression* + closure() + { return this->closure_; } + + // Return a backend expression for the code of a function. + static Bexpression* + get_code_pointer(Gogo*, Named_object* function, Location loc); + + protected: + int + do_traverse(Traverse*); + + Type* + do_type(); + + void + do_determine_type(const Type_context*) + { + if (this->closure_ != NULL) + this->closure_->determine_type_no_context(); + } + + Expression* + do_copy() + { + return Expression::make_func_reference(this->function_, + (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_; + // A closure. This is normally NULL. For a nested function, it may + // be a struct holding pointers to all the variables referenced by + // this function and defined in enclosing functions. + Expression* closure_; +}; + +// A function descriptor. A function descriptor is a struct with a +// single field pointing to the function code. This is used for +// functions without closures. + +class Func_descriptor_expression : public Expression +{ + public: + Func_descriptor_expression(Named_object* fn); + + // Make the function descriptor type, so that it can be converted. + static void + make_func_descriptor_type(); + + protected: + int + do_traverse(Traverse*); + + Type* + do_type(); + + void + do_determine_type(const Type_context*) + { } + + Expression* + do_copy() + { return Expression::make_func_descriptor(this->fn_); } + + bool + do_is_addressable() const + { return true; } + + tree + do_get_tree(Translate_context*); + + void + do_dump_expression(Ast_dump_context* context) const; + + private: + // The type of all function descriptors. + static Type* descriptor_type; + + // The function for which this is the descriptor. + Named_object* fn_; + // The descriptor variable. + Bvariable* dvar_; +}; + +// A reference to an unknown name. + +class Unknown_expression : public Parser_expression +{ + public: + Unknown_expression(Named_object* named_object, Location location) + : Parser_expression(EXPRESSION_UNKNOWN_REFERENCE, location), + named_object_(named_object), no_error_message_(false), + is_composite_literal_key_(false) + { } + + // The associated named object. + Named_object* + named_object() const + { return this->named_object_; } + + // The name of the identifier which was unknown. + const std::string& + name() const; + + // Call this to indicate that we should not give an error if this + // name is never defined. This is used to avoid knock-on errors + // during an erroneous parse. + void + set_no_error_message() + { this->no_error_message_ = true; } + + // Note that this expression is being used as the key in a composite + // literal, so it may be OK if it is not resolved. + void + set_is_composite_literal_key() + { this->is_composite_literal_key_ = true; } + + // Note that this expression should no longer be treated as a + // composite literal key. + void + clear_is_composite_literal_key() + { this->is_composite_literal_key_ = false; } + + protected: + Expression* + 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_; + // True if we should not give errors if this is undefined. This is + // used if there was a parse failure. + bool no_error_message_; + // True if this is the key in a composite literal. + bool is_composite_literal_key_; +}; + +// An index expression. This is lowered to an array index, a string +// index, or a map index. + +class Index_expression : public Parser_expression +{ + public: + Index_expression(Expression* left, Expression* start, Expression* end, + Expression* cap, Location location) + : Parser_expression(EXPRESSION_INDEX, location), + left_(left), start_(start), end_(end), cap_(cap), is_lvalue_(false) + { } + + // Record that this expression is an lvalue. + void + set_is_lvalue() + { this->is_lvalue_ = true; } + + // Dump an index expression, i.e. an expression of the form + // expr[expr], expr[expr:expr], or expr[expr:expr:expr] to a dump context. + static void + dump_index_expression(Ast_dump_context*, const Expression* expr, + const Expression* start, const Expression* end, + const Expression* cap); + + protected: + int + do_traverse(Traverse*); + + Expression* + do_lower(Gogo*, Named_object*, Statement_inserter*, int); + + Expression* + do_copy() + { + return new Index_expression(this->left_->copy(), this->start_->copy(), + (this->end_ == NULL + ? NULL + : this->end_->copy()), + (this->cap_ == NULL + ? NULL + : this->cap_->copy()), + this->location()); + } + + bool + do_must_eval_subexpressions_in_order(int* skip) const + { + *skip = 1; + return true; + } + + 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_; + // The first index. + Expression* start_; + // The second index. This is NULL for an index, non-NULL for a + // slice. + Expression* end_; + // The capacity argument. This is NULL for indices and slices that use the + // default capacity, non-NULL for indices and slices that specify the + // capacity. + Expression* cap_; + // Whether this is being used as an l-value. We set this during the + // parse because map index expressions need to know. + bool is_lvalue_; +}; + +// An index into a map. + +class Map_index_expression : public Expression +{ + public: + Map_index_expression(Expression* map, Expression* index, + Location location) + : Expression(EXPRESSION_MAP_INDEX, location), + map_(map), index_(index), is_lvalue_(false), + is_in_tuple_assignment_(false) + { } + + // Return the map. + Expression* + map() + { return this->map_; } + + const Expression* + map() const + { return this->map_; } + + // Return the index. + Expression* + index() + { return this->index_; } + + const Expression* + index() const + { return this->index_; } + + // Get the type of the map being indexed. + Map_type* + get_map_type() const; + + // Record that this map expression is an lvalue. The difference is + // that an lvalue always inserts the key. + void + set_is_lvalue() + { this->is_lvalue_ = true; } + + // Return whether this map expression occurs in an assignment to a + // pair of values. + bool + is_in_tuple_assignment() const + { return this->is_in_tuple_assignment_; } + + // Record that this map expression occurs in an assignment to a pair + // of values. + void + set_is_in_tuple_assignment() + { this->is_in_tuple_assignment_ = true; } + + // Return a tree for the map index. This returns a tree which + // evaluates to a pointer to a value in the map. If INSERT is true, + // the key will be inserted if not present, and the value pointer + // will be zero initialized. If INSERT is false, and the key is not + // present in the map, the pointer will be NULL. + tree + get_value_pointer(Translate_context*, bool insert); + + protected: + int + do_traverse(Traverse*); + + Type* + do_type(); + + void + do_determine_type(const Type_context*); + + void + do_check_types(Gogo*); + + Expression* + do_copy() + { + return Expression::make_map_index(this->map_->copy(), + this->index_->copy(), + this->location()); + } + + bool + do_must_eval_subexpressions_in_order(int* skip) const + { + *skip = 1; + return true; + } + + // A map index expression is an lvalue but it is not addressable. + + tree + do_get_tree(Translate_context*); + + void + do_dump_expression(Ast_dump_context*) const; + + private: + // The map we are looking into. + Expression* map_; + // The index. + Expression* index_; + // Whether this is an lvalue. + bool is_lvalue_; + // Whether this is in a tuple assignment to a pair of values. + bool is_in_tuple_assignment_; +}; + +// An expression which represents a method bound to its first +// argument. + +class Bound_method_expression : public Expression +{ + public: + Bound_method_expression(Expression* expr, const Method *method, + Named_object* function, Location location) + : Expression(EXPRESSION_BOUND_METHOD, location), + expr_(expr), expr_type_(NULL), method_(method), function_(function) + { } + + // Return the object which is the first argument. + Expression* + first_argument() + { return this->expr_; } + + // Return the implicit type of the first argument. This will be + // non-NULL when using a method from an anonymous field without + // using an explicit stub. + Type* + first_argument_type() const + { return this->expr_type_; } + + // Return the method. + const Method* + method() const + { return this->method_; } + + // Return the function to call. + Named_object* + function() const + { return this->function_; } + + // Set the implicit type of the expression. + void + set_first_argument_type(Type* type) + { this->expr_type_ = type; } + + // Create a thunk to call FUNCTION, for METHOD, when it is used as + // part of a method value. + static Named_object* + create_thunk(Gogo*, const Method* method, Named_object* function); + + protected: + int + do_traverse(Traverse*); + + Expression* + do_lower(Gogo*, Named_object*, Statement_inserter*, int); + + Type* + do_type(); + + void + do_determine_type(const Type_context*); + + void + do_check_types(Gogo*); + + Expression* + do_copy() + { + return new Bound_method_expression(this->expr_->copy(), this->method_, + this->function_, this->location()); + } + + tree + do_get_tree(Translate_context*); + + void + do_dump_expression(Ast_dump_context*) const; + + private: + // A mapping from method functions to the thunks we have created for + // them. + typedef Unordered_map(Named_object*, Named_object*) Method_value_thunks; + static Method_value_thunks method_value_thunks; + + // The object used to find the method. This is passed to the method + // as the first argument. + Expression* expr_; + // The implicit type of the object to pass to the method. This is + // 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. + const Method* method_; + // The function to call. This is not the same as + // method_->named_object() when the method has a stub. This will be + // the real function rather than the stub. + Named_object* function_; +}; + +// A reference to a field in a struct. + +class Field_reference_expression : public Expression +{ + public: + Field_reference_expression(Expression* expr, unsigned int field_index, + Location location) + : Expression(EXPRESSION_FIELD_REFERENCE, location), + expr_(expr), field_index_(field_index), implicit_(false), called_fieldtrack_(false) + { } + + // Return the struct expression. + Expression* + expr() const + { return this->expr_; } + + // Return the field index. + unsigned int + field_index() const + { return this->field_index_; } + + // Return whether this node was implied by an anonymous field. + bool + implicit() const + { return this->implicit_; } + + void + set_implicit(bool implicit) + { this->implicit_ = implicit; } + + // Set the struct expression. This is used when parsing. + void + set_struct_expression(Expression* expr) + { + go_assert(this->expr_ == NULL); + this->expr_ = expr; + } + + protected: + int + do_traverse(Traverse* traverse) + { return Expression::traverse(&this->expr_, traverse); } + + Expression* + do_lower(Gogo*, Named_object*, Statement_inserter*, int); + + Type* + do_type(); + + void + do_determine_type(const Type_context*) + { this->expr_->determine_type_no_context(); } + + void + do_check_types(Gogo*); + + Expression* + do_copy() + { + return Expression::make_field_reference(this->expr_->copy(), + this->field_index_, + this->location()); + } + + bool + do_is_addressable() const + { return this->expr_->is_addressable(); } + + void + 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*); + + void + do_dump_expression(Ast_dump_context*) const; + + private: + // The expression we are looking into. This should have a type of + // struct. + Expression* expr_; + // The zero-based index of the field we are retrieving. + unsigned int field_index_; + // Whether this node was emitted implicitly for an embedded field, + // that is, expr_ is not the expr_ of the original user node. + bool implicit_; + // Whether we have already emitted a fieldtrack call. + bool called_fieldtrack_; +}; + +// A reference to a field of an interface. + +class Interface_field_reference_expression : public Expression +{ + public: + Interface_field_reference_expression(Expression* expr, + const std::string& name, + Location location) + : Expression(EXPRESSION_INTERFACE_FIELD_REFERENCE, location), + expr_(expr), name_(name) + { } + + // Return the expression for the interface object. + Expression* + expr() + { return this->expr_; } + + // Return the name of the method to call. + const std::string& + name() const + { return this->name_; } + + // Create a thunk to call the method NAME in TYPE when it is used as + // part of a method value. + static Named_object* + create_thunk(Gogo*, Interface_type* type, const std::string& name); + + // Return an expression for the pointer to the function to call. + Expression* + get_function(); + + // Return an expression for the first argument to pass to the interface + // function. This is the real object associated with the interface object. + Expression* + get_underlying_object(); + + protected: + int + do_traverse(Traverse* traverse); + + Expression* + do_lower(Gogo*, Named_object*, Statement_inserter*, int); + + Type* + do_type(); + + void + do_determine_type(const Type_context*); + + void + do_check_types(Gogo*); + + Expression* + do_copy() + { + return Expression::make_interface_field_reference(this->expr_->copy(), + this->name_, + this->location()); + } + + tree + do_get_tree(Translate_context*); + + void + do_dump_expression(Ast_dump_context*) const; + + private: + // A mapping from interface types to a list of thunks we have + // created for methods. + typedef std::vector<std::pair<std::string, Named_object*> > Method_thunks; + typedef Unordered_map(Interface_type*, Method_thunks*) + Interface_method_thunks; + static Interface_method_thunks interface_method_thunks; + + // The expression for the interface object. This should have a type + // of interface or pointer to interface. + Expression* expr_; + // The field we are retrieving--the name of the method. + std::string name_; +}; + +// A type guard expression. + +class Type_guard_expression : public Expression +{ + public: + Type_guard_expression(Expression* expr, Type* type, Location location) + : Expression(EXPRESSION_TYPE_GUARD, location), + expr_(expr), type_(type) + { } + + // Return the expression to convert. + Expression* + expr() + { return this->expr_; } + + // Return the type to which to convert. + Type* + type() + { return this->type_; } + + protected: + int + do_traverse(Traverse* traverse); + + Type* + do_type() + { return this->type_; } + + void + do_determine_type(const Type_context*) + { this->expr_->determine_type_no_context(); } + + void + do_check_types(Gogo*); + + Expression* + do_copy() + { + return new Type_guard_expression(this->expr_->copy(), this->type_, + this->location()); + } + + tree + do_get_tree(Translate_context*); + + void + do_dump_expression(Ast_dump_context*) const; + + private: + // The expression to convert. + Expression* expr_; + // The type to which to convert. + Type* type_; +}; + +// A receive expression. + +class Receive_expression : public Expression +{ + public: + Receive_expression(Expression* channel, Location location) + : Expression(EXPRESSION_RECEIVE, location), + channel_(channel) + { } + + // Return the channel. + Expression* + channel() + { return this->channel_; } + + protected: + int + do_traverse(Traverse* traverse) + { return Expression::traverse(&this->channel_, traverse); } + + bool + do_discarding_value() + { return true; } + + Type* + do_type(); + + void + do_determine_type(const Type_context*) + { this->channel_->determine_type_no_context(); } + + void + do_check_types(Gogo*); + + Expression* + do_copy() + { + return Expression::make_receive(this->channel_->copy(), this->location()); + } + + bool + do_must_eval_in_order() const + { return true; } + + tree + do_get_tree(Translate_context*); + + void + do_dump_expression(Ast_dump_context*) const; + + private: + // The channel from which we are receiving. + Expression* channel_; +}; + +// A numeric constant. This is used both for untyped constants and +// for constants that have a type. + +class Numeric_constant +{ + public: + Numeric_constant() + : classification_(NC_INVALID), type_(NULL) + { } + + ~Numeric_constant(); + + Numeric_constant(const Numeric_constant&); + + Numeric_constant& operator=(const Numeric_constant&); + + // Set to an unsigned long value. + void + set_unsigned_long(Type*, unsigned long); + + // Set to an integer value. + void + set_int(Type*, const mpz_t); + + // Set to a rune value. + void + set_rune(Type*, const mpz_t); + + // Set to a floating point value. + void + set_float(Type*, const mpfr_t); + + // Set to a complex value. + void + set_complex(Type*, const mpfr_t, const mpfr_t); + + // Classifiers. + bool + is_int() const + { return this->classification_ == Numeric_constant::NC_INT; } + + bool + is_rune() const + { return this->classification_ == Numeric_constant::NC_RUNE; } + + bool + is_float() const + { return this->classification_ == Numeric_constant::NC_FLOAT; } + + bool + is_complex() const + { return this->classification_ == Numeric_constant::NC_COMPLEX; } + + // Value retrievers. These will initialize the values as well as + // set them. GET_INT is only valid if IS_INT returns true, and + // likewise respectively. + void + get_int(mpz_t*) const; + + void + get_rune(mpz_t*) const; + + void + get_float(mpfr_t*) const; + + void + get_complex(mpfr_t*, mpfr_t*) const; + + // Codes returned by to_unsigned_long. + enum To_unsigned_long + { + // Value is integer and fits in unsigned long. + NC_UL_VALID, + // Value is not integer. + NC_UL_NOTINT, + // Value is integer but is negative. + NC_UL_NEGATIVE, + // Value is non-negative integer but does not fit in unsigned + // long. + NC_UL_BIG + }; + + // If the value can be expressed as an integer that fits in an + // unsigned long, set *VAL and return NC_UL_VALID. Otherwise return + // one of the other To_unsigned_long codes. + To_unsigned_long + to_unsigned_long(unsigned long* val) const; + + // If the value can be expressed as an int, return true and + // initialize and set VAL. This will return false for a value with + // an explicit float or complex type, even if the value is integral. + bool + to_int(mpz_t* val) const; + + // If the value can be expressed as a float, return true and + // initialize and set VAL. + bool + to_float(mpfr_t* val) const; + + // If the value can be expressed as a complex, return true and + // initialize and set VR and VI. + bool + to_complex(mpfr_t* vr, mpfr_t* vi) const; + + // Get the type. + Type* + type() const; + + // If the constant can be expressed in TYPE, then set the type of + // the constant to TYPE and return true. Otherwise return false, + // and, if ISSUE_ERROR is true, issue an error message. LOCATION is + // the location to use for the error. + bool + set_type(Type* type, bool issue_error, Location location); + + // Return an Expression for this value. + Expression* + expression(Location) const; + + private: + void + clear(); + + To_unsigned_long + mpz_to_unsigned_long(const mpz_t ival, unsigned long *val) const; + + To_unsigned_long + mpfr_to_unsigned_long(const mpfr_t fval, unsigned long *val) const; + + bool + check_int_type(Integer_type*, bool, Location) const; + + bool + check_float_type(Float_type*, bool, Location); + + bool + check_complex_type(Complex_type*, bool, Location); + + // The kinds of constants. + enum Classification + { + NC_INVALID, + NC_RUNE, + NC_INT, + NC_FLOAT, + NC_COMPLEX + }; + + // The kind of constant. + Classification classification_; + // The value. + union + { + // If NC_INT or NC_RUNE. + mpz_t int_val; + // If NC_FLOAT. + mpfr_t float_val; + // If NC_COMPLEX. + struct + { + mpfr_t real; + mpfr_t imag; + } complex_val; + } u_; + // The type if there is one. This will be NULL for an untyped + // constant. + Type* type_; +}; + +#endif // !defined(GO_EXPRESSIONS_H) |