static const int RUNTIME_TYPE_KIND_UINT32 = 10;
static const int RUNTIME_TYPE_KIND_UINT64 = 11;
static const int RUNTIME_TYPE_KIND_UINTPTR = 12;
-static const int RUNTIME_TYPE_KIND_FLOAT = 13;
-static const int RUNTIME_TYPE_KIND_FLOAT32 = 14;
-static const int RUNTIME_TYPE_KIND_FLOAT64 = 15;
-static const int RUNTIME_TYPE_KIND_COMPLEX = 16;
-static const int RUNTIME_TYPE_KIND_COMPLEX64 = 17;
-static const int RUNTIME_TYPE_KIND_COMPLEX128 = 18;
-static const int RUNTIME_TYPE_KIND_ARRAY = 19;
-static const int RUNTIME_TYPE_KIND_CHAN = 20;
-static const int RUNTIME_TYPE_KIND_FUNC = 21;
-static const int RUNTIME_TYPE_KIND_INTERFACE = 22;
-static const int RUNTIME_TYPE_KIND_MAP = 23;
-static const int RUNTIME_TYPE_KIND_PTR = 24;
-static const int RUNTIME_TYPE_KIND_SLICE = 25;
-static const int RUNTIME_TYPE_KIND_STRING = 26;
-static const int RUNTIME_TYPE_KIND_STRUCT = 27;
-static const int RUNTIME_TYPE_KIND_UNSAFE_POINTER = 28;
+static const int RUNTIME_TYPE_KIND_FLOAT32 = 13;
+static const int RUNTIME_TYPE_KIND_FLOAT64 = 14;
+static const int RUNTIME_TYPE_KIND_COMPLEX64 = 15;
+static const int RUNTIME_TYPE_KIND_COMPLEX128 = 16;
+static const int RUNTIME_TYPE_KIND_ARRAY = 17;
+static const int RUNTIME_TYPE_KIND_CHAN = 18;
+static const int RUNTIME_TYPE_KIND_FUNC = 19;
+static const int RUNTIME_TYPE_KIND_INTERFACE = 20;
+static const int RUNTIME_TYPE_KIND_MAP = 21;
+static const int RUNTIME_TYPE_KIND_PTR = 22;
+static const int RUNTIME_TYPE_KIND_SLICE = 23;
+static const int RUNTIME_TYPE_KIND_STRING = 24;
+static const int RUNTIME_TYPE_KIND_STRUCT = 25;
+static const int RUNTIME_TYPE_KIND_UNSAFE_POINTER = 26;
// To build the complete list of methods for a named type we need to
// gather all methods from anonymous fields. Those methods may
verify()
{ return this->do_verify(); }
- // Return true if two types are identical. If this returns false,
+ // Return true if two types are identical. If ERRORS_ARE_IDENTICAL,
+ // returns that an erroneous type is identical to any other type;
+ // this is used to avoid cascading errors. If this returns false,
// and REASON is not NULL, it may set *REASON.
static bool
- are_identical(const Type* lhs, const Type* rhs, std::string* reason);
+ are_identical(const Type* lhs, const Type* rhs, bool errors_are_identical,
+ std::string* reason);
// Return true if two types are compatible for use in a binary
// operation, other than a shift, comparison, or channel send. This
// Return true if NAME is an unexported field or method of TYPE.
static bool
- is_unexported_field_or_method(Gogo*, const Type*, const std::string&);
+ is_unexported_field_or_method(Gogo*, const Type*, const std::string&,
+ std::vector<const Named_type*>*);
// This type was passed to the builtin function make. ARGS are the
// arguments passed to make after the type; this may be NULL if
check_make_expression(Expression_list* args, source_location location)
{ return this->do_check_make_expression(args, location); }
+ // Convert the builtin named types.
+ static void
+ convert_builtin_named_types(Gogo*);
+
// Return a tree representing this type.
tree
get_tree(Gogo*);
static bool
find_field_or_method(const Type* type, const std::string& name,
bool receiver_can_be_pointer,
- int* level, bool* is_method,
- bool* found_pointer_method,
+ std::vector<const Named_type*>*, int* level,
+ bool* is_method, bool* found_pointer_method,
std::string* ambig1, std::string* ambig2);
// Get a tree for a type without looking in the hash table for
static Type_trees type_trees;
+ // A list of builtin named types.
+ static std::vector<Named_type*> named_builtin_types;
+
// The type classification.
Type_classification classification_;
// The tree representation of the type, once it has been determined.
public:
bool
operator()(const Type* t1, const Type* t2) const
- { return Type::are_identical(t1, t2, NULL); }
+ { return Type::are_identical(t1, t2, false, NULL); }
};
// An identifier with a type.
// Whether this type is the same as T.
bool
is_identical(const Function_type* t, bool ignore_receiver,
- std::string*) const;
+ bool errors_are_identical, std::string*) const;
// Record that this is a varargs function.
void
Function_type*
copy_with_receiver(Type*) const;
+ static Type*
+ make_function_type_descriptor_type();
+
protected:
int
do_traverse(Traverse*);
do_export(Export*) const;
private:
- static Type*
- make_function_type_descriptor_type();
-
Expression*
type_descriptor_params(Type*, const Typed_identifier*,
const Typed_identifier_list*);
static Pointer_type*
do_import(Import*);
+ static Type*
+ make_pointer_type_descriptor_type();
+
protected:
int
do_traverse(Traverse*);
do_export(Export*) const;
private:
- static Type*
- make_pointer_type_descriptor_type();
-
// The type to which this type points.
Type* to_type_;
};
// Whether this type is identical with T.
bool
- is_identical(const Struct_type* t) const;
+ 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
tree
fill_in_tree(Gogo*, tree);
+ static Type*
+ make_struct_type_descriptor_type();
+
protected:
int
do_traverse(Traverse*);
do_export(Export*) const;
private:
+ // Used to avoid infinite loops in field_reference_depth.
+ struct Saw_named_type
+ {
+ Saw_named_type* next;
+ Named_type* nt;
+ };
+
Field_reference_expression*
field_reference_depth(Expression* struct_expr, const std::string& name,
- source_location, unsigned int* depth) const;
-
- static Type*
- make_struct_type_descriptor_type();
+ source_location, Saw_named_type*,
+ unsigned int* depth) const;
// The fields of the struct.
Struct_field_list* fields_;
// Whether this type is identical with T.
bool
- is_identical(const Array_type* t) const;
+ is_identical(const Array_type* t, bool errors_are_identical) const;
// Whether this type has any hidden fields.
bool
static Array_type*
do_import(Import*);
+ // Fill in the fields for a named array type.
+ tree
+ fill_in_array_tree(Gogo*, tree);
+
// Fill in the fields for a named slice type.
tree
- fill_in_tree(Gogo*, tree);
+ fill_in_slice_tree(Gogo*, tree);
+
+ static Type*
+ make_array_type_descriptor_type();
+
+ static Type*
+ make_slice_type_descriptor_type();
protected:
int
tree
get_length_tree(Gogo*);
- Type*
- make_array_type_descriptor_type();
-
- Type*
- make_slice_type_descriptor_type();
-
Expression*
array_type_descriptor(Gogo*, Named_type*);
// Whether this type is identical with T.
bool
- is_identical(const Map_type* t) const;
+ is_identical(const Map_type* t, bool errors_are_identical) const;
// Import a map type.
static Map_type*
do_import(Import*);
+ static Type*
+ make_map_type_descriptor_type();
+
protected:
int
do_traverse(Traverse*);
do_export(Export*) const;
private:
- static Type*
- make_map_type_descriptor_type();
-
// The key type.
Type* key_type_;
// The value type.
// Whether this type is identical with T.
bool
- is_identical(const Channel_type* t) const;
+ is_identical(const Channel_type* t, bool errors_are_identical) const;
// Import a channel type.
static Channel_type*
do_import(Import*);
+ static Type*
+ make_chan_type_descriptor_type();
+
protected:
int
do_traverse(Traverse* traverse)
do_export(Export*) const;
private:
- static Type*
- make_chan_type_descriptor_type();
-
// Whether this channel can send data.
bool may_send_;
// Whether this channel can receive data.
methods_(methods), location_(location)
{ gcc_assert(methods == NULL || !methods->empty()); }
+ // The location where the interface type was defined.
+ source_location
+ location() const
+ { return this->location_; }
+
// Return whether this is an empty interface.
bool
is_empty() const
// Whether this type is identical with T. REASON is as in
// implements_interface.
bool
- is_identical(const Interface_type* t) const;
+ is_identical(const Interface_type* t, bool errors_are_identical) const;
// Whether we can assign T to this type. is_identical is known to
// be false.
static Interface_type*
do_import(Import*);
+ // Make a struct for an empty interface type.
+ static tree
+ empty_type_tree(Gogo*);
+
+ // Make a struct for non-empty interface type.
+ static tree
+ non_empty_type_tree(source_location);
+
// Fill in the fields for a named interface type.
tree
fill_in_tree(Gogo*, tree);
+ static Type*
+ make_interface_type_descriptor_type();
+
protected:
int
do_traverse(Traverse*);
do_export(Export*) const;
private:
- static Type*
- make_interface_type_descriptor_type();
-
// The list of methods associated with the interface. This will be
// NULL for the empty interface.
Typed_identifier_list* methods_;
named_object_(named_object), in_function_(NULL), type_(type),
local_methods_(NULL), all_methods_(NULL),
interface_method_tables_(NULL), pointer_interface_method_tables_(NULL),
- location_(location), named_tree_(NULL), is_visible_(true),
- is_error_(false), seen_(false)
+ location_(location), named_tree_(NULL), dependencies_(),
+ is_visible_(true), is_error_(false), is_converted_(false),
+ is_circular_(false), seen_(0)
{ }
// Return the associated Named_object. This holds the actual name.
is_builtin() const
{ return this->location_ == BUILTINS_LOCATION; }
+ // Whether this is a circular type: a pointer or function type that
+ // refers to itself, which is not possible in C.
+ bool
+ is_circular() const
+ { return this->is_circular_; }
+
+ // Return the base type for this type.
+ Type*
+ named_base();
+
+ const Type*
+ named_base() const;
+
+ // Return whether this is an error type.
+ bool
+ is_named_error_type() const;
+
// Add a method to this type.
Named_object*
add_method(const std::string& name, Function*);
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
+ add_dependency(Named_type* nt)
+ { this->dependencies_.push_back(nt); }
+
// Export the type.
void
export_named_type(Export*, const std::string& name) const;
static void
import_named_type(Import*, Named_type**);
+ // Initial conversion to backend representation.
+ void
+ convert(Gogo*);
+
protected:
int
do_traverse(Traverse* traverse)
do_verify();
bool
- do_has_pointer() const
- { return this->type_->has_pointer(); }
+ do_has_pointer() const;
unsigned int
do_hash_for_method(Gogo*) const;
do_export(Export*) const;
private:
+ // Create the placeholder during conversion.
+ void
+ create_placeholder(Gogo*);
+
// A mapping from interfaces to the associated interface method
// tables for this type. This maps to a decl.
typedef Unordered_map_hash(const Interface_type*, tree, Type_hash_identical,
// The tree for this type while converting to GENERIC. This is used
// to avoid endless recursion when a named type refers to itself.
tree named_tree_;
+ // A list of types which must be converted to the backend
+ // representation before this type can be converted. This is for
+ // cases like
+ // type S1 { p *S2 }
+ // type S2 { s S1 }
+ // where we can't convert S2 to the backend representation unless we
+ // have converted S1.
+ std::vector<Named_type*> dependencies_;
// Whether this type is visible. This is false if this type was
// created because it was referenced by an imported object, but the
// type itself was not exported. This will always be true for types
bool is_visible_;
// Whether this type is erroneous.
bool is_error_;
+ // Whether this type has been converted to the backend
+ // representation.
+ bool is_converted_;
+ // Whether this is a pointer or function type which refers to the
+ // type itself.
+ bool is_circular_;
// 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.
- mutable bool seen_;
+ mutable int seen_;
};
// A forward declaration. This handles a type which has been declared
bool
do_has_pointer() const
- { return this->base()->has_pointer(); }
+ { return this->real_type()->has_pointer(); }
unsigned int
do_hash_for_method(Gogo* gogo) const