aboutsummaryrefslogtreecommitdiff
path: root/gcc/go/gofrontend/expressions.h
diff options
context:
space:
mode:
authorIan Lance Taylor <iant@golang.org>2023-10-19 19:34:31 -0700
committerIan Lance Taylor <iant@golang.org>2023-12-18 17:30:56 -0800
commitc20328e7cad2989bcdc9ff5003d6a16405c31ab5 (patch)
tree837db6d6d15e763947916017b122788e30ea1e59 /gcc/go/gofrontend/expressions.h
parent15cb5204e4c5f79d1b7179ae2590bb65e24b745f (diff)
downloadgcc-c20328e7cad2989bcdc9ff5003d6a16405c31ab5.zip
gcc-c20328e7cad2989bcdc9ff5003d6a16405c31ab5.tar.gz
gcc-c20328e7cad2989bcdc9ff5003d6a16405c31ab5.tar.bz2
compiler: move lowering pass after check types pass
This change moves the lowering pass after the type determination and the type checking passes. This lets us simplify some of the code that determines the type of an expression, which previously had to work correctly both before and after type determination. I'm doing this to help with future generic support. For example, with generics, we can see code like func ident[T any](v T) T { return v } func F() int32 { s := int32(1) return ident(s) } Before this change, we would type check return statements in the lowering pass (see Return_statement::do_lower). With a generic example like the above, that means we have to determine the type of s, and use that to infer the type arguments passed to ident, and use that to determine the result type of ident. That is too much to do at lowering time. Of course we can change the way that return statements work, but similar issues arise with index expressions, the types of closures for function literals, and probably other cases as well. Rather than try to deal with all those cases, we move the lowering pass after type checking. This requires a bunch of changes, notably for determining constant types. We have to add type checking for various constructs that formerly disappeared in the lowering pass. So it's a lot of shuffling. Sorry for the size of the patch. Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/536643
Diffstat (limited to 'gcc/go/gofrontend/expressions.h')
-rw-r--r--gcc/go/gofrontend/expressions.h236
1 files changed, 183 insertions, 53 deletions
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index d5df724..8763772 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -596,7 +596,8 @@ class Expression
{ return this->do_is_static_initializer(); }
// If this is not a numeric constant, return false. If it is one,
- // return true, and set VAL to hold the value.
+ // return true, and set VAL to hold the value. This method can be
+ // called before the determine_types pass.
bool
numeric_constant_value(Numeric_constant* val)
{ return this->do_numeric_constant_value(val); }
@@ -633,8 +634,7 @@ class Expression
// Return whether this expression really represents a type.
bool
- is_type_expression() const
- { return this->classification_ == EXPRESSION_TYPE; }
+ is_type_expression() const;
// If this is a const reference, return the Const_expression
// structure. Otherwise, return NULL. This is a controlled dynamic
@@ -735,6 +735,10 @@ class Expression
unary_expression()
{ return this->convert<Unary_expression, EXPRESSION_UNARY>(); }
+ const Unary_expression*
+ unary_expression() const
+ { return this->convert<const Unary_expression, EXPRESSION_UNARY>(); }
+
// If this is a binary expression, return the Binary_expression
// structure. Otherwise return NULL.
Binary_expression*
@@ -1022,10 +1026,8 @@ class Expression
void
determine_type_no_context(Gogo*);
- // Return the current type of the expression. This may be changed
- // by determine_type. This should not be called before the lowering
- // pass, unless the is_type_expression method returns true (i.e.,
- // this is an EXPRESSION_TYPE).
+ // Return the type of the expression. This should not be called
+ // before the determine_types pass.
Type*
type()
{ return this->do_type(); }
@@ -1472,17 +1474,6 @@ class Parser_expression : public Expression
virtual Expression*
do_lower(Gogo*, Named_object*, Statement_inserter*, int) = 0;
- Type*
- do_type();
-
- void
- do_determine_type(Gogo*, const Type_context*)
- { go_unreachable(); }
-
- void
- do_check_types(Gogo*)
- { go_unreachable(); }
-
Bexpression*
do_get_backend(Translate_context*)
{ go_unreachable(); }
@@ -1495,7 +1486,8 @@ class Const_expression : public Expression
public:
Const_expression(Named_object* constant, Location location)
: Expression(EXPRESSION_CONST_REFERENCE, location),
- constant_(constant), type_(NULL), seen_(false)
+ constant_(constant), type_(NULL), iota_value_(0), seen_(false),
+ is_iota_(false)
{ }
Named_object*
@@ -1510,6 +1502,10 @@ class Const_expression : public Expression
void
check_for_init_loop();
+ // Set the iota value if this is a reference to iota.
+ void
+ set_iota_value(int);
+
protected:
int
do_traverse(Traverse*);
@@ -1576,9 +1572,14 @@ class Const_expression : public Expression
// The type of this reference. This is used if the constant has an
// abstract type.
Type* type_;
+ // If this const is a reference to the predeclared iota value, the
+ // value to use.
+ int iota_value_;
// Used to prevent infinite recursion when a constant incorrectly
// refers to itself.
mutable bool seen_;
+ // Whether this const is a reference to the predeclared iota value.
+ bool is_iota_;
};
// An expression which is simply a variable.
@@ -1976,8 +1977,7 @@ class Type_conversion_expression : public Expression
do_boolean_constant_value(bool*);
Type*
- do_type()
- { return this->type_; }
+ do_type();
void
do_determine_type(Gogo*, const Type_context*);
@@ -2074,7 +2074,7 @@ class Unary_expression : public Expression
Unary_expression(Operator op, Expression* expr, Location location)
: Expression(EXPRESSION_UNARY, location),
op_(op), escapes_(true), create_temp_(false), is_gc_root_(false),
- is_slice_init_(false), expr_(expr),
+ is_slice_init_(false), expr_(expr), type_(NULL),
issue_nil_check_(NIL_CHECK_DEFAULT)
{ }
@@ -2131,7 +2131,7 @@ class Unary_expression : public Expression
// could be done, false if not. On overflow, issues an error and
// sets *ISSUED_ERROR.
static bool
- eval_constant(Operator op, const Numeric_constant* unc,
+ eval_constant(Type*, Operator op, const Numeric_constant* unc,
Location, Numeric_constant* nc, bool *issued_error);
static Expression*
@@ -2246,6 +2246,8 @@ class Unary_expression : public Expression
bool is_slice_init_;
// The operand.
Expression* expr_;
+ // The type of the expression. Not used for AND and MULT.
+ Type* type_;
// Whether or not to issue a nil check for this expression if its address
// is being taken.
Nil_check_classification issue_nil_check_;
@@ -2372,15 +2374,15 @@ class Binary_expression : public Expression
static bool
eval_integer(Operator op, const Numeric_constant*, const Numeric_constant*,
- Location, Numeric_constant*);
+ Location, Numeric_constant*, bool* issued_error);
static bool
eval_float(Operator op, const Numeric_constant*, const Numeric_constant*,
- Location, Numeric_constant*);
+ Location, Numeric_constant*, bool* issued_error);
static bool
eval_complex(Operator op, const Numeric_constant*, const Numeric_constant*,
- Location, Numeric_constant*);
+ Location, Numeric_constant*, bool* issued_error);
static bool
compare_integer(const Numeric_constant*, const Numeric_constant*, int*);
@@ -2412,7 +2414,7 @@ class Binary_expression : public Expression
Expression* left_;
// The right hand side operand.
Expression* right_;
- // The type of a comparison operation.
+ // The type of the expression.
Type* type_;
};
@@ -2493,8 +2495,8 @@ class Call_expression : public Expression
Call_expression(Expression* fn, Expression_list* args, bool is_varargs,
Location location)
: Expression(EXPRESSION_CALL, location),
- fn_(fn), args_(args), type_(NULL), call_(NULL), call_temp_(NULL)
- , expected_result_count_(0), is_varargs_(is_varargs),
+ fn_(fn), args_(args), type_(NULL), lowered_(NULL), call_(NULL),
+ call_temp_(NULL), expected_result_count_(0), is_varargs_(is_varargs),
varargs_are_lowered_(false), types_are_determined_(false),
is_deferred_(false), is_concurrent_(false), is_equal_function_(false),
issued_error_(false), is_multi_value_arg_(false), is_flattened_(false)
@@ -2530,7 +2532,8 @@ class Call_expression : public Expression
// Set the number of results expected from this call. This is used
// when the call appears in a context that expects multiple results,
- // such as a, b = f().
+ // such as a, b = f(). This must be called before the
+ // determine_types pass.
void
set_expected_result_count(size_t);
@@ -2616,6 +2619,10 @@ class Call_expression : public Expression
inline const Builtin_call_expression*
builtin_call_expression() const;
+ // Lower to a Builtin_call_expression if appropriate.
+ Expression*
+ lower_builtin(Gogo*);
+
protected:
int
do_traverse(Traverse*);
@@ -2627,12 +2634,20 @@ class Call_expression : public Expression
do_flatten(Gogo*, Named_object*, Statement_inserter*);
bool
- do_discarding_value()
- { return true; }
+ do_discarding_value();
virtual Type*
do_type();
+ virtual bool
+ do_is_constant() const;
+
+ bool
+ do_is_untyped(Type**) const;
+
+ bool
+ do_numeric_constant_value(Numeric_constant*);
+
virtual void
do_determine_type(Gogo*, const Type_context*);
@@ -2665,17 +2680,26 @@ class Call_expression : public Expression
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,
- Slice_storage_escape_disp escape_disp);
-
// Let a builtin expression check whether types have been
// determined.
bool
determining_types();
+ // Let a builtin expression retrieve the expected type.
+ Type*
+ type()
+ { return this->type_; }
+
+ // Let a builtin expression set the expected type.
+ void
+ set_type(Type* type)
+ { this->type_ = type; }
+
+ // Let a builtin expression simply f(g()) where g returns multiple
+ // results.
+ void
+ simplify_multiple_results(Gogo*);
+
void
export_arguments(Export_function_body*) const;
@@ -2687,7 +2711,10 @@ class Call_expression : public Expression
private:
bool
- check_argument_type(int, const Type*, const Type*, Location, bool);
+ rewrite_varargs();
+
+ bool
+ check_argument_type(int, const Type*, const Type*, Location);
Expression*
intrinsify(Gogo*, Statement_inserter*);
@@ -2706,6 +2733,8 @@ class Call_expression : public Expression
Expression_list* args_;
// The type of the expression, to avoid recomputing it.
Type* type_;
+ // If not NULL, this is a lowered version of this Call_expression.
+ Expression* lowered_;
// The backend expression for the call, used for a call which returns a tuple.
Bexpression* call_;
// A temporary variable to store this call if the function returns a tuple.
@@ -3087,7 +3116,8 @@ 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)
+ named_object_(named_object), lowered_(NULL), iota_value_(0),
+ no_error_message_(false), is_iota_(false)
{ }
// The associated named object.
@@ -3106,7 +3136,38 @@ class Unknown_expression : public Parser_expression
set_no_error_message()
{ this->no_error_message_ = true; }
+ // Set the iota value if this is a reference to iota.
+ void
+ set_iota_value(int);
+
protected:
+ int
+ do_traverse(Traverse*);
+
+ Type*
+ do_type();
+
+ void
+ do_determine_type(Gogo*, const Type_context*);
+
+ bool
+ do_is_constant() const;
+
+ bool
+ do_is_untyped(Type**) const;
+
+ virtual bool
+ do_numeric_constant_value(Numeric_constant*);
+
+ virtual bool
+ do_string_constant_value(std::string*);
+
+ virtual bool
+ do_boolean_constant_value(bool*);
+
+ bool
+ do_is_addressable() const;
+
Expression*
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
@@ -3120,9 +3181,15 @@ class Unknown_expression : public Parser_expression
private:
// The unknown name.
Named_object* named_object_;
+ // The fully resolved expression.
+ Expression* lowered_;
+ // The iota value if this turns out to be a reference to iota.
+ int iota_value_;
// 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 could be a reference to iota.
+ bool is_iota_;
};
// An index expression. This is lowered to an array index, a string
@@ -3134,9 +3201,15 @@ class Index_expression : public Parser_expression
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)
+ left_(left), start_(start), end_(end), cap_(cap),
+ needs_nil_check_(false)
{ }
+ // Return the expression being indexed.
+ Expression*
+ left() const
+ { return this->left_; }
+
// 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
@@ -3144,24 +3217,44 @@ class Index_expression : public Parser_expression
const Expression* start, const Expression* end,
const Expression* cap);
+ // Report whether EXPR is a map index expression.
+ static bool
+ is_map_index(Expression* expr);
+
protected:
int
do_traverse(Traverse*);
+ Type*
+ do_type();
+
+ void
+ do_determine_type(Gogo*, const Type_context*);
+
+ void
+ do_check_types(Gogo*);
+
+ bool
+ do_is_addressable() const;
+
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());
+ Index_expression* ret =
+ 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());
+ if (this->needs_nil_check_)
+ ret->needs_nil_check_ = true;
+ return ret;
}
// This shouldn't be called--we don't know yet.
@@ -3173,8 +3266,8 @@ class Index_expression : public Parser_expression
do_dump_expression(Ast_dump_context*) const;
void
- do_issue_nil_check()
- { this->left_->issue_nil_check(); }
+ do_issue_nil_check();
+
private:
// The expression being indexed.
Expression* left_;
@@ -3187,6 +3280,9 @@ class Index_expression : public Parser_expression
// default capacity, non-NULL for indices and slices that specify the
// capacity.
Expression* cap_;
+ // True if this needs a nil check. This changes how we handle
+ // dereferencing a pointer to an array.
+ bool needs_nil_check_;
};
// An array index. This is used for both indexing and slicing.
@@ -3234,6 +3330,11 @@ class Array_index_expression : public Expression
set_needs_bounds_check(bool b)
{ this->needs_bounds_check_ = b; }
+ // Check indexes.
+ static bool
+ check_indexes(Expression* array, Expression* start, Expression* len,
+ Expression* cap, Location);
+
protected:
int
do_traverse(Traverse*);
@@ -3339,6 +3440,11 @@ class String_index_expression : public Expression
end() const
{ return this->end_; }
+ // Check indexes.
+ static bool
+ check_indexes(Expression* string, Expression* start, Expression* len,
+ Location);
+
protected:
int
do_traverse(Traverse*);
@@ -3832,7 +3938,8 @@ class Composite_literal_expression : public Parser_expression
Location location)
: Parser_expression(EXPRESSION_COMPOSITE_LITERAL, location),
type_(type), depth_(depth), vals_(vals), has_keys_(has_keys),
- all_are_names_(all_are_names), key_path_(std::vector<bool>(depth))
+ all_are_names_(all_are_names), key_path_(std::vector<bool>(depth)),
+ traverse_order_(NULL)
{}
@@ -3848,6 +3955,15 @@ class Composite_literal_expression : public Parser_expression
int
do_traverse(Traverse* traverse);
+ Type*
+ do_type();
+
+ void
+ do_determine_type(Gogo*, const Type_context*);
+
+ void
+ do_check_types(Gogo*);
+
Expression*
do_lower(Gogo*, Named_object*, Statement_inserter*, int);
@@ -3858,8 +3974,14 @@ class Composite_literal_expression : public Parser_expression
do_dump_expression(Ast_dump_context*) const;
private:
+ bool
+ resolve_struct_keys(Gogo*, Type* type);
+
+ void
+ resolve_array_length(Type*);
+
Expression*
- lower_struct(Gogo*, Type*);
+ lower_struct(Type*);
Expression*
lower_array(Type*);
@@ -3888,6 +4010,10 @@ class Composite_literal_expression : public Parser_expression
// a value. This is used to decide which type to use when given a map literal
// with omitted key types.
std::vector<bool> key_path_;
+ // If not NULL, the order in which to traverse vals_ for a struct
+ // composite literal. This is used so that we implement the order
+ // of evaluation rules correctly.
+ std::vector<unsigned long>* traverse_order_;
};
// Helper/mixin class for struct and array construction expressions;
@@ -3948,6 +4074,10 @@ class Struct_construction_expression : public Expression,
bool
is_constant_struct() const;
+ // Check types of a struct composite literal.
+ static bool
+ check_value_types(Gogo*, Type*, Expression_list*, Location);
+
protected:
int
do_traverse(Traverse* traverse);