Go patch committed: Add Expression::is_untyped method

Message ID CAOyqgcU3j0sDsO0Q9pav_ZmDXoo-3qs7LqB9PFcjD2+K-BbaBQ@mail.gmail.com
State Unresolved
Headers
Series Go patch committed: Add Expression::is_untyped method |

Checks

Context Check Description
snail/gcc-patch-check warning Git am fail log

Commit Message

Ian Lance Taylor Oct. 23, 2023, 9:06 p.m. UTC
  This Go frontend patches adds an Expression::is_untyped method.  This
method is not currently used by anything, but it will be used by later
changes in this series.  Bootstrapped and ran Go testsuite on
x86_64-pc-linux-gnu.  Committed to mainline.

Ian
ac50e9b72bf9bb6d5b28096bb164fb050db6e290
  

Patch

diff --git a/gcc/go/gofrontend/MERGE b/gcc/go/gofrontend/MERGE
index 0f961157dfd..d4095637cea 100644
--- a/gcc/go/gofrontend/MERGE
+++ b/gcc/go/gofrontend/MERGE
@@ -1,4 +1,4 @@ 
-081ec9824a74ec9d82628d8d2f6b9a7a4c35a529
+1c0a7c9338801d15afba7e39109554ed3406654e
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
diff --git a/gcc/go/gofrontend/expressions.cc b/gcc/go/gofrontend/expressions.cc
index 273831fabf3..5bea6238def 100644
--- a/gcc/go/gofrontend/expressions.cc
+++ b/gcc/go/gofrontend/expressions.cc
@@ -201,6 +201,19 @@  Expression::report_error(const char* msg)
   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.
 
@@ -826,6 +839,10 @@  class Error_expression : public Expression
   do_is_constant() const
   { return true; }
 
+  bool
+  do_is_untyped(Type**) const
+  { return false; }
+
   bool
   do_numeric_constant_value(Numeric_constant* nc) const
   {
@@ -1965,6 +1982,9 @@  class Boolean_expression : public Expression
   do_is_constant() const
   { return true; }
 
+  bool
+  do_is_untyped(Type**) const;
+
   bool
   do_is_zero_value() const
   { return this->val_ == false; }
@@ -2023,6 +2043,15 @@  Boolean_expression::do_traverse(Traverse* traverse)
   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*
@@ -2096,6 +2125,15 @@  String_expression::do_traverse(Traverse* traverse)
   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*
@@ -2485,6 +2523,9 @@  class Integer_expression : public Expression
   do_is_constant() const
   { return true; }
 
+  bool
+  do_is_untyped(Type**) const;
+
   bool
   do_is_zero_value() const
   { return mpz_sgn(this->val_) == 0; }
@@ -2568,6 +2609,18 @@  Integer_expression::do_numeric_constant_value(Numeric_constant* nc) const
   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.
 
@@ -2913,6 +2966,9 @@  class Float_expression : public Expression
   do_is_constant() const
   { return true; }
 
+  bool
+  do_is_untyped(Type**) const;
+
   bool
   do_is_zero_value() const
   {
@@ -2979,6 +3035,15 @@  Float_expression::do_traverse(Traverse* traverse)
   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.
 
@@ -3135,6 +3200,9 @@  class Complex_expression : public Expression
   do_is_constant() const
   { return true; }
 
+  bool
+  do_is_untyped(Type**) const;
+
   bool
   do_is_zero_value() const
   {
@@ -3205,6 +3273,15 @@  Complex_expression::do_traverse(Traverse* traverse)
   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.
 
@@ -3458,6 +3535,21 @@  Const_expression::do_boolean_constant_value(bool* val) const
   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*
@@ -3707,6 +3799,13 @@  class Nil_expression : public Expression
   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; }
@@ -4774,6 +4873,14 @@  Unary_expression::do_is_constant() const
     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.
 
@@ -5523,6 +5630,81 @@  Binary_expression::do_traverse(Traverse* traverse)
   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
@@ -7645,6 +7827,21 @@  String_concat_expression::do_is_constant() const
   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
 {
@@ -9671,6 +9868,47 @@  Builtin_call_expression::do_is_constant() 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
diff --git a/gcc/go/gofrontend/expressions.h b/gcc/go/gofrontend/expressions.h
index 2abc9cb8425..49140d100a4 100644
--- a/gcc/go/gofrontend/expressions.h
+++ b/gcc/go/gofrontend/expressions.h
@@ -566,6 +566,15 @@  class Expression
   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
@@ -1169,6 +1178,11 @@  class Expression
   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
@@ -1274,6 +1288,12 @@  class Expression
   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*);
@@ -1501,6 +1521,9 @@  class Const_expression : public Expression
   do_is_constant() const
   { return true; }
 
+  bool
+  do_is_untyped(Type**) const;
+
   bool
   do_is_zero_value() const;
 
@@ -1830,6 +1853,9 @@  class String_expression : public Expression
   do_is_constant() const
   { return true; }
 
+  bool
+  do_is_untyped(Type**) const;
+
   bool
   do_is_zero_value() const
   { return this->val_ == ""; }
@@ -2136,6 +2162,9 @@  class Unary_expression : public Expression
   bool
   do_is_constant() const;
 
+  bool
+  do_is_untyped(Type**) const;
+
   bool
   do_is_static_initializer() const;
 
@@ -2293,6 +2322,9 @@  class Binary_expression : public Expression
   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;
 
@@ -2415,6 +2447,9 @@  class String_concat_expression : public Expression
   bool
   do_is_constant() const;
 
+  bool
+  do_is_untyped(Type**) const;
+
   bool
   do_is_zero_value() const;
 
@@ -2767,6 +2802,9 @@  class Builtin_call_expression : public Call_expression
   bool
   do_is_constant() const;
 
+  bool
+  do_is_untyped(Type**) const;
+
   bool
   do_numeric_constant_value(Numeric_constant*) const;