compiler: change expression importing to use Import_expression
authorIan Lance Taylor <ian@gcc.gnu.org>
Tue, 27 Nov 2018 20:07:15 +0000 (20:07 +0000)
committerIan Lance Taylor <ian@gcc.gnu.org>
Tue, 27 Nov 2018 20:07:15 +0000 (20:07 +0000)
    Change expression importing to use a new abstract interface class
    Import_expression, so that we can more easily import expressions from
    inlinable function bodies.  This is a refactoring with no affect on
    compiler behavior.

    Reviewed-on: https://go-review.googlesource.com/c/150065

From-SVN: r266526

gcc/go/gofrontend/MERGE
gcc/go/gofrontend/expressions.cc
gcc/go/gofrontend/expressions.h
gcc/go/gofrontend/gogo.cc
gcc/go/gofrontend/gogo.h
gcc/go/gofrontend/import.cc
gcc/go/gofrontend/import.h

index 71c7fcff227dbee47ac1b52926db47e8b38b4f21..7aebeb10333f668ea5a7de4a012d395a1dcf85b7 100644 (file)
@@ -1,4 +1,4 @@
-75d48ff977a2865d12b03857362ea48016a4b885
+6e0974fc6c9aa6ef19f72fbb5698e4b3734a4220
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
index 391eb663be45e4ba4a57b65dc92de03608d66984..9292b5c4d2f471245326763d95933ec4221dcd45 100644 (file)
@@ -1583,7 +1583,7 @@ class Boolean_expression : public Expression
   { }
 
   static Expression*
-  do_import(Import*, Location);
+  do_import(Import_expression*, Location);
 
  protected:
   bool
@@ -1649,7 +1649,7 @@ Boolean_expression::do_determine_type(const Type_context* context)
 // Import a boolean constant.
 
 Expression*
-Boolean_expression::do_import(Import* imp, Location loc)
+Boolean_expression::do_import(Import_expression* imp, Location loc)
 {
   if (imp->peek_char() == 't')
     {
@@ -1768,7 +1768,7 @@ String_expression::do_export(Export_function_body* efb) const
 // Import a string expression.
 
 Expression*
-String_expression::do_import(Import* imp, Location loc)
+String_expression::do_import(Import_expression* imp, Location loc)
 {
   imp->require_c_string("\"");
   std::string val;
@@ -1944,7 +1944,7 @@ class Integer_expression : public Expression
   { mpz_init_set(this->val_, *val); }
 
   static Expression*
-  do_import(Import*, Location);
+  do_import(Import_expression*, Location);
 
   // Write VAL to string dump.
   static void
@@ -2151,7 +2151,7 @@ Integer_expression::do_export(Export_function_body* efb) const
 // all these types because they all start with digits.
 
 Expression*
-Integer_expression::do_import(Import* imp, Location loc)
+Integer_expression::do_import(Import_expression* imp, Location loc)
 {
   std::string num = imp->read_identifier();
   imp->require_c_string(" ");
@@ -3133,7 +3133,7 @@ class Nil_expression : public Expression
   { }
 
   static Expression*
-  do_import(Import*, Location);
+  do_import(Import_expression*, Location);
 
  protected:
   bool
@@ -3172,7 +3172,7 @@ class Nil_expression : public Expression
 // Import a nil expression.
 
 Expression*
-Nil_expression::do_import(Import* imp, Location loc)
+Nil_expression::do_import(Import_expression* imp, Location loc)
 {
   imp->require_c_string("nil");
   return Expression::make_nil(loc);
@@ -3623,7 +3623,7 @@ Type_conversion_expression::do_export(Export_function_body* efb) const
 // Import a type conversion or a struct construction.
 
 Expression*
-Type_conversion_expression::do_import(Import* imp, Location loc)
+Type_conversion_expression::do_import(Import_expression* imp, Location loc)
 {
   imp->require_c_string("convert(");
   Type* type = imp->read_type();
@@ -4634,7 +4634,7 @@ Unary_expression::do_export(Export_function_body* efb) const
 // Import a unary expression.
 
 Expression*
-Unary_expression::do_import(Import* imp, Location loc)
+Unary_expression::do_import(Import_expression* imp, Location loc)
 {
   Operator op;
   switch (imp->get_char())
@@ -6403,7 +6403,7 @@ Binary_expression::do_export(Export_function_body* efb) const
 // Import a binary expression.
 
 Expression*
-Binary_expression::do_import(Import* imp, Location loc)
+Binary_expression::do_import(Import_expression* imp, Location loc)
 {
   imp->require_c_string("(");
 
@@ -16138,7 +16138,7 @@ Expression::make_backend(Bexpression* bexpr, Type* type, Location location)
 // various class definitions.
 
 Expression*
-Expression::import_expression(Import* imp, Location loc)
+Expression::import_expression(Import_expression* imp, Location loc)
 {
   int c = imp->peek_char();
   if (imp->match_c_string("- ")
index 3641b03239e500f6377502ef911fa56f6744cdb0..70616571922582e35ce86d99078db76aa023b6b3 100644 (file)
@@ -66,7 +66,7 @@ class Compound_expression;
 class Numeric_constant;
 class Named_object;
 class Export_function_body;
-class Import;
+class Import_expression;
 class Temporary_statement;
 class Label;
 class Ast_dump_context;
@@ -1018,7 +1018,7 @@ class Expression
   // returned expression.  Errors should be reported using the
   // Import's location method.
   static Expression*
-  import_expression(Import*, Location);
+  import_expression(Import_expression*, Location);
 
   // Return an expression which checks that VAL, of arbitrary integer type,
   // is non-negative and is not more than the maximum integer value.
@@ -1567,7 +1567,7 @@ class String_expression : public Expression
   { return this->val_; }
 
   static Expression*
-  do_import(Import*, Location);
+  do_import(Import_expression*, Location);
 
  protected:
   bool
@@ -1646,7 +1646,7 @@ class Type_conversion_expression : public Expression
 
   // Import a type conversion expression.
   static Expression*
-  do_import(Import*, Location);
+  do_import(Import_expression*, Location);
 
  protected:
   int
@@ -1817,7 +1817,7 @@ class Unary_expression : public Expression
                Location, Numeric_constant* nc, bool *issued_error);
 
   static Expression*
-  do_import(Import*, Location);
+  do_import(Import_expression*, Location);
 
   // Declare that this deref does or does not require an explicit nil check.
   void
@@ -1966,7 +1966,7 @@ class Binary_expression : public Expression
                   bool* result);
 
   static Expression*
-  do_import(Import*, Location);
+  do_import(Import_expression*, Location);
 
   // Report an error if OP can not be applied to TYPE.  Return whether
   // it can.  OTYPE is the type of the other operand.
index 79d92e559d82688d1325de109134952a4af1f527..eb0297bc2db379ee96af9c4405647eedc3c9eb00 100644 (file)
@@ -527,9 +527,9 @@ Gogo::import_package(const std::string& filename,
       return;
     }
 
-  Import imp(stream, location);
-  imp.register_builtin_types(this);
-  Package* package = imp.import(this, local_name, is_local_name_exported);
+  Import* imp = new Import(stream, location);
+  imp->register_builtin_types(this);
+  Package* package = imp->import(this, local_name, is_local_name_exported);
   if (package != NULL)
     {
       if (package->pkgpath() == this->pkgpath())
@@ -540,7 +540,10 @@ Gogo::import_package(const std::string& filename,
       this->imports_.insert(std::make_pair(filename, package));
     }
 
+  imp->clear_stream();
   delete stream;
+
+  // FIXME: we never delete imp; we may need it for inlinable functions.
 }
 
 Import_init *
@@ -6763,8 +6766,6 @@ Function_declaration::import_function_body(Gogo* gogo, Named_object* no)
   const std::string& body(this->imported_body_);
   go_assert(!body.empty());
 
-  Location orig_loc = no->location();
-
   // Read the "//FILE:LINE" comment starts the export data.
 
   size_t indent = 1;
@@ -6877,7 +6878,7 @@ Function_declaration::import_function_body(Gogo* gogo, Named_object* no)
       no = rtype->add_method(no->name(), fn);
     }
 
-  Import_function_body ifb(gogo, orig_loc, no, body, nl + 1, outer, indent);
+  Import_function_body ifb(gogo, this->imp_, no, body, nl + 1, outer, indent);
 
   if (!Block::import_block(outer, &ifb, start_loc))
     return;
index 1c79f6fda57e86b54cbc22f64471067c102ae1ea..8ca567ca13c1a0cb7727a32122e1cb5bc55d3acd 100644 (file)
@@ -1691,8 +1691,11 @@ class Function_declaration
 
   // Record the imported body of this function.
   void
-  set_imported_body(const std::string& imported_body)
-  { this->imported_body_ = imported_body; }
+  set_imported_body(Import* imp, const std::string& imported_body)
+  {
+    this->imp_ = imp;
+    this->imported_body_ = imported_body;
+  }
 
   // Whether this declaration is on the list of inlinable functions.
   bool
@@ -1756,6 +1759,8 @@ class Function_declaration
   Bfunction* fndecl_;
   // Pragmas for this function.  This is a set of GOPRAGMA bits.
   unsigned int pragmas_;
+  // Importer for function body if imported from a different package.
+  Import* imp_;
   // Export data for function body if imported from a different package.
   std::string imported_body_;
   // Whether this declaration is already on the list of inlinable functions.
index 7ee3cb6f991c785bc8de0b9f9303f896d4fa84d5..524e739f21c3c3b3085ef9ecc421214e74bb2725 100644 (file)
@@ -790,7 +790,7 @@ Import::import_func(Package* package)
   if (nointerface)
     no->func_declaration_value()->set_nointerface();
   if (!body.empty() && !no->func_declaration_value()->has_imported_body())
-    no->func_declaration_value()->set_imported_body(body);
+    no->func_declaration_value()->set_imported_body(this, body);
 
   return no;
 }
@@ -886,41 +886,7 @@ Import::read_type()
   if (c == '>')
     {
       // A reference to a type defined earlier.
-
-      if (index >= 0 && !this->type_data_.empty())
-       {
-         if (static_cast<size_t>(index) >= this->type_offsets_.size())
-           {
-             go_error_at(this->location_,
-                         ("error in import data at %d: "
-                          "bad type index %d >= %d"),
-                         stream->pos(), index,
-                         static_cast<int>(this->type_offsets_.size()));
-             stream->set_saw_error();
-             return Type::make_error_type();
-           }
-
-         if (this->types_[index] == NULL)
-           {
-             if (!this->parse_type(index))
-               return Type::make_error_type();
-           }
-       }
-
-      if (index < 0
-         ? (static_cast<size_t>(- index) >= this->builtin_types_.size()
-            || this->builtin_types_[- index] == NULL)
-         : (static_cast<size_t>(index) >= this->types_.size()
-            || this->types_[index] == NULL))
-       {
-         go_error_at(this->location_,
-                     "error in import data at %d: bad type index %d",
-                     stream->pos(), index);
-         stream->set_saw_error();
-         return Type::make_error_type();
-       }
-
-      return index < 0 ? this->builtin_types_[- index] : this->types_[index];
+      return this->type_for_index(index, "import data", stream->pos());
     }
 
   if (this->version_ >= EXPORT_FORMAT_V3)
@@ -1126,6 +1092,47 @@ Import::read_named_type(int index)
   return type;
 }
 
+// Return the type given an index.
+
+Type*
+Import::type_for_index(int index, const std::string& input_name,
+                      size_t input_offset)
+{
+  if (index >= 0 && !this->type_data_.empty())
+    {
+      if (static_cast<size_t>(index) >= this->type_offsets_.size())
+       {
+         go_error_at(this->location_,
+                     "error in %s at %lu: bad type index %d >= %d",
+                     input_name.c_str(),
+                     static_cast<unsigned long>(input_offset),
+                     index, static_cast<int>(this->type_offsets_.size()));
+         return Type::make_error_type();
+       }
+
+      if (this->types_[index] == NULL)
+       {
+         if (!this->parse_type(index))
+           return Type::make_error_type();
+       }
+    }
+
+  if (index < 0
+      ? (static_cast<size_t>(- index) >= this->builtin_types_.size()
+        || this->builtin_types_[- index] == NULL)
+      : (static_cast<size_t>(index) >= this->types_.size()
+        || this->types_[index] == NULL))
+    {
+      go_error_at(this->location_,
+                 "error in %s at %lu: bad type index %d",
+                 input_name.c_str(),
+                 static_cast<unsigned long>(input_offset), index);
+      return Type::make_error_type();
+    }
+
+  return index < 0 ? this->builtin_types_[- index] : this->types_[index];
+}
+
 // Read an escape note.
 
 std::string
@@ -1408,3 +1415,88 @@ Import_function_body::name() const
 {
   return this->named_object_->name();
 }
+
+// Class Import_function_body.
+
+// Require that the next bytes match STR, issuing an error if not.
+// Advance past the string.
+
+void
+Import_function_body::require_c_string(const char* str)
+{
+  if (!this->match_c_string(str))
+    {
+      if (!this->saw_error_)
+       go_error_at(this->location(),
+                   "invalid export data for %qs: expected %qs at %lu",
+                   this->name().c_str(), str,
+                   static_cast<unsigned long>(this->off_));
+      this->saw_error_ = true;
+      return;
+    }
+  this->advance(strlen(str));
+}
+
+// Read an identifier.
+
+std::string
+Import_function_body::read_identifier()
+{
+  size_t start = this->off_;
+  for (size_t i = start; i < this->body_.length(); i++)
+    {
+      int c = static_cast<unsigned char>(this->body_[i]);
+      if (c == ' ' || c == '\n' || c == ';')
+       {
+         this->off_ = i;
+         return this->body_.substr(start, i - start);
+       }
+    }
+  this->off_ = this->body_.length();
+  return this->body_.substr(start);
+}
+
+// Read a type.
+
+Type*
+Import_function_body::read_type()
+{
+  this->require_c_string("<type ");
+  size_t start = this->off_;
+  size_t i;
+  int c = '\0';
+  for (i = start; i < this->body_.length(); ++i)
+    {
+      c = static_cast<unsigned char>(this->body_[i]);
+      if (c != '-' && (c < '0' || c > '9'))
+       break;
+    }
+  this->off_ = i + 1;
+
+  char *end;
+  long val = strtol(this->body_.substr(start, i - start).c_str(), &end, 10);
+  if (*end != '\0' || i > 0x7fffffff)
+    {
+      if (!this->saw_error_)
+       go_error_at(this->location(),
+                   "invalid export data for %qs: expected integer at %lu",
+                   this->name().c_str(),
+                   static_cast<unsigned long>(start));
+      this->saw_error_ = true;
+      return Type::make_error_type();
+    }
+
+  if (c != '>')
+    {
+      if (!this->saw_error_)
+       go_error_at(this->location(),
+                   "invalid export data for %qs: expected %<>%> at %lu",
+                   this->name().c_str(),
+                   static_cast<unsigned long>(i));
+      this->saw_error_ = true;
+      return Type::make_error_type();
+    }
+
+  return this->imp_->type_for_index(static_cast<int>(val), this->name(),
+                                   static_cast<unsigned long>(start));
+}
index 3fc05dfcaa788afb2d1f81a3c8b7476049c4afe1..c2120c9afd294f23573f5e8abb2956efb878dad9 100644 (file)
@@ -17,10 +17,65 @@ class Type;
 class Named_object;
 class Named_type;
 class Expression;
+class Import_function_body;
+
+// Expressions can be imported either directly from import data (for
+// simple constant expressions that can appear in a const declaration
+// or as an array length in a type definition) or from an exported
+// function body (for an inlinable function).  These two cases happen
+// at different points in the compilation and have different
+// requirements, so it's not easy to unify them.  Import_expression is
+// an abstract interface that permits the expression import code to
+// work at either point.  When importing expressions that only occur
+// for an inlinable function, the ifb method is available to get the
+// full Import_function_body.
+
+class Import_expression
+{
+ public:
+  // Return the import function body.  This should only be called for
+  // expressions that can not appear outside of an inlinable function
+  // body.
+  virtual Import_function_body*
+  ifb() = 0;
+
+  // The location to report in an error message.
+  virtual Location
+  location() const = 0;
+
+  // Peek at the next character in the input, returning a value from 0
+  // to 0xff.  Returns -1 at end of stream.
+  virtual int
+  peek_char() = 0;
+
+  // Return the next character and advance.
+  virtual int
+  get_char() = 0;
+
+  // Return true if the next bytes match STR.
+  virtual bool
+  match_c_string(const char* str) = 0;
+
+  // Require that the next bytes match STR.
+  virtual void
+  require_c_string(const char* str) = 0;
+
+  // Advance the stream SKIP bytes.
+  virtual void
+  advance(size_t skip) = 0;
+
+  // Read an identifier.
+  virtual std::string
+  read_identifier() = 0;
+
+  // Read a type.
+  virtual Type*
+  read_type() = 0;
+};
 
 // This class manages importing Go declarations.
 
-class Import
+class Import : public Import_expression
 {
  public:
   // The Stream class is an interface used to read the data.  The
@@ -138,6 +193,9 @@ class Import
   // Constructor.
   Import(Stream*, Location);
 
+  virtual ~Import()
+  {}
+
   // Register the builtin types.
   void
   register_builtin_types(Gogo*);
@@ -217,10 +275,26 @@ class Import
   Type*
   read_type();
 
+  // Return the type for a type index.  INPUT_NAME and INPUT_OFFSET
+  // are only for error reporting.
+  Type*
+  type_for_index(int index, const std::string& input_name,
+                size_t input_offset);
+
   // Read an escape note.
   std::string
   read_escape();
 
+  // Clear the stream when it is no longer accessible.
+  void
+  clear_stream()
+  { this->stream_ = NULL; }
+
+  // Just so that Import implements Import_expression.
+  Import_function_body*
+  ifb()
+  { return NULL; }
+
  private:
   static Stream*
   try_package_in_directory(const std::string&, Location);
@@ -468,13 +542,13 @@ class Stream_from_string_ref : public Import::Stream
 // Class to manage importing a function body.  This is passed around
 // to Statements and Expressions.  It parses the function into the IR.
 
-class Import_function_body
+class Import_function_body : public Import_expression
 {
  public:
-  Import_function_body(Gogo* gogo, Location loc, Named_object* named_object,
+  Import_function_body(Gogo* gogo, Import* imp, Named_object* named_object,
                       const std::string& body, size_t off, Block* block,
                       int indent)
-    : gogo_(gogo), loc_(loc), named_object_(named_object), body_(body),
+    : gogo_(gogo), imp_(imp), named_object_(named_object), body_(body),
       off_(off), block_(block), indent_(indent)
   { }
 
@@ -486,7 +560,7 @@ class Import_function_body
   // The location to report in an error message.
   Location
   location() const
-  { return this->loc_; }
+  { return this->imp_->location(); }
 
   // A reference to the body we are reading.
   const std::string&
@@ -503,6 +577,11 @@ class Import_function_body
   set_off(size_t off)
   { this->off_ = off; }
 
+  // Advance the offset by SKIP bytes.
+  void
+  advance(size_t skip)
+  { this->off_ += skip; }
+
   // The current block.
   Block*
   block()
@@ -517,11 +596,58 @@ class Import_function_body
   const std::string&
   name() const;
 
+  // Return the next character in the input stream, or -1 at the end.
+  int
+  peek_char()
+  {
+    if (this->body_.length() <= this->off_)
+      return -1;
+    return static_cast<unsigned char>(this->body_[this->off_]);
+  }
+
+  // Return the next character and advance.
+  int
+  get_char()
+  {
+    if (this->body_.length() <= this->off_)
+      return -1;
+    int c = static_cast<unsigned char>(this->body_[this->off_]);
+    this->off_++;
+    return c;
+  }
+
+  // Return whether the C string matches the current body position.
+  bool
+  match_c_string(const char* str)
+  {
+    size_t len = strlen(str);
+    return (this->body_.length() >= this->off_ + len
+           && this->body_.compare(this->off_, len, str) == 0);
+  }
+
+  // Give an error if the next bytes do not match STR.  Advance the
+  // offset by the length of STR.
+  void
+  require_c_string(const char* str);
+
+  // Read an identifier.
+  std::string
+  read_identifier();
+
+  // Read a type.
+  Type*
+  read_type();
+
+  // Implement Import_expression.
+  Import_function_body*
+  ifb()
+  { return this; }
+
  private:
   // The IR.
   Gogo* gogo_;
-  // The location to report in an error message.
-  Location loc_;
+  // The importer.
+  Import* imp_;
   // The function we are parsing.
   Named_object* named_object_;
   // The exported data we are parsing.  Note that this is a reference;
@@ -533,6 +659,9 @@ class Import_function_body
   Block* block_;
   // Current expected indentation level.
   int indent_;
+  // Whether we've seen an error.  Used to avoid reporting excess
+  // errors.
+  bool saw_error_;
 };
 
 #endif // !defined(GO_IMPORT_H)