aboutsummaryrefslogtreecommitdiff
path: root/src/cmd/compile/internal/noder/import.go
diff options
context:
space:
mode:
authorMatthew Dempsky <mdempsky@google.com>2021-01-24 10:52:00 -0800
committerMatthew Dempsky <mdempsky@google.com>2021-01-25 01:31:37 +0000
commit063c72f06d8673f3a2a03fd549c61935ca3e5cc5 (patch)
tree38600b03f3aa47fa87772e1c7e9c8659fc6a8200 /src/cmd/compile/internal/noder/import.go
parentd05d6fab32cb3d47f8682d19ca11085430f39164 (diff)
downloadgo-063c72f06d8673f3a2a03fd549c61935ca3e5cc5.tar.gz
go-063c72f06d8673f3a2a03fd549c61935ca3e5cc5.zip
[dev.regabi] cmd/compile: backport changes from dev.typeparams (9456804)
This CL backports a bunch of changes that landed on dev.typeparams, but are not dependent on types2 or generics. By backporting, we reduce the divergence between development branches, hopefully improving test coverage and reducing risk of merge conflicts. Updates #43866. Change-Id: I382510855c9b5fac52b17066e44a00bd07fe86f5 Reviewed-on: https://go-review.googlesource.com/c/go/+/286172 Trust: Matthew Dempsky <mdempsky@google.com> Trust: Robert Griesemer <gri@golang.org> Run-TryBot: Matthew Dempsky <mdempsky@google.com> Reviewed-by: Robert Griesemer <gri@golang.org>
Diffstat (limited to 'src/cmd/compile/internal/noder/import.go')
-rw-r--r--src/cmd/compile/internal/noder/import.go239
1 files changed, 114 insertions, 125 deletions
diff --git a/src/cmd/compile/internal/noder/import.go b/src/cmd/compile/internal/noder/import.go
index ca041a156c..747c30e6ff 100644
--- a/src/cmd/compile/internal/noder/import.go
+++ b/src/cmd/compile/internal/noder/import.go
@@ -5,18 +5,20 @@
package noder
import (
+ "errors"
"fmt"
- "go/constant"
"os"
- "path"
+ pathpkg "path"
"runtime"
"sort"
+ "strconv"
"strings"
"unicode"
"unicode/utf8"
"cmd/compile/internal/base"
"cmd/compile/internal/ir"
+ "cmd/compile/internal/syntax"
"cmd/compile/internal/typecheck"
"cmd/compile/internal/types"
"cmd/internal/archive"
@@ -38,160 +40,157 @@ func islocalname(name string) bool {
strings.HasPrefix(name, "../") || name == ".."
}
-func findpkg(name string) (file string, ok bool) {
- if islocalname(name) {
+func openPackage(path string) (*os.File, error) {
+ if islocalname(path) {
if base.Flag.NoLocalImports {
- return "", false
+ return nil, errors.New("local imports disallowed")
}
if base.Flag.Cfg.PackageFile != nil {
- file, ok = base.Flag.Cfg.PackageFile[name]
- return file, ok
+ return os.Open(base.Flag.Cfg.PackageFile[path])
}
- // try .a before .6. important for building libraries:
- // if there is an array.6 in the array.a library,
- // want to find all of array.a, not just array.6.
- file = fmt.Sprintf("%s.a", name)
- if _, err := os.Stat(file); err == nil {
- return file, true
+ // try .a before .o. important for building libraries:
+ // if there is an array.o in the array.a library,
+ // want to find all of array.a, not just array.o.
+ if file, err := os.Open(fmt.Sprintf("%s.a", path)); err == nil {
+ return file, nil
}
- file = fmt.Sprintf("%s.o", name)
- if _, err := os.Stat(file); err == nil {
- return file, true
+ if file, err := os.Open(fmt.Sprintf("%s.o", path)); err == nil {
+ return file, nil
}
- return "", false
+ return nil, errors.New("file not found")
}
// local imports should be canonicalized already.
// don't want to see "encoding/../encoding/base64"
// as different from "encoding/base64".
- if q := path.Clean(name); q != name {
- base.Errorf("non-canonical import path %q (should be %q)", name, q)
- return "", false
+ if q := pathpkg.Clean(path); q != path {
+ return nil, fmt.Errorf("non-canonical import path %q (should be %q)", path, q)
}
if base.Flag.Cfg.PackageFile != nil {
- file, ok = base.Flag.Cfg.PackageFile[name]
- return file, ok
+ return os.Open(base.Flag.Cfg.PackageFile[path])
}
for _, dir := range base.Flag.Cfg.ImportDirs {
- file = fmt.Sprintf("%s/%s.a", dir, name)
- if _, err := os.Stat(file); err == nil {
- return file, true
+ if file, err := os.Open(fmt.Sprintf("%s/%s.a", dir, path)); err == nil {
+ return file, nil
}
- file = fmt.Sprintf("%s/%s.o", dir, name)
- if _, err := os.Stat(file); err == nil {
- return file, true
+ if file, err := os.Open(fmt.Sprintf("%s/%s.o", dir, path)); err == nil {
+ return file, nil
}
}
if objabi.GOROOT != "" {
suffix := ""
- suffixsep := ""
if base.Flag.InstallSuffix != "" {
- suffixsep = "_"
- suffix = base.Flag.InstallSuffix
+ suffix = "_" + base.Flag.InstallSuffix
} else if base.Flag.Race {
- suffixsep = "_"
- suffix = "race"
+ suffix = "_race"
} else if base.Flag.MSan {
- suffixsep = "_"
- suffix = "msan"
+ suffix = "_msan"
}
- file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
- if _, err := os.Stat(file); err == nil {
- return file, true
+ if file, err := os.Open(fmt.Sprintf("%s/pkg/%s_%s%s/%s.a", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffix, path)); err == nil {
+ return file, nil
}
- file = fmt.Sprintf("%s/pkg/%s_%s%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffixsep, suffix, name)
- if _, err := os.Stat(file); err == nil {
- return file, true
+ if file, err := os.Open(fmt.Sprintf("%s/pkg/%s_%s%s/%s.o", objabi.GOROOT, objabi.GOOS, objabi.GOARCH, suffix, path)); err == nil {
+ return file, nil
}
}
-
- return "", false
+ return nil, errors.New("file not found")
}
// myheight tracks the local package's height based on packages
// imported so far.
var myheight int
-func importfile(f constant.Value) *types.Pkg {
- if f.Kind() != constant.String {
- base.Errorf("import path must be a string")
- return nil
- }
-
- path_ := constant.StringVal(f)
- if len(path_) == 0 {
- base.Errorf("import path is empty")
- return nil
- }
-
- if isbadimport(path_, false) {
- return nil
- }
-
+// resolveImportPath resolves an import path as it appears in a Go
+// source file to the package's full path.
+func resolveImportPath(path string) (string, error) {
// The package name main is no longer reserved,
// but we reserve the import path "main" to identify
// the main package, just as we reserve the import
// path "math" to identify the standard math package.
- if path_ == "main" {
- base.Errorf("cannot import \"main\"")
- base.ErrorExit()
- }
-
- if base.Ctxt.Pkgpath != "" && path_ == base.Ctxt.Pkgpath {
- base.Errorf("import %q while compiling that package (import cycle)", path_)
- base.ErrorExit()
+ if path == "main" {
+ return "", errors.New("cannot import \"main\"")
}
- if mapped, ok := base.Flag.Cfg.ImportMap[path_]; ok {
- path_ = mapped
+ if base.Ctxt.Pkgpath != "" && path == base.Ctxt.Pkgpath {
+ return "", fmt.Errorf("import %q while compiling that package (import cycle)", path)
}
- if path_ == "unsafe" {
- return ir.Pkgs.Unsafe
+ if mapped, ok := base.Flag.Cfg.ImportMap[path]; ok {
+ path = mapped
}
- if islocalname(path_) {
- if path_[0] == '/' {
- base.Errorf("import path cannot be absolute path")
- return nil
+ if islocalname(path) {
+ if path[0] == '/' {
+ return "", errors.New("import path cannot be absolute path")
}
- prefix := base.Ctxt.Pathname
- if base.Flag.D != "" {
- prefix = base.Flag.D
+ prefix := base.Flag.D
+ if prefix == "" {
+ // Questionable, but when -D isn't specified, historically we
+ // resolve local import paths relative to the directory the
+ // compiler's current directory, not the respective source
+ // file's directory.
+ prefix = base.Ctxt.Pathname
}
- path_ = path.Join(prefix, path_)
+ path = pathpkg.Join(prefix, path)
- if isbadimport(path_, true) {
- return nil
+ if err := checkImportPath(path, true); err != nil {
+ return "", err
}
}
- file, found := findpkg(path_)
- if !found {
- base.Errorf("can't find import: %q", path_)
- base.ErrorExit()
+ return path, nil
+}
+
+// TODO(mdempsky): Return an error instead.
+func importfile(decl *syntax.ImportDecl) *types.Pkg {
+ if decl.Path.Kind != syntax.StringLit {
+ base.Errorf("import path must be a string")
+ return nil
}
- importpkg := types.NewPkg(path_, "")
- if importpkg.Imported {
- return importpkg
+ path, err := strconv.Unquote(decl.Path.Value)
+ if err != nil {
+ base.Errorf("import path must be a string")
+ return nil
+ }
+
+ if err := checkImportPath(path, false); err != nil {
+ base.Errorf("%s", err.Error())
+ return nil
}
- importpkg.Imported = true
+ path, err = resolveImportPath(path)
+ if err != nil {
+ base.Errorf("%s", err)
+ return nil
+ }
+
+ importpkg := types.NewPkg(path, "")
+ if importpkg.Direct {
+ return importpkg // already fully loaded
+ }
+ importpkg.Direct = true
+ typecheck.Target.Imports = append(typecheck.Target.Imports, importpkg)
+
+ if path == "unsafe" {
+ return importpkg // initialized with universe
+ }
- imp, err := bio.Open(file)
+ f, err := openPackage(path)
if err != nil {
- base.Errorf("can't open import: %q: %v", path_, err)
+ base.Errorf("could not import %q: %v", path, err)
base.ErrorExit()
}
+ imp := bio.NewReader(f)
defer imp.Close()
+ file := f.Name()
// check object header
p, err := imp.ReadString('\n')
@@ -261,12 +260,12 @@ func importfile(f constant.Value) *types.Pkg {
var fingerprint goobj.FingerprintType
switch c {
case '\n':
- base.Errorf("cannot import %s: old export format no longer supported (recompile library)", path_)
+ base.Errorf("cannot import %s: old export format no longer supported (recompile library)", path)
return nil
case 'B':
if base.Debug.Export != 0 {
- fmt.Printf("importing %s (%s)\n", path_, file)
+ fmt.Printf("importing %s (%s)\n", path, file)
}
imp.ReadByte() // skip \n after $$B
@@ -285,17 +284,17 @@ func importfile(f constant.Value) *types.Pkg {
fingerprint = typecheck.ReadImports(importpkg, imp)
default:
- base.Errorf("no import in %q", path_)
+ base.Errorf("no import in %q", path)
base.ErrorExit()
}
// assume files move (get installed) so don't record the full path
if base.Flag.Cfg.PackageFile != nil {
// If using a packageFile map, assume path_ can be recorded directly.
- base.Ctxt.AddImport(path_, fingerprint)
+ base.Ctxt.AddImport(path, fingerprint)
} else {
// For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a".
- base.Ctxt.AddImport(file[len(file)-len(path_)-len(".a"):], fingerprint)
+ base.Ctxt.AddImport(file[len(file)-len(path)-len(".a"):], fingerprint)
}
if importpkg.Height >= myheight {
@@ -315,47 +314,37 @@ var reservedimports = []string{
"type",
}
-func isbadimport(path string, allowSpace bool) bool {
+func checkImportPath(path string, allowSpace bool) error {
+ if path == "" {
+ return errors.New("import path is empty")
+ }
+
if strings.Contains(path, "\x00") {
- base.Errorf("import path contains NUL")
- return true
+ return errors.New("import path contains NUL")
}
for _, ri := range reservedimports {
if path == ri {
- base.Errorf("import path %q is reserved and cannot be used", path)
- return true
+ return fmt.Errorf("import path %q is reserved and cannot be used", path)
}
}
for _, r := range path {
- if r == utf8.RuneError {
- base.Errorf("import path contains invalid UTF-8 sequence: %q", path)
- return true
- }
-
- if r < 0x20 || r == 0x7f {
- base.Errorf("import path contains control character: %q", path)
- return true
- }
-
- if r == '\\' {
- base.Errorf("import path contains backslash; use slash: %q", path)
- return true
- }
-
- if !allowSpace && unicode.IsSpace(r) {
- base.Errorf("import path contains space character: %q", path)
- return true
- }
-
- if strings.ContainsRune("!\"#$%&'()*,:;<=>?[]^`{|}", r) {
- base.Errorf("import path contains invalid character '%c': %q", r, path)
- return true
+ switch {
+ case r == utf8.RuneError:
+ return fmt.Errorf("import path contains invalid UTF-8 sequence: %q", path)
+ case r < 0x20 || r == 0x7f:
+ return fmt.Errorf("import path contains control character: %q", path)
+ case r == '\\':
+ return fmt.Errorf("import path contains backslash; use slash: %q", path)
+ case !allowSpace && unicode.IsSpace(r):
+ return fmt.Errorf("import path contains space character: %q", path)
+ case strings.ContainsRune("!\"#$%&'()*,:;<=>?[]^`{|}", r):
+ return fmt.Errorf("import path contains invalid character '%c': %q", r, path)
}
}
- return false
+ return nil
}
func pkgnotused(lineno src.XPos, path string, name string) {