libgo: update to Go 1.12.1
Reviewed-on: https://go-review.googlesource.com/c/gofrontend/+/167749 From-SVN: r269780
This commit is contained in:
parent
891cd9e3b9
commit
a8b58d84bf
23 changed files with 398 additions and 138 deletions
|
@ -1,4 +1,4 @@
|
|||
cc70be24502faeffefb66fd0abeb7f20a6c7792a
|
||||
87945b620b2100d33e27f33e6276a4e4e5890659
|
||||
|
||||
The first line of this file holds the git revision number of the last
|
||||
merge done from the gofrontend repository.
|
||||
|
|
|
@ -1,4 +1,4 @@
|
|||
05e77d41914d247a1e7caf37d7125ccaa5a53505
|
||||
0380c9ad38843d523d9c9804fe300cb7edd7cd3c
|
||||
|
||||
The first line of this file holds the git revision number of the
|
||||
last merge done from the master library sources.
|
||||
|
|
|
@ -1 +1 @@
|
|||
go1.12
|
||||
go1.12.1
|
||||
|
|
|
@ -200,18 +200,6 @@ func (f *File) saveExprs(x interface{}, context astContext) {
|
|||
}
|
||||
case *ast.CallExpr:
|
||||
f.saveCall(x, context)
|
||||
case *ast.GenDecl:
|
||||
if x.Tok == token.CONST {
|
||||
for _, spec := range x.Specs {
|
||||
vs := spec.(*ast.ValueSpec)
|
||||
if vs.Type == nil {
|
||||
for _, name := range spec.(*ast.ValueSpec).Names {
|
||||
consts[name.Name] = true
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -915,21 +915,16 @@ func (p *Package) rewriteCall(f *File, call *Call) (string, bool) {
|
|||
needsUnsafe = true
|
||||
}
|
||||
|
||||
// Explicitly convert untyped constants to the
|
||||
// parameter type, to avoid a type mismatch.
|
||||
if p.isConst(f, arg) {
|
||||
ptype := p.rewriteUnsafe(param.Go)
|
||||
// Use "var x T = ..." syntax to explicitly convert untyped
|
||||
// constants to the parameter type, to avoid a type mismatch.
|
||||
ptype := p.rewriteUnsafe(param.Go)
|
||||
|
||||
if !p.needsPointerCheck(f, param.Go, args[i]) || param.BadPointer {
|
||||
if ptype != param.Go {
|
||||
needsUnsafe = true
|
||||
}
|
||||
arg = &ast.CallExpr{
|
||||
Fun: ptype,
|
||||
Args: []ast.Expr{arg},
|
||||
}
|
||||
}
|
||||
|
||||
if !p.needsPointerCheck(f, param.Go, args[i]) {
|
||||
fmt.Fprintf(&sb, "_cgo%d := %s; ", i, gofmtPos(arg, origArg.Pos()))
|
||||
fmt.Fprintf(&sb, "var _cgo%d %s = %s; ", i,
|
||||
gofmtLine(ptype), gofmtPos(arg, origArg.Pos()))
|
||||
continue
|
||||
}
|
||||
|
||||
|
@ -1272,47 +1267,6 @@ func (p *Package) isType(t ast.Expr) bool {
|
|||
return false
|
||||
}
|
||||
|
||||
// isConst reports whether x is an untyped constant expression.
|
||||
func (p *Package) isConst(f *File, x ast.Expr) bool {
|
||||
switch x := x.(type) {
|
||||
case *ast.BasicLit:
|
||||
return true
|
||||
case *ast.SelectorExpr:
|
||||
id, ok := x.X.(*ast.Ident)
|
||||
if !ok || id.Name != "C" {
|
||||
return false
|
||||
}
|
||||
name := f.Name[x.Sel.Name]
|
||||
if name != nil {
|
||||
return name.IsConst()
|
||||
}
|
||||
case *ast.Ident:
|
||||
return x.Name == "nil" ||
|
||||
strings.HasPrefix(x.Name, "_Ciconst_") ||
|
||||
strings.HasPrefix(x.Name, "_Cfconst_") ||
|
||||
strings.HasPrefix(x.Name, "_Csconst_") ||
|
||||
consts[x.Name]
|
||||
case *ast.UnaryExpr:
|
||||
return p.isConst(f, x.X)
|
||||
case *ast.BinaryExpr:
|
||||
return p.isConst(f, x.X) && p.isConst(f, x.Y)
|
||||
case *ast.ParenExpr:
|
||||
return p.isConst(f, x.X)
|
||||
case *ast.CallExpr:
|
||||
// Calling the builtin function complex on two untyped
|
||||
// constants returns an untyped constant.
|
||||
// TODO: It's possible to construct a case that will
|
||||
// erroneously succeed if there is a local function
|
||||
// named "complex", shadowing the builtin, that returns
|
||||
// a numeric type. I can't think of any cases that will
|
||||
// erroneously fail.
|
||||
if id, ok := x.Fun.(*ast.Ident); ok && id.Name == "complex" && len(x.Args) == 2 {
|
||||
return p.isConst(f, x.Args[0]) && p.isConst(f, x.Args[1])
|
||||
}
|
||||
}
|
||||
return false
|
||||
}
|
||||
|
||||
// isVariable reports whether x is a variable, possibly with field references.
|
||||
func (p *Package) isVariable(x ast.Expr) bool {
|
||||
switch x := x.(type) {
|
||||
|
@ -2533,13 +2487,16 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
// Treat this typedef as a uintptr.
|
||||
s := *sub
|
||||
s.Go = c.uintptr
|
||||
s.BadPointer = true
|
||||
sub = &s
|
||||
// Make sure we update any previously computed type.
|
||||
if oldType := typedef[name.Name]; oldType != nil {
|
||||
oldType.Go = sub.Go
|
||||
oldType.BadPointer = true
|
||||
}
|
||||
}
|
||||
t.Go = name
|
||||
t.BadPointer = sub.BadPointer
|
||||
if unionWithPointer[sub.Go] {
|
||||
unionWithPointer[t.Go] = true
|
||||
}
|
||||
|
@ -2549,6 +2506,7 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||
if oldType == nil {
|
||||
tt := *t
|
||||
tt.Go = sub.Go
|
||||
tt.BadPointer = sub.BadPointer
|
||||
typedef[name.Name] = &tt
|
||||
}
|
||||
|
||||
|
|
|
@ -71,9 +71,6 @@ type File struct {
|
|||
Edit *edit.Buffer
|
||||
}
|
||||
|
||||
// Untyped constants in the current package.
|
||||
var consts = make(map[string]bool)
|
||||
|
||||
func (f *File) offset(p token.Pos) int {
|
||||
return fset.Position(p).Offset
|
||||
}
|
||||
|
@ -154,6 +151,7 @@ type Type struct {
|
|||
Go ast.Expr
|
||||
EnumValues map[string]int64
|
||||
Typedef string
|
||||
BadPointer bool
|
||||
}
|
||||
|
||||
// A FuncType collects information about a function type in both the C and Go worlds.
|
||||
|
|
7
libgo/go/cmd/go/internal/cache/default.go
vendored
7
libgo/go/cmd/go/internal/cache/default.go
vendored
|
@ -37,7 +37,7 @@ See golang.org to learn more about Go.
|
|||
// the first time Default is called.
|
||||
func initDefaultCache() {
|
||||
dir := DefaultDir()
|
||||
if dir == "off" || dir == "" {
|
||||
if dir == "off" {
|
||||
if defaultDirErr != nil {
|
||||
base.Fatalf("build cache is required, but could not be located: %v", defaultDirErr)
|
||||
}
|
||||
|
@ -74,7 +74,12 @@ func DefaultDir() string {
|
|||
|
||||
defaultDirOnce.Do(func() {
|
||||
defaultDir = os.Getenv("GOCACHE")
|
||||
if filepath.IsAbs(defaultDir) || defaultDir == "off" {
|
||||
return
|
||||
}
|
||||
if defaultDir != "" {
|
||||
defaultDir = "off"
|
||||
defaultDirErr = fmt.Errorf("GOCACHE is not an absolute path")
|
||||
return
|
||||
}
|
||||
|
||||
|
|
|
@ -129,6 +129,7 @@ func GetTestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Pac
|
|||
ptest.Internal.Imports = append(imports, p.Internal.Imports...)
|
||||
ptest.Internal.RawImports = str.StringList(rawTestImports, p.Internal.RawImports)
|
||||
ptest.Internal.ForceLibrary = true
|
||||
ptest.Internal.BuildInfo = ""
|
||||
ptest.Internal.Build = new(build.Package)
|
||||
*ptest.Internal.Build = *p.Internal.Build
|
||||
m := map[string][]token.Position{}
|
||||
|
@ -186,6 +187,7 @@ func GetTestPackagesFor(p *Package, cover *TestCover) (pmain, ptest, pxtest *Pac
|
|||
},
|
||||
Internal: PackageInternal{
|
||||
Build: &build.Package{Name: "main"},
|
||||
BuildInfo: p.Internal.BuildInfo,
|
||||
Asmflags: p.Internal.Asmflags,
|
||||
Gcflags: p.Internal.Gcflags,
|
||||
Ldflags: p.Internal.Ldflags,
|
||||
|
@ -352,6 +354,7 @@ func recompileForTest(pmain, preal, ptest, pxtest *Package) {
|
|||
copy(p1.Imports, p.Imports)
|
||||
p = p1
|
||||
p.Target = ""
|
||||
p.Internal.BuildInfo = ""
|
||||
}
|
||||
|
||||
// Update p.Internal.Imports to use test copies.
|
||||
|
@ -361,6 +364,13 @@ func recompileForTest(pmain, preal, ptest, pxtest *Package) {
|
|||
p.Internal.Imports[i] = p1
|
||||
}
|
||||
}
|
||||
|
||||
// Don't compile build info from a main package. This can happen
|
||||
// if -coverpkg patterns include main packages, since those packages
|
||||
// are imported by pmain.
|
||||
if p.Internal.BuildInfo != "" && p != pmain {
|
||||
split()
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
|
|
|
@ -23,55 +23,99 @@ import (
|
|||
type codeRepo struct {
|
||||
modPath string
|
||||
|
||||
code codehost.Repo
|
||||
// code is the repository containing this module.
|
||||
code codehost.Repo
|
||||
// codeRoot is the import path at the root of code.
|
||||
codeRoot string
|
||||
codeDir string
|
||||
// codeDir is the directory (relative to root) at which we expect to find the module.
|
||||
// If pathMajor is non-empty and codeRoot is not the full modPath,
|
||||
// then we look in both codeDir and codeDir+modPath
|
||||
codeDir string
|
||||
|
||||
path string
|
||||
pathPrefix string
|
||||
pathMajor string
|
||||
// pathMajor is the suffix of modPath that indicates its major version,
|
||||
// or the empty string if modPath is at major version 0 or 1.
|
||||
//
|
||||
// pathMajor is typically of the form "/vN", but possibly ".vN", or
|
||||
// ".vN-unstable" for modules resolved using gopkg.in.
|
||||
pathMajor string
|
||||
// pathPrefix is the prefix of modPath that excludes pathMajor.
|
||||
// It is used only for logging.
|
||||
pathPrefix string
|
||||
|
||||
// pseudoMajor is the major version prefix to use when generating
|
||||
// pseudo-versions for this module, derived from the module path.
|
||||
//
|
||||
// TODO(golang.org/issue/29262): We can't distinguish v0 from v1 using the
|
||||
// path alone: we have to compute it by examining the tags at a particular
|
||||
// revision.
|
||||
pseudoMajor string
|
||||
}
|
||||
|
||||
func newCodeRepo(code codehost.Repo, root, path string) (Repo, error) {
|
||||
if !hasPathPrefix(path, root) {
|
||||
return nil, fmt.Errorf("mismatched repo: found %s for %s", root, path)
|
||||
// newCodeRepo returns a Repo that reads the source code for the module with the
|
||||
// given path, from the repo stored in code, with the root of the repo
|
||||
// containing the path given by codeRoot.
|
||||
func newCodeRepo(code codehost.Repo, codeRoot, path string) (Repo, error) {
|
||||
if !hasPathPrefix(path, codeRoot) {
|
||||
return nil, fmt.Errorf("mismatched repo: found %s for %s", codeRoot, path)
|
||||
}
|
||||
pathPrefix, pathMajor, ok := module.SplitPathVersion(path)
|
||||
if !ok {
|
||||
return nil, fmt.Errorf("invalid module path %q", path)
|
||||
}
|
||||
if codeRoot == path {
|
||||
pathPrefix = path
|
||||
}
|
||||
pseudoMajor := "v0"
|
||||
if pathMajor != "" {
|
||||
pseudoMajor = pathMajor[1:]
|
||||
}
|
||||
|
||||
// Compute codeDir = bar, the subdirectory within the repo
|
||||
// corresponding to the module root.
|
||||
//
|
||||
// At this point we might have:
|
||||
// codeRoot = github.com/rsc/foo
|
||||
// path = github.com/rsc/foo/bar/v2
|
||||
// codeRoot = github.com/rsc/foo
|
||||
// pathPrefix = github.com/rsc/foo/bar
|
||||
// pathMajor = /v2
|
||||
// pseudoMajor = v2
|
||||
//
|
||||
// Compute codeDir = bar, the subdirectory within the repo
|
||||
// corresponding to the module root.
|
||||
codeDir := strings.Trim(strings.TrimPrefix(pathPrefix, root), "/")
|
||||
if strings.HasPrefix(path, "gopkg.in/") {
|
||||
// But gopkg.in is a special legacy case, in which pathPrefix does not start with codeRoot.
|
||||
// For example we might have:
|
||||
// codeRoot = gopkg.in/yaml.v2
|
||||
// pathPrefix = gopkg.in/yaml
|
||||
// pathMajor = .v2
|
||||
// pseudoMajor = v2
|
||||
// codeDir = pathPrefix (because codeRoot is not a prefix of pathPrefix)
|
||||
// Clear codeDir - the module root is the repo root for gopkg.in repos.
|
||||
codeDir = ""
|
||||
// which gives
|
||||
// codeDir = bar
|
||||
//
|
||||
// We know that pathPrefix is a prefix of path, and codeRoot is a prefix of
|
||||
// path, but codeRoot may or may not be a prefix of pathPrefix, because
|
||||
// codeRoot may be the entire path (in which case codeDir should be empty).
|
||||
// That occurs in two situations.
|
||||
//
|
||||
// One is when a go-import meta tag resolves the complete module path,
|
||||
// including the pathMajor suffix:
|
||||
// path = nanomsg.org/go/mangos/v2
|
||||
// codeRoot = nanomsg.org/go/mangos/v2
|
||||
// pathPrefix = nanomsg.org/go/mangos
|
||||
// pathMajor = /v2
|
||||
// pseudoMajor = v2
|
||||
//
|
||||
// The other is similar: for gopkg.in only, the major version is encoded
|
||||
// with a dot rather than a slash, and thus can't be in a subdirectory.
|
||||
// path = gopkg.in/yaml.v2
|
||||
// codeRoot = gopkg.in/yaml.v2
|
||||
// pathPrefix = gopkg.in/yaml
|
||||
// pathMajor = .v2
|
||||
// pseudoMajor = v2
|
||||
//
|
||||
codeDir := ""
|
||||
if codeRoot != path {
|
||||
if !hasPathPrefix(pathPrefix, codeRoot) {
|
||||
return nil, fmt.Errorf("repository rooted at %s cannot contain module %s", codeRoot, path)
|
||||
}
|
||||
codeDir = strings.Trim(pathPrefix[len(codeRoot):], "/")
|
||||
}
|
||||
|
||||
r := &codeRepo{
|
||||
modPath: path,
|
||||
code: code,
|
||||
codeRoot: root,
|
||||
codeRoot: codeRoot,
|
||||
codeDir: codeDir,
|
||||
pathPrefix: pathPrefix,
|
||||
pathMajor: pathMajor,
|
||||
|
@ -149,9 +193,6 @@ func (r *codeRepo) Stat(rev string) (*RevInfo, error) {
|
|||
return r.Latest()
|
||||
}
|
||||
codeRev := r.revToRev(rev)
|
||||
if semver.IsValid(codeRev) && r.codeDir != "" {
|
||||
codeRev = r.codeDir + "/" + codeRev
|
||||
}
|
||||
info, err := r.code.Stat(codeRev)
|
||||
if err != nil {
|
||||
return nil, err
|
||||
|
@ -290,7 +331,7 @@ func (r *codeRepo) findDir(version string) (rev, dir string, gomod []byte, err e
|
|||
found1 := err1 == nil && isMajor(mpath1, r.pathMajor)
|
||||
|
||||
var file2 string
|
||||
if r.pathMajor != "" && !strings.HasPrefix(r.pathMajor, ".") {
|
||||
if r.pathMajor != "" && r.codeRoot != r.modPath && !strings.HasPrefix(r.pathMajor, ".") {
|
||||
// Suppose pathMajor is "/v2".
|
||||
// Either go.mod should claim v2 and v2/go.mod should not exist,
|
||||
// or v2/go.mod should exist and claim v2. Not both.
|
||||
|
@ -298,6 +339,9 @@ func (r *codeRepo) findDir(version string) (rev, dir string, gomod []byte, err e
|
|||
// because of replacement modules. This might be a fork of
|
||||
// the real module, found at a different path, usable only in
|
||||
// a replace directive.
|
||||
//
|
||||
// TODO(bcmills): This doesn't seem right. Investigate futher.
|
||||
// (Notably: why can't we replace foo/v2 with fork-of-foo/v3?)
|
||||
dir2 := path.Join(r.codeDir, r.pathMajor[1:])
|
||||
file2 = path.Join(dir2, "go.mod")
|
||||
gomod2, err2 := r.code.ReadFile(rev, file2, codehost.MaxGoMod)
|
||||
|
@ -418,7 +462,7 @@ func (r *codeRepo) Zip(dst io.Writer, version string) error {
|
|||
}
|
||||
defer dl.Close()
|
||||
if actualDir != "" && !hasPathPrefix(dir, actualDir) {
|
||||
return fmt.Errorf("internal error: downloading %v %v: dir=%q but actualDir=%q", r.path, rev, dir, actualDir)
|
||||
return fmt.Errorf("internal error: downloading %v %v: dir=%q but actualDir=%q", r.modPath, rev, dir, actualDir)
|
||||
}
|
||||
subdir := strings.Trim(strings.TrimPrefix(dir, actualDir), "/")
|
||||
|
||||
|
|
|
@ -323,6 +323,15 @@ var codeRepoTests = []struct {
|
|||
time: time.Date(2017, 5, 31, 16, 3, 50, 0, time.UTC),
|
||||
gomod: "module gopkg.in/natefinch/lumberjack.v2\n",
|
||||
},
|
||||
{
|
||||
path: "nanomsg.org/go/mangos/v2",
|
||||
rev: "v2.0.2",
|
||||
version: "v2.0.2",
|
||||
name: "63f66a65137b9a648ac9f7bf0160b4a4d17d7999",
|
||||
short: "63f66a65137b",
|
||||
time: time.Date(2018, 12, 1, 15, 7, 40, 0, time.UTC),
|
||||
gomod: "module nanomsg.org/go/mangos/v2\n\nrequire (\n\tgithub.com/Microsoft/go-winio v0.4.11\n\tgithub.com/droundy/goopt v0.0.0-20170604162106-0b8effe182da\n\tgithub.com/gopherjs/gopherjs v0.0.0-20181103185306-d547d1d9531e // indirect\n\tgithub.com/gorilla/websocket v1.4.0\n\tgithub.com/jtolds/gls v4.2.1+incompatible // indirect\n\tgithub.com/smartystreets/assertions v0.0.0-20180927180507-b2de0cb4f26d // indirect\n\tgithub.com/smartystreets/goconvey v0.0.0-20181108003508-044398e4856c\n\tgolang.org/x/sys v0.0.0-20181128092732-4ed8d59d0b35 // indirect\n)\n",
|
||||
},
|
||||
}
|
||||
|
||||
func TestCodeRepo(t *testing.T) {
|
||||
|
|
|
@ -167,7 +167,7 @@ func compare(aVal, bVal reflect.Value) int {
|
|||
if c, ok := nilCompare(aVal, bVal); ok {
|
||||
return c
|
||||
}
|
||||
c := compare(reflect.ValueOf(aType), reflect.ValueOf(bType))
|
||||
c := compare(reflect.ValueOf(aVal.Elem().Type()), reflect.ValueOf(bVal.Elem().Type()))
|
||||
if c != 0 {
|
||||
return c
|
||||
}
|
||||
|
|
|
@ -126,10 +126,6 @@ var sortTests = []sortTest{
|
|||
map[[2]int]string{{7, 2}: "72", {7, 1}: "71", {3, 4}: "34"},
|
||||
"[3 4]:34 [7 1]:71 [7 2]:72",
|
||||
},
|
||||
{
|
||||
map[interface{}]string{7: "7", 4: "4", 3: "3", nil: "nil"},
|
||||
"<nil>:nil 3:3 4:4 7:7",
|
||||
},
|
||||
}
|
||||
|
||||
func sprint(data interface{}) string {
|
||||
|
@ -210,3 +206,41 @@ func TestOrder(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestInterface(t *testing.T) {
|
||||
// A map containing multiple concrete types should be sorted by type,
|
||||
// then value. However, the relative ordering of types is unspecified,
|
||||
// so test this by checking the presence of sorted subgroups.
|
||||
m := map[interface{}]string{
|
||||
[2]int{1, 0}: "",
|
||||
[2]int{0, 1}: "",
|
||||
true: "",
|
||||
false: "",
|
||||
3.1: "",
|
||||
2.1: "",
|
||||
1.1: "",
|
||||
math.NaN(): "",
|
||||
3: "",
|
||||
2: "",
|
||||
1: "",
|
||||
"c": "",
|
||||
"b": "",
|
||||
"a": "",
|
||||
struct{ x, y int }{1, 0}: "",
|
||||
struct{ x, y int }{0, 1}: "",
|
||||
}
|
||||
got := sprint(m)
|
||||
typeGroups := []string{
|
||||
"NaN: 1.1: 2.1: 3.1:", // float64
|
||||
"false: true:", // bool
|
||||
"1: 2: 3:", // int
|
||||
"a: b: c:", // string
|
||||
"[0 1]: [1 0]:", // [2]int
|
||||
"{0 1}: {1 0}:", // struct{ x int; y int }
|
||||
}
|
||||
for _, g := range typeGroups {
|
||||
if !strings.Contains(got, g) {
|
||||
t.Errorf("sorted map should contain %q", g)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
|
|
@ -92,7 +92,8 @@ func removeAllFrom(parent *File, path string) error {
|
|||
if IsNotExist(err) {
|
||||
return nil
|
||||
}
|
||||
return err
|
||||
recurseErr = err
|
||||
break
|
||||
}
|
||||
|
||||
names, readErr := file.Readdirnames(request)
|
||||
|
|
|
@ -372,3 +372,33 @@ func TestRemoveAllButReadOnly(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
func TestRemoveUnreadableDir(t *testing.T) {
|
||||
switch runtime.GOOS {
|
||||
case "nacl", "js", "windows":
|
||||
t.Skipf("skipping test on %s", runtime.GOOS)
|
||||
}
|
||||
|
||||
if Getuid() == 0 {
|
||||
t.Skip("skipping test when running as root")
|
||||
}
|
||||
|
||||
t.Parallel()
|
||||
|
||||
tempDir, err := ioutil.TempDir("", "TestRemoveAllButReadOnly-")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer RemoveAll(tempDir)
|
||||
|
||||
target := filepath.Join(tempDir, "d0", "d1", "d2")
|
||||
if err := MkdirAll(target, 0755); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := Chmod(target, 0300); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := RemoveAll(filepath.Join(tempDir, "d0")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -96,19 +96,14 @@ func Clean(path string) string {
|
|||
}
|
||||
return originalPath + "."
|
||||
}
|
||||
|
||||
n := len(path)
|
||||
if volLen > 2 && n == 1 && os.IsPathSeparator(path[0]) {
|
||||
// UNC volume name with trailing slash.
|
||||
return FromSlash(originalPath[:volLen])
|
||||
}
|
||||
rooted := os.IsPathSeparator(path[0])
|
||||
|
||||
// Invariants:
|
||||
// reading from path; r is index of next byte to process.
|
||||
// writing to out; w is index of next byte to write.
|
||||
// dotdot is index in out where .. must stop, either because
|
||||
// writing to buf; w is index of next byte to write.
|
||||
// dotdot is index in buf where .. must stop, either because
|
||||
// it is the leading slash or it is a leading ../../.. prefix.
|
||||
n := len(path)
|
||||
out := lazybuf{path: path, volAndPath: originalPath, volLen: volLen}
|
||||
r, dotdot := 0, 0
|
||||
if rooted {
|
||||
|
|
|
@ -93,9 +93,6 @@ var wincleantests = []PathTest{
|
|||
{`//host/share/foo/../baz`, `\\host\share\baz`},
|
||||
{`\\a\b\..\c`, `\\a\b\c`},
|
||||
{`\\a\b`, `\\a\b`},
|
||||
{`\\a\b\`, `\\a\b`},
|
||||
{`\\folder\share\foo`, `\\folder\share\foo`},
|
||||
{`\\folder\share\foo\`, `\\folder\share\foo`},
|
||||
}
|
||||
|
||||
func TestClean(t *testing.T) {
|
||||
|
@ -1417,3 +1414,103 @@ func TestIssue29372(t *testing.T) {
|
|||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 30520 part 1.
|
||||
func TestEvalSymlinksAboveRoot(t *testing.T) {
|
||||
testenv.MustHaveSymlink(t)
|
||||
|
||||
t.Parallel()
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "TestEvalSymlinksAboveRoot")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
evalTmpDir, err := filepath.EvalSymlinks(tmpDir)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
if err := os.Mkdir(filepath.Join(evalTmpDir, "a"), 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Symlink(filepath.Join(evalTmpDir, "a"), filepath.Join(evalTmpDir, "b")); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(evalTmpDir, "a", "file"), nil, 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
// Count the number of ".." elements to get to the root directory.
|
||||
vol := filepath.VolumeName(evalTmpDir)
|
||||
c := strings.Count(evalTmpDir[len(vol):], string(os.PathSeparator))
|
||||
var dd []string
|
||||
for i := 0; i < c+2; i++ {
|
||||
dd = append(dd, "..")
|
||||
}
|
||||
|
||||
wantSuffix := strings.Join([]string{"a", "file"}, string(os.PathSeparator))
|
||||
|
||||
// Try different numbers of "..".
|
||||
for _, i := range []int{c, c + 1, c + 2} {
|
||||
check := strings.Join([]string{evalTmpDir, strings.Join(dd[:i], string(os.PathSeparator)), evalTmpDir[len(vol)+1:], "b", "file"}, string(os.PathSeparator))
|
||||
if resolved, err := filepath.EvalSymlinks(check); err != nil {
|
||||
t.Errorf("EvalSymlinks(%q) failed: %v", check, err)
|
||||
} else if !strings.HasSuffix(resolved, wantSuffix) {
|
||||
t.Errorf("EvalSymlinks(%q) = %q does not end with %q", check, resolved, wantSuffix)
|
||||
} else {
|
||||
t.Logf("EvalSymlinks(%q) = %q", check, resolved)
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
// Issue 30520 part 2.
|
||||
func TestEvalSymlinksAboveRootChdir(t *testing.T) {
|
||||
testenv.MustHaveSymlink(t)
|
||||
|
||||
tmpDir, err := ioutil.TempDir("", "TestEvalSymlinksAboveRootChdir")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpDir)
|
||||
|
||||
wd, err := os.Getwd()
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.Chdir(wd)
|
||||
|
||||
if err := os.Chdir(tmpDir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
subdir := filepath.Join("a", "b")
|
||||
if err := os.MkdirAll(subdir, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Symlink(subdir, "c"); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := ioutil.WriteFile(filepath.Join(subdir, "file"), nil, 0666); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
subdir = filepath.Join("d", "e", "f")
|
||||
if err := os.MkdirAll(subdir, 0777); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
if err := os.Chdir(subdir); err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
check := filepath.Join("..", "..", "..", "c", "file")
|
||||
wantSuffix := filepath.Join("a", "b", "file")
|
||||
if resolved, err := filepath.EvalSymlinks(check); err != nil {
|
||||
t.Errorf("EvalSymlinks(%q) failed: %v", check, err)
|
||||
} else if !strings.HasSuffix(resolved, wantSuffix) {
|
||||
t.Errorf("EvalSymlinks(%q) = %q does not end with %q", check, resolved, wantSuffix)
|
||||
} else {
|
||||
t.Logf("EvalSymlinks(%q) = %q", check, resolved)
|
||||
}
|
||||
}
|
||||
|
|
|
@ -44,18 +44,26 @@ func walkSymlinks(path string) (string, error) {
|
|||
} else if path[start:end] == ".." {
|
||||
// Back up to previous component if possible.
|
||||
// Note that volLen includes any leading slash.
|
||||
|
||||
// Set r to the index of the last slash in dest,
|
||||
// after the volume.
|
||||
var r int
|
||||
for r = len(dest) - 1; r >= volLen; r-- {
|
||||
if os.IsPathSeparator(dest[r]) {
|
||||
break
|
||||
}
|
||||
}
|
||||
if r < volLen {
|
||||
if r < volLen || dest[r+1:] == ".." {
|
||||
// Either path has no slashes
|
||||
// (it's empty or just "C:")
|
||||
// or it ends in a ".." we had to keep.
|
||||
// Either way, keep this "..".
|
||||
if len(dest) > volLen {
|
||||
dest += pathSeparator
|
||||
}
|
||||
dest += ".."
|
||||
} else {
|
||||
// Discard everything since the last slash.
|
||||
dest = dest[:r]
|
||||
}
|
||||
continue
|
||||
|
|
23
libgo/go/runtime/testdata/testprog/gc.go
vendored
23
libgo/go/runtime/testdata/testprog/gc.go
vendored
|
@ -18,6 +18,7 @@ func init() {
|
|||
register("GCFairness2", GCFairness2)
|
||||
register("GCSys", GCSys)
|
||||
register("GCPhys", GCPhys)
|
||||
register("DeferLiveness", DeferLiveness)
|
||||
}
|
||||
|
||||
func GCSys() {
|
||||
|
@ -210,3 +211,25 @@ func GCPhys() {
|
|||
fmt.Println("OK")
|
||||
runtime.KeepAlive(saved)
|
||||
}
|
||||
|
||||
// Test that defer closure is correctly scanned when the stack is scanned.
|
||||
func DeferLiveness() {
|
||||
var x [10]int
|
||||
escape(&x)
|
||||
fn := func() {
|
||||
if x[0] != 42 {
|
||||
panic("FAIL")
|
||||
}
|
||||
}
|
||||
defer fn()
|
||||
|
||||
x[0] = 42
|
||||
runtime.GC()
|
||||
runtime.GC()
|
||||
runtime.GC()
|
||||
}
|
||||
|
||||
//go:noinline
|
||||
func escape(x interface{}) { sink2 = x; sink2 = nil }
|
||||
|
||||
var sink2 interface{}
|
||||
|
|
|
@ -578,6 +578,13 @@ func (s *state) evalField(dot reflect.Value, fieldName string, node parse.Node,
|
|||
}
|
||||
typ := receiver.Type()
|
||||
receiver, isNil := indirect(receiver)
|
||||
if receiver.Kind() == reflect.Interface && isNil {
|
||||
// Calling a method on a nil interface can't work. The
|
||||
// MethodByName method call below would panic.
|
||||
s.errorf("nil pointer evaluating %s.%s", typ, fieldName)
|
||||
return zero
|
||||
}
|
||||
|
||||
// Unless it's an interface, need to get to a value of type *T to guarantee
|
||||
// we see all methods of T and *T.
|
||||
ptr := receiver
|
||||
|
|
|
@ -58,8 +58,10 @@ type T struct {
|
|||
Empty3 interface{}
|
||||
Empty4 interface{}
|
||||
// Non-empty interfaces.
|
||||
NonEmptyInterface I
|
||||
NonEmptyInterfacePtS *I
|
||||
NonEmptyInterface I
|
||||
NonEmptyInterfacePtS *I
|
||||
NonEmptyInterfaceNil I
|
||||
NonEmptyInterfaceTypedNil I
|
||||
// Stringer.
|
||||
Str fmt.Stringer
|
||||
Err error
|
||||
|
@ -141,24 +143,25 @@ var tVal = &T{
|
|||
{"one": 1, "two": 2},
|
||||
{"eleven": 11, "twelve": 12},
|
||||
},
|
||||
Empty1: 3,
|
||||
Empty2: "empty2",
|
||||
Empty3: []int{7, 8},
|
||||
Empty4: &U{"UinEmpty"},
|
||||
NonEmptyInterface: &T{X: "x"},
|
||||
NonEmptyInterfacePtS: &siVal,
|
||||
Str: bytes.NewBuffer([]byte("foozle")),
|
||||
Err: errors.New("erroozle"),
|
||||
PI: newInt(23),
|
||||
PS: newString("a string"),
|
||||
PSI: newIntSlice(21, 22, 23),
|
||||
BinaryFunc: func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) },
|
||||
VariadicFunc: func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
|
||||
VariadicFuncInt: func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") },
|
||||
NilOKFunc: func(s *int) bool { return s == nil },
|
||||
ErrFunc: func() (string, error) { return "bla", nil },
|
||||
PanicFunc: func() string { panic("test panic") },
|
||||
Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X
|
||||
Empty1: 3,
|
||||
Empty2: "empty2",
|
||||
Empty3: []int{7, 8},
|
||||
Empty4: &U{"UinEmpty"},
|
||||
NonEmptyInterface: &T{X: "x"},
|
||||
NonEmptyInterfacePtS: &siVal,
|
||||
NonEmptyInterfaceTypedNil: (*T)(nil),
|
||||
Str: bytes.NewBuffer([]byte("foozle")),
|
||||
Err: errors.New("erroozle"),
|
||||
PI: newInt(23),
|
||||
PS: newString("a string"),
|
||||
PSI: newIntSlice(21, 22, 23),
|
||||
BinaryFunc: func(a, b string) string { return fmt.Sprintf("[%s=%s]", a, b) },
|
||||
VariadicFunc: func(s ...string) string { return fmt.Sprint("<", strings.Join(s, "+"), ">") },
|
||||
VariadicFuncInt: func(a int, s ...string) string { return fmt.Sprint(a, "=<", strings.Join(s, "+"), ">") },
|
||||
NilOKFunc: func(s *int) bool { return s == nil },
|
||||
ErrFunc: func() (string, error) { return "bla", nil },
|
||||
PanicFunc: func() string { panic("test panic") },
|
||||
Tmpl: Must(New("x").Parse("test template")), // "x" is the value of .X
|
||||
}
|
||||
|
||||
var tSliceOfNil = []*T{nil}
|
||||
|
@ -365,6 +368,7 @@ var execTests = []execTest{
|
|||
{".NilOKFunc not nil", "{{call .NilOKFunc .PI}}", "false", tVal, true},
|
||||
{".NilOKFunc nil", "{{call .NilOKFunc nil}}", "true", tVal, true},
|
||||
{"method on nil value from slice", "-{{range .}}{{.Method1 1234}}{{end}}-", "-1234-", tSliceOfNil, true},
|
||||
{"method on typed nil interface value", "{{.NonEmptyInterfaceTypedNil.Method0}}", "M0", tVal, true},
|
||||
|
||||
// Function call builtin.
|
||||
{".BinaryFunc", "{{call .BinaryFunc `1` `2`}}", "[1=2]", tVal, true},
|
||||
|
@ -1492,6 +1496,11 @@ func TestExecutePanicDuringCall(t *testing.T) {
|
|||
"{{call .PanicFunc}}", tVal,
|
||||
`template: t:1:2: executing "t" at <call .PanicFunc>: error calling call: test panic`,
|
||||
},
|
||||
{
|
||||
"method call on nil interface",
|
||||
"{{.NonEmptyInterfaceNil.Method0}}", tVal,
|
||||
`template: t:1:23: executing "t" at <.NonEmptyInterfaceNil.Method0>: nil pointer evaluating template.I.Method0`,
|
||||
},
|
||||
}
|
||||
for _, tc := range tests {
|
||||
b := new(bytes.Buffer)
|
||||
|
|
14
libgo/misc/cgo/test/testdata/issue30527.go
vendored
Normal file
14
libgo/misc/cgo/test/testdata/issue30527.go
vendored
Normal file
|
@ -0,0 +1,14 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
// Issue 30527: function call rewriting casts untyped
|
||||
// constants to int because of ":=" usage.
|
||||
|
||||
package cgotest
|
||||
|
||||
import "cgotest/issue30527"
|
||||
|
||||
func issue30527G() {
|
||||
issue30527.G(nil)
|
||||
}
|
19
libgo/misc/cgo/test/testdata/issue30527/a.go
vendored
Normal file
19
libgo/misc/cgo/test/testdata/issue30527/a.go
vendored
Normal file
|
@ -0,0 +1,19 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package issue30527
|
||||
|
||||
import "math"
|
||||
|
||||
/*
|
||||
#include <inttypes.h>
|
||||
|
||||
static void issue30527F(char **p, uint64_t mod, uint32_t unused) {}
|
||||
*/
|
||||
import "C"
|
||||
|
||||
func G(p **C.char) {
|
||||
C.issue30527F(p, math.MaxUint64, 1)
|
||||
C.issue30527F(p, 1<<64-1, Z)
|
||||
}
|
11
libgo/misc/cgo/test/testdata/issue30527/b.go
vendored
Normal file
11
libgo/misc/cgo/test/testdata/issue30527/b.go
vendored
Normal file
|
@ -0,0 +1,11 @@
|
|||
// Copyright 2019 The Go Authors. All rights reserved.
|
||||
// Use of this source code is governed by a BSD-style
|
||||
// license that can be found in the LICENSE file.
|
||||
|
||||
package issue30527
|
||||
|
||||
const (
|
||||
X = 1 << iota
|
||||
Y
|
||||
Z
|
||||
)
|
Loading…
Add table
Reference in a new issue