this->set_is_error();
}
+// A convenience function for handling a type in do_is_untyped. If
+// TYPE is not abstract, return false. Otherwise set *PTYPE to TYPE
+// and return true.
+
+bool
+Expression::is_untyped_type(Type* type, Type** ptype)
+{
+ if (!type->is_abstract())
+ return false;
+ *ptype = type;
+ return true;
+}
+
// Set types of variables and constants. This is implemented by the
// child class.
do_is_constant() const
{ return true; }
+ bool
+ do_is_untyped(Type**) const
+ { return false; }
+
bool
do_numeric_constant_value(Numeric_constant* nc) const
{
do_is_constant() const
{ return true; }
+ bool
+ do_is_untyped(Type**) const;
+
bool
do_is_zero_value() const
{ return this->val_ == false; }
return TRAVERSE_CONTINUE;
}
+bool
+Boolean_expression::do_is_untyped(Type** ptype) const
+{
+ if (this->type_ != NULL)
+ return Expression::is_untyped_type(this->type_, ptype);
+ *ptype = Type::make_boolean_type();
+ return true;
+}
+
// Get the type.
Type*
return TRAVERSE_CONTINUE;
}
+bool
+String_expression::do_is_untyped(Type** ptype) const
+{
+ if (this->type_ != NULL)
+ return Expression::is_untyped_type(this->type_, ptype);
+ *ptype = Type::make_string_type();
+ return true;
+}
+
// Get the type.
Type*
do_is_constant() const
{ return true; }
+ bool
+ do_is_untyped(Type**) const;
+
bool
do_is_zero_value() const
{ return mpz_sgn(this->val_) == 0; }
return true;
}
+bool
+Integer_expression::do_is_untyped(Type** ptype) const
+{
+ if (this->type_ != NULL)
+ return Expression::is_untyped_type(this->type_, ptype);
+ if (this->is_character_constant_)
+ *ptype = Type::make_abstract_character_type();
+ else
+ *ptype = Type::make_abstract_integer_type();
+ return true;
+}
+
// Return the current type. If we haven't set the type yet, we return
// an abstract integer type.
do_is_constant() const
{ return true; }
+ bool
+ do_is_untyped(Type**) const;
+
bool
do_is_zero_value() const
{
return TRAVERSE_CONTINUE;
}
+bool
+Float_expression::do_is_untyped(Type** ptype) const
+{
+ if (this->type_ != NULL)
+ return Expression::is_untyped_type(this->type_, ptype);
+ *ptype = Type::make_abstract_float_type();
+ return true;
+}
+
// Return the current type. If we haven't set the type yet, we return
// an abstract float type.
do_is_constant() const
{ return true; }
+ bool
+ do_is_untyped(Type**) const;
+
bool
do_is_zero_value() const
{
return TRAVERSE_CONTINUE;
}
+bool
+Complex_expression::do_is_untyped(Type** ptype) const
+{
+ if (this->type_ != NULL)
+ return Expression::is_untyped_type(this->type_, ptype);
+ *ptype = Type::make_abstract_complex_type();
+ return true;
+}
+
// Return the current type. If we haven't set the type yet, we return
// an abstract complex type.
return ok;
}
+// Whether this is untyped.
+
+bool
+Const_expression::do_is_untyped(Type** ptype) const
+{
+ if (this->type_ != NULL)
+ return Expression::is_untyped_type(this->type_, ptype);
+
+ Named_constant* nc = this->constant_->const_value();
+ if (nc->type() != NULL)
+ return Expression::is_untyped_type(nc->type(), ptype);
+
+ return nc->expr()->is_untyped(ptype);
+}
+
// Return the type of the const reference.
Type*
do_is_constant() const
{ return true; }
+ bool
+ do_untyped_type(Type** ptype) const
+ {
+ *ptype = Type::make_nil_type();
+ return true;
+ }
+
bool
do_is_zero_value() const
{ return true; }
return this->expr_->is_constant();
}
+bool
+Unary_expression::do_is_untyped(Type** ptype) const
+{
+ if (this->op_ == OPERATOR_MULT || this->op_ == OPERATOR_AND)
+ return false;
+ return this->expr_->is_untyped(ptype);
+}
+
// Return whether a unary expression can be used as a constant
// initializer.
return Expression::traverse(&this->right_, traverse);
}
+// Return whether a binary expression is untyped.
+
+bool
+Binary_expression::do_is_untyped(Type** ptype) const
+{
+ if (this->type_ != NULL)
+ return Expression::is_untyped_type(this->type_, ptype);
+
+ switch (this->op_)
+ {
+ case OPERATOR_EQEQ:
+ case OPERATOR_NOTEQ:
+ case OPERATOR_LT:
+ case OPERATOR_LE:
+ case OPERATOR_GT:
+ case OPERATOR_GE:
+ // Comparisons are untyped by default.
+ *ptype = Type::make_boolean_type();
+ return true;
+
+ case OPERATOR_LSHIFT:
+ case OPERATOR_RSHIFT:
+ // A shift operation is untyped if the left hand expression is
+ // untyped. The right hand expression is irrelevant.
+ return this->left_->is_untyped(ptype);
+
+ default:
+ break;
+ }
+
+ Type* tleft;
+ Type* tright;
+ if (!this->left_->is_untyped(&tleft)
+ || !this->right_->is_untyped(&tright))
+ return false;
+
+ // If both sides are numeric, pick a type based on the kind.
+ enum kind { INT, RUNE, FLOAT, COMPLEX };
+ enum kind kleft, kright;
+
+ if (tleft->integer_type() != NULL)
+ kleft = tleft->integer_type()->is_rune() ? RUNE : INT;
+ else if (tleft->float_type() != NULL)
+ kleft = FLOAT;
+ else if (tleft->complex_type() != NULL)
+ kleft = COMPLEX;
+ else
+ {
+ // Not numeric. If the types are different, we will report an
+ // error later.
+ *ptype = tleft;
+ return true;
+ }
+
+ if (tright->integer_type() != NULL)
+ kright = tright->integer_type()->is_rune() ? RUNE : INT;
+ else if (tright->float_type() != NULL)
+ kright = FLOAT;
+ else if (tright->complex_type() != NULL)
+ kright = COMPLEX;
+ else
+ {
+ // Types are different. We will report an error later.
+ *ptype = tleft;
+ return true;
+ }
+
+ if (kleft > kright)
+ *ptype = tleft;
+ else
+ *ptype = tright;
+
+ return true;
+}
+
// Return whether this expression may be used as a static initializer.
bool
return true;
}
+bool
+String_concat_expression::do_is_untyped(Type** ptype) const
+{
+ for (Expression_list::iterator pe = this->exprs_->begin();
+ pe != this->exprs_->end();
+ ++pe)
+ {
+ if (!(*pe)->is_untyped(ptype))
+ return false;
+ }
+
+ *ptype = Type::make_string_type();
+ return true;
+}
+
bool
String_concat_expression::do_is_zero_value() const
{
return false;
}
+// Return whether a builtin call is untyped. Most builtin functions
+// have a known type, but complex, real, and imag can be untyped.
+
+bool
+Builtin_call_expression::do_is_untyped(Type** ptype) const
+{
+ if (this->is_error_expression())
+ return false;
+
+ switch (this->code_)
+ {
+ default:
+ return false;
+
+ case BUILTIN_COMPLEX:
+ {
+ const Expression_list* args = this->args();
+ if (args == NULL || args->size() != 2)
+ return false;
+ Type* dummy;
+ if (!args->front()->is_untyped(&dummy)
+ || !args->back()->is_untyped(&dummy))
+ return false;
+ *ptype = Type::make_abstract_complex_type();
+ return true;
+ }
+
+ case BUILTIN_REAL:
+ case BUILTIN_IMAG:
+ {
+ Expression* arg = this->one_arg();
+ if (arg == NULL)
+ return false;
+ if (!arg->is_untyped(ptype))
+ return false;
+ *ptype = Type::make_abstract_float_type();
+ return true;
+ }
+ }
+}
+
// Return a numeric constant if possible.
bool
is_constant() const
{ return this->do_is_constant(); }
+ // Return whether this expression is untyped. This isn't quite the
+ // same as is_constant with an abstract type, as 1<<val is untyped
+ // even if val is a variable. If this returns true, it sets *PTYPE
+ // to an abstract type, which is the type the expression will have
+ // if there is no context.
+ bool
+ is_untyped(Type** ptype) const
+ { return this->do_is_untyped(ptype); }
+
// Return whether this is the zero value of its type.
bool
is_zero_value() const
do_is_constant() const
{ return false; }
+ // Return whether this expression is untyped.
+ virtual bool
+ do_is_untyped(Type**) const
+ { return false; }
+
// Return whether this is the zero value of its type.
virtual bool
do_is_zero_value() const
void
report_error(const char*);
+ // A convenience function for handling a type in do_is_untyped. If
+ // TYPE is not abstract, return false. Otherwise set *PTYPE to TYPE
+ // and return true.
+ static bool
+ is_untyped_type(Type* type, Type** ptype);
+
// Write a name to export data.
static void
export_name(Export_function_body* efb, const Named_object*);
do_is_constant() const
{ return true; }
+ bool
+ do_is_untyped(Type**) const;
+
bool
do_is_zero_value() const;
do_is_constant() const
{ return true; }
+ bool
+ do_is_untyped(Type**) const;
+
bool
do_is_zero_value() const
{ return this->val_ == ""; }
bool
do_is_constant() const;
+ bool
+ do_is_untyped(Type**) const;
+
bool
do_is_static_initializer() const;
do_is_constant() const
{ return this->left_->is_constant() && this->right_->is_constant(); }
+ bool
+ do_is_untyped(Type**) const;
+
bool
do_is_static_initializer() const;
bool
do_is_constant() const;
+ bool
+ do_is_untyped(Type**) const;
+
bool
do_is_zero_value() const;
bool
do_is_constant() const;
+ bool
+ do_is_untyped(Type**) const;
+
bool
do_numeric_constant_value(Numeric_constant*) const;