This is the first in a series of patches to start changing gccgo's
export data to support type indexing and, eventually cross-package
inlining of simple functions.  (This is an inlining approach different
than LTO that relies on recording the function body in the export
data).  This patch doesn't do much, just drops some unnecessary
semicolons in the export data.  Bootstrapped and ran Go testsuite on
x86_64-pc-linux-gnu.  Committed to mainline.

Ian
Index: gcc/go/gofrontend/MERGE
===================================================================
--- gcc/go/gofrontend/MERGE     (revision 264985)
+++ gcc/go/gofrontend/MERGE     (working copy)
@@ -1,4 +1,4 @@
-e32e9aaee598eeb43f9616cf6ca1d11acaa9d167
+0494dc5737f0c89ad6f45e04e8313e4161678861
 
 The first line of this file holds the git revision number of the last
 merge done from the gofrontend repository.
Index: gcc/go/gofrontend/export.cc
===================================================================
--- gcc/go/gofrontend/export.cc (revision 264813)
+++ gcc/go/gofrontend/export.cc (working copy)
@@ -26,14 +26,18 @@ const int Export::magic_len;
 // Current version magic string.
 const char Export::cur_magic[Export::magic_len] =
   {
-    'v', '2', ';', '\n'
+    'v', '3', ';', '\n'
   };
 
-// Magic string for previous version (still supported)
+// Magic strings for previous versions (still supported).
 const char Export::v1_magic[Export::magic_len] =
   {
     'v', '1', ';', '\n'
   };
+const char Export::v2_magic[Export::magic_len] =
+  {
+    'v', '2', ';', '\n'
+  };
 
 const int Export::checksum_len;
 
@@ -147,7 +151,7 @@ Export::export_globals(const std::string
   // The package name.
   this->write_c_string("package ");
   this->write_string(package_name);
-  this->write_c_string(";\n");
+  this->write_c_string("\n");
 
   // The prefix or package path, used for all global symbols.
   if (prefix.empty())
@@ -161,7 +165,7 @@ Export::export_globals(const std::string
       this->write_c_string("prefix ");
       this->write_string(prefix);
     }
-  this->write_c_string(";\n");
+  this->write_c_string("\n");
 
   this->write_packages(packages);
 
@@ -191,7 +195,7 @@ Export::export_globals(const std::string
       dig = c & 0xf;
       s += dig < 10 ? '0' + dig : 'A' + dig - 10;
     }
-  s += ";\n";
+  s += "\n";
   this->stream_->write_checksum(s);
 }
 
@@ -233,7 +237,7 @@ Export::write_packages(const std::map<st
       this->write_string((*p)->pkgpath());
       this->write_c_string(" ");
       this->write_string((*p)->pkgpath_symbol());
-      this->write_c_string(";\n");
+      this->write_c_string("\n");
     }
 }
 
@@ -271,7 +275,7 @@ Export::write_imports(const std::map<std
       this->write_string(p->second->pkgpath());
       this->write_c_string(" \"");
       this->write_string(p->first);
-      this->write_c_string("\";\n");
+      this->write_c_string("\"\n");
 
       this->packages_.insert(p->second);
     }
@@ -347,7 +351,7 @@ Export::write_imported_init_fns(const st
 
   if (imported_init_fns.empty())
     {
-      this->write_c_string(";\n");
+      this->write_c_string("\n");
       return;
     }
 
@@ -394,7 +398,7 @@ Export::write_imported_init_fns(const st
            it->second.push_back(ii->init_name());
        }
     }
-  this->write_c_string(";\n");
+  this->write_c_string("\n");
 
   // Create the init graph. Start by populating the graph with
   // all the edges we inherited from imported packages.
@@ -494,7 +498,7 @@ Export::write_imported_init_fns(const st
          this->write_unsigned(sink);
        }
     }
-  this->write_c_string(";\n");
+  this->write_c_string("\n");
 }
 
 // Write a name to the export stream.
Index: gcc/go/gofrontend/export.h
===================================================================
--- gcc/go/gofrontend/export.h  (revision 264813)
+++ gcc/go/gofrontend/export.h  (working copy)
@@ -57,7 +57,8 @@ enum Export_data_version {
   EXPORT_FORMAT_UNKNOWN = 0,
   EXPORT_FORMAT_V1 = 1,
   EXPORT_FORMAT_V2 = 2,
-  EXPORT_FORMAT_CURRENT = EXPORT_FORMAT_V2
+  EXPORT_FORMAT_V3 = 3,
+  EXPORT_FORMAT_CURRENT = EXPORT_FORMAT_V3
 };
 
 // This class manages exporting Go declarations.  It handles the main
@@ -119,9 +120,10 @@ class Export : public String_dump
   // Size of export data magic string (which includes version number).
   static const int magic_len = 4;
 
-  // Magic strings (current version and older v1 version).
+  // Magic strings (current version and older versions).
   static const char cur_magic[magic_len];
   static const char v1_magic[magic_len];
+  static const char v2_magic[magic_len];
 
   // The length of the checksum string.
   static const int checksum_len = 20;
Index: gcc/go/gofrontend/gogo.cc
===================================================================
--- gcc/go/gofrontend/gogo.cc   (revision 264813)
+++ gcc/go/gofrontend/gogo.cc   (working copy)
@@ -5391,7 +5391,7 @@ Function::export_func_with_type(Export*
          exp->write_c_string(")");
        }
     }
-  exp->write_c_string(";\n");
+  exp->write_c_string("\n");
 }
 
 // Import a function.
@@ -5498,7 +5498,8 @@ Function::import_func(Import* imp, std::
          imp->require_c_string(")");
        }
     }
-  imp->require_c_string(";\n");
+  imp->require_semicolon_if_old_version();
+  imp->require_c_string("\n");
   *presults = results;
 }
 
@@ -6885,7 +6886,7 @@ Variable::export_var(Export* exp, const
   exp->write_string(name);
   exp->write_c_string(" ");
   exp->write_type(this->type());
-  exp->write_c_string(";\n");
+  exp->write_c_string("\n");
 }
 
 // Import a variable.
@@ -6897,7 +6898,8 @@ Variable::import_var(Import* imp, std::s
   *pname = imp->read_identifier();
   imp->require_c_string(" ");
   *ptype = imp->read_type();
-  imp->require_c_string(";\n");
+  imp->require_semicolon_if_old_version();
+  imp->require_c_string("\n");
 }
 
 // Convert a variable to the backend representation.
@@ -7089,7 +7091,7 @@ Named_constant::export_const(Export* exp
     }
   exp->write_c_string("= ");
   this->expr()->export_expression(exp);
-  exp->write_c_string(";\n");
+  exp->write_c_string("\n");
 }
 
 // Import a constant.
@@ -7110,7 +7112,8 @@ Named_constant::import_const(Import* imp
     }
   imp->require_c_string("= ");
   *pexpr = Expression::import_expression(imp);
-  imp->require_c_string(";\n");
+  imp->require_semicolon_if_old_version();
+  imp->require_c_string("\n");
 }
 
 // Get the backend representation.
Index: gcc/go/gofrontend/import.cc
===================================================================
--- gcc/go/gofrontend/import.cc (revision 264813)
+++ gcc/go/gofrontend/import.cc (working copy)
@@ -241,8 +241,9 @@ Import::find_export_data(const std::stri
     return NULL;
 
   // Check for a file containing nothing but Go export data.
-  if (memcmp(buf, Export::cur_magic, Export::magic_len) == 0 ||
-      memcmp(buf, Export::v1_magic, Export::magic_len) == 0)
+  if (memcmp(buf, Export::cur_magic, Export::magic_len) == 0
+      || memcmp(buf, Export::v1_magic, Export::magic_len) == 0
+      || memcmp(buf, Export::v2_magic, Export::magic_len) == 0)
     return new Stream_from_file(fd);
 
   // See if we can read this as an archive.
@@ -325,6 +326,12 @@ Import::import(Gogo* gogo, const std::st
                                Export::magic_len);
          this->version_ = EXPORT_FORMAT_V1;
        }
+      else if (stream->match_bytes(Export::v2_magic, Export::magic_len))
+       {
+         stream->require_bytes(this->location_, Export::v2_magic,
+                               Export::magic_len);
+         this->version_ = EXPORT_FORMAT_V2;
+       }
       else
        {
          go_error_at(this->location_,
@@ -335,7 +342,8 @@ Import::import(Gogo* gogo, const std::st
 
       this->require_c_string("package ");
       std::string package_name = this->read_identifier();
-      this->require_c_string(";\n");
+      this->require_semicolon_if_old_version();
+      this->require_c_string("\n");
 
       std::string pkgpath;
       std::string pkgpath_symbol;
@@ -343,7 +351,8 @@ Import::import(Gogo* gogo, const std::st
        {
          this->advance(7);
          std::string unique_prefix = this->read_identifier();
-         this->require_c_string(";\n");
+         this->require_semicolon_if_old_version();
+         this->require_c_string("\n");
          pkgpath = unique_prefix + '.' + package_name;
          pkgpath_symbol = (Gogo::pkgpath_for_symbol(unique_prefix) + '.'
                            + Gogo::pkgpath_for_symbol(package_name));
@@ -352,10 +361,14 @@ Import::import(Gogo* gogo, const std::st
        {
          this->require_c_string("pkgpath ");
          pkgpath = this->read_identifier();
-         this->require_c_string(";\n");
+         this->require_semicolon_if_old_version();
+         this->require_c_string("\n");
          pkgpath_symbol = Gogo::pkgpath_for_symbol(pkgpath);
        }
 
+      if (stream->saw_error())
+       return NULL;
+
       this->package_ = gogo->add_imported_package(package_name, local_name,
                                                  is_local_name_exported,
                                                  pkgpath, pkgpath_symbol,
@@ -418,7 +431,8 @@ Import::import(Gogo* gogo, const std::st
       // load time.
       this->require_c_string("checksum ");
       stream->advance(Export::checksum_len * 2);
-      this->require_c_string(";\n");
+      this->require_semicolon_if_old_version();
+      this->require_c_string("\n");
     }
 
   return this->package_;
@@ -436,7 +450,8 @@ Import::read_one_package()
   std::string pkgpath = this->read_identifier();
   this->require_c_string(" ");
   std::string pkgpath_symbol = this->read_identifier();
-  this->require_c_string(";\n");
+  this->require_semicolon_if_old_version();
+  this->require_c_string("\n");
 
   Package* p = this->gogo_->register_package(pkgpath, pkgpath_symbol,
                                             Linemap::unknown_location());
@@ -456,7 +471,9 @@ Import::read_one_import()
   Stream* stream = this->stream_;
   while (stream->peek_char() != '"')
     stream->advance(1);
-  this->require_c_string("\";\n");
+  this->require_c_string("\"");
+  this->require_semicolon_if_old_version();
+  this->require_c_string("\n");
 
   Package* p = this->gogo_->register_package(pkgpath, "",
                                             Linemap::unknown_location());
@@ -474,7 +491,7 @@ Import::read_import_init_fns(Gogo* gogo)
   // to read the init_graph section.
   std::map<std::string, unsigned> init_idx;
 
-  while (!this->match_c_string(";"))
+  while (!this->match_c_string("\n") && !this->match_c_string(";"))
     {
       int priority = -1;
 
@@ -499,7 +516,8 @@ Import::read_import_init_fns(Gogo* gogo)
       unsigned idx = init_idx.size();
       init_idx[init_name] = idx;
     }
-  this->require_c_string(";\n");
+  this->require_semicolon_if_old_version();
+  this->require_c_string("\n");
 
   if (this->match_c_string("init_graph"))
     {
@@ -524,7 +542,7 @@ Import::read_import_init_fns(Gogo* gogo)
       //
       // where src + sink are init functions indices.
 
-      while (!this->match_c_string(";"))
+      while (!this->match_c_string("\n") && !this->match_c_string(";"))
        {
          this->require_c_string(" ");
          std::string src_string = this->read_identifier();
@@ -543,7 +561,8 @@ Import::read_import_init_fns(Gogo* gogo)
 
          ii_src->record_precursor_fcn(ii_sink->init_name());
        }
-      this->require_c_string(";\n");
+      this->require_semicolon_if_old_version();
+      this->require_c_string("\n");
     }
 }
 
@@ -967,7 +986,7 @@ Import::read_identifier()
   while (true)
     {
       c = stream->peek_char();
-      if (c == -1 || c == ' ' || c == ';')
+      if (c == -1 || c == ' ' || c == '\n' || c == ';')
        break;
       ret += c;
       stream->advance(1);
Index: gcc/go/gofrontend/import.h
===================================================================
--- gcc/go/gofrontend/import.h  (revision 264813)
+++ gcc/go/gofrontend/import.h  (working copy)
@@ -184,6 +184,15 @@ class Import
   advance(size_t skip)
   { this->stream_->advance(skip); }
 
+  // Skip a semicolon if using an older version.
+  void
+  require_semicolon_if_old_version()
+  {
+    if (this->version_ == EXPORT_FORMAT_V1
+       || this->version_ == EXPORT_FORMAT_V2)
+      this->require_c_string(";");
+  }
+
   // Read an identifier.
   std::string
   read_identifier();
Index: gcc/go/gofrontend/types.cc
===================================================================
--- gcc/go/gofrontend/types.cc  (revision 264813)
+++ gcc/go/gofrontend/types.cc  (working copy)
@@ -10892,7 +10892,7 @@ Named_type::export_named_type(Export* ex
   // be written by Export::write_type anyhow.
   exp->write_c_string("type ");
   exp->write_type(this);
-  exp->write_c_string(";\n");
+  exp->write_c_string("\n");
 }
 
 // Import a named type.
@@ -10904,7 +10904,8 @@ Named_type::import_named_type(Import* im
   Type *type = imp->read_type();
   *ptype = type->named_type();
   go_assert(*ptype != NULL);
-  imp->require_c_string(";\n");
+  imp->require_semicolon_if_old_version();
+  imp->require_c_string("\n");
 }
 
 // Export the type when it is referenced by another type.  In this
Index: libgo/go/go/internal/gccgoimporter/importer.go
===================================================================
--- libgo/go/go/internal/gccgoimporter/importer.go      (revision 264813)
+++ libgo/go/go/internal/gccgoimporter/importer.go      (working copy)
@@ -64,6 +64,7 @@ func findExportFile(searchpaths []string
 const (
        gccgov1Magic    = "v1;\n"
        gccgov2Magic    = "v2;\n"
+       gccgov3Magic    = "v3;\n"
        goimporterMagic = "\n$$ "
        archiveMagic    = "!<ar"
        aixbigafMagic   = "<big"
@@ -93,7 +94,7 @@ func openExportFile(fpath string) (reade
 
        var objreader io.ReaderAt
        switch string(magic[:]) {
-       case gccgov1Magic, gccgov2Magic, goimporterMagic:
+       case gccgov1Magic, gccgov2Magic, gccgov3Magic, goimporterMagic:
                // Raw export data.
                reader = f
                return
@@ -208,7 +209,7 @@ func GetImporter(searchpaths []string, i
                }
 
                switch magics {
-               case gccgov1Magic, gccgov2Magic:
+               case gccgov1Magic, gccgov2Magic, gccgov3Magic:
                        var p parser
                        p.init(fpath, reader, imports)
                        pkg = p.parsePackage()
Index: libgo/go/go/internal/gccgoimporter/parser.go
===================================================================
--- libgo/go/go/internal/gccgoimporter/parser.go        (revision 264813)
+++ libgo/go/go/internal/gccgoimporter/parser.go        (working copy)
@@ -34,7 +34,7 @@ func (p *parser) init(filename string, s
        p.scanner.Init(src)
        p.scanner.Error = func(_ *scanner.Scanner, msg string) { p.error(msg) }
        p.scanner.Mode = scanner.ScanIdents | scanner.ScanInts | 
scanner.ScanFloats | scanner.ScanStrings | scanner.ScanComments | 
scanner.SkipComments
-       p.scanner.Whitespace = 1<<'\t' | 1<<'\n' | 1<<' '
+       p.scanner.Whitespace = 1<<'\t' | 1<<' '
        p.scanner.Filename = filename // for good error messages
        p.next()
        p.imports = imports
@@ -71,6 +71,13 @@ func (p *parser) expect(tok rune) string
        return lit
 }
 
+func (p *parser) expectEOL() {
+       if p.version == "v1" || p.version == "v2" {
+               p.expect(';')
+       }
+       p.expect('\n')
+}
+
 func (p *parser) expectKeyword(keyword string) {
        lit := p.expect(scanner.Ident)
        if lit != keyword {
@@ -96,7 +103,7 @@ func (p *parser) parseUnquotedString() s
        buf.WriteString(p.scanner.TokenText())
        // This loop needs to examine each character before deciding whether to 
consume it. If we see a semicolon,
        // we need to let it be consumed by p.next().
-       for ch := p.scanner.Peek(); ch != ';' && ch != scanner.EOF && 
p.scanner.Whitespace&(1<<uint(ch)) == 0; ch = p.scanner.Peek() {
+       for ch := p.scanner.Peek(); ch != '\n' && ch != ';' && ch != 
scanner.EOF && p.scanner.Whitespace&(1<<uint(ch)) == 0; ch = p.scanner.Peek() {
                buf.WriteRune(ch)
                p.scanner.Next()
        }
@@ -431,19 +438,22 @@ func (p *parser) parseNamedType(n int) t
                nt.SetUnderlying(underlying.Underlying())
        }
 
-       // collect associated methods
-       for p.tok == scanner.Ident {
-               p.expectKeyword("func")
-               p.expect('(')
-               receiver, _ := p.parseParam(pkg)
-               p.expect(')')
-               name := p.parseName()
-               params, isVariadic := p.parseParamList(pkg)
-               results := p.parseResultList(pkg)
-               p.expect(';')
+       if p.tok == '\n' {
+               p.next()
+               // collect associated methods
+               for p.tok == scanner.Ident {
+                       p.expectKeyword("func")
+                       p.expect('(')
+                       receiver, _ := p.parseParam(pkg)
+                       p.expect(')')
+                       name := p.parseName()
+                       params, isVariadic := p.parseParamList(pkg)
+                       results := p.parseResultList(pkg)
+                       p.expectEOL()
 
-               sig := types.NewSignature(receiver, params, results, isVariadic)
-               nt.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig))
+                       sig := types.NewSignature(receiver, params, results, 
isVariadic)
+                       nt.AddMethod(types.NewFunc(token.NoPos, pkg, name, sig))
+               }
        }
 
        return nt
@@ -740,11 +750,12 @@ func (p *parser) parsePackageInit() Pack
        return PackageInit{Name: name, InitFunc: initfunc, Priority: priority}
 }
 
-// Throw away tokens until we see a ';'. If we see a '<', attempt to parse as 
a type.
+// Throw away tokens until we see a newline or ';'.
+// If we see a '<', attempt to parse as a type.
 func (p *parser) discardDirectiveWhileParsingTypes(pkg *types.Package) {
        for {
                switch p.tok {
-               case ';':
+               case '\n', ';':
                        return
                case '<':
                        p.parseType(pkg)
@@ -763,7 +774,7 @@ func (p *parser) maybeCreatePackage() {
        }
 }
 
-// InitDataDirective = ( "v1" | "v2" ) ";" |
+// InitDataDirective = ( "v1" | "v2" | "v3" ) ";" |
 //                     "priority" int ";" |
 //                     "init" { PackageInit } ";" |
 //                     "checksum" unquotedString ";" .
@@ -774,31 +785,32 @@ func (p *parser) parseInitDataDirective(
        }
 
        switch p.lit {
-       case "v1", "v2":
+       case "v1", "v2", "v3":
                p.version = p.lit
                p.next()
                p.expect(';')
+               p.expect('\n')
 
        case "priority":
                p.next()
                p.initdata.Priority = int(p.parseInt())
-               p.expect(';')
+               p.expectEOL()
 
        case "init":
                p.next()
-               for p.tok != ';' && p.tok != scanner.EOF {
+               for p.tok != '\n' && p.tok != ';' && p.tok != scanner.EOF {
                        p.initdata.Inits = append(p.initdata.Inits, 
p.parsePackageInit())
                }
-               p.expect(';')
+               p.expectEOL()
 
        case "init_graph":
                p.next()
                // The graph data is thrown away for now.
-               for p.tok != ';' && p.tok != scanner.EOF {
+               for p.tok != '\n' && p.tok != ';' && p.tok != scanner.EOF {
                        p.parseInt()
                        p.parseInt()
                }
-               p.expect(';')
+               p.expectEOL()
 
        case "checksum":
                // Don't let the scanner try to parse the checksum as a number.
@@ -808,7 +820,7 @@ func (p *parser) parseInitDataDirective(
                p.scanner.Mode &^= scanner.ScanInts | scanner.ScanFloats
                p.next()
                p.parseUnquotedString()
-               p.expect(';')
+               p.expectEOL()
 
        default:
                p.errorf("unexpected identifier: %q", p.lit)
@@ -831,29 +843,29 @@ func (p *parser) parseDirective() {
        }
 
        switch p.lit {
-       case "v1", "v2", "priority", "init", "init_graph", "checksum":
+       case "v1", "v2", "v3", "priority", "init", "init_graph", "checksum":
                p.parseInitDataDirective()
 
        case "package":
                p.next()
                p.pkgname = p.parseUnquotedString()
                p.maybeCreatePackage()
-               if p.version == "v2" && p.tok != ';' {
+               if p.version != "v1" && p.tok != '\n' && p.tok != ';' {
                        p.parseUnquotedString()
                        p.parseUnquotedString()
                }
-               p.expect(';')
+               p.expectEOL()
 
        case "pkgpath":
                p.next()
                p.pkgpath = p.parseUnquotedString()
                p.maybeCreatePackage()
-               p.expect(';')
+               p.expectEOL()
 
        case "prefix":
                p.next()
                p.pkgpath = p.parseUnquotedString()
-               p.expect(';')
+               p.expectEOL()
 
        case "import":
                p.next()
@@ -861,7 +873,7 @@ func (p *parser) parseDirective() {
                pkgpath := p.parseUnquotedString()
                p.getPkg(pkgpath, pkgname)
                p.parseString()
-               p.expect(';')
+               p.expectEOL()
 
        case "func":
                p.next()
@@ -869,24 +881,24 @@ func (p *parser) parseDirective() {
                if fun != nil {
                        p.pkg.Scope().Insert(fun)
                }
-               p.expect(';')
+               p.expectEOL()
 
        case "type":
                p.next()
                p.parseType(p.pkg)
-               p.expect(';')
+               p.expectEOL()
 
        case "var":
                p.next()
                v := p.parseVar(p.pkg)
                p.pkg.Scope().Insert(v)
-               p.expect(';')
+               p.expectEOL()
 
        case "const":
                p.next()
                c := p.parseConst(p.pkg)
                p.pkg.Scope().Insert(c)
-               p.expect(';')
+               p.expectEOL()
 
        default:
                p.errorf("unexpected identifier: %q", p.lit)
Index: libgo/go/go/internal/gccgoimporter/parser_test.go
===================================================================
--- libgo/go/go/internal/gccgoimporter/parser_test.go   (revision 264813)
+++ libgo/go/go/internal/gccgoimporter/parser_test.go   (working copy)
@@ -19,7 +19,7 @@ var typeParserTests = []struct {
        {id: "foo", typ: "<type 1 *<type -19>>", want: "*error"},
        {id: "foo", typ: "<type 1 *any>", want: "unsafe.Pointer"},
        {id: "foo", typ: "<type 1 \"Bar\" <type 2 *<type 1>>>", want: 
"foo.Bar", underlying: "*foo.Bar"},
-       {id: "foo", typ: "<type 1 \"bar.Foo\" \"bar\" <type -1> func (? <type 
1>) M (); >", want: "bar.Foo", underlying: "int8", methods: "func 
(bar.Foo).M()"},
+       {id: "foo", typ: "<type 1 \"bar.Foo\" \"bar\" <type -1>\n func (? <type 
1>) M ()\n>", want: "bar.Foo", underlying: "int8", methods: "func 
(bar.Foo).M()"},
        {id: "foo", typ: "<type 1 \".bar.foo\" \"bar\" <type -1>>", want: 
"bar.foo", underlying: "int8"},
        {id: "foo", typ: "<type 1 []<type -1>>", want: "[]int8"},
        {id: "foo", typ: "<type 1 [42]<type -1>>", want: "[42]int8"},

Reply via email to