aboutsummaryrefslogtreecommitdiff
path: root/src/cmd
diff options
context:
space:
mode:
Diffstat (limited to 'src/cmd')
-rw-r--r--src/cmd/asm/internal/lex/slice.go2
-rw-r--r--src/cmd/compile/internal/ssa/_gen/RISCV64.rules10
-rw-r--r--src/cmd/compile/internal/ssa/rewriteRISCV64.go16
-rw-r--r--src/cmd/compile/internal/types2/check.go38
-rw-r--r--src/cmd/compile/internal/types2/issues_test.go81
-rw-r--r--src/cmd/compile/internal/types2/package.go21
-rw-r--r--src/cmd/compile/internal/types2/sizeof_test.go2
-rw-r--r--src/cmd/compile/internal/types2/version.go23
-rw-r--r--src/cmd/compile/internal/types2/version_test.go24
-rw-r--r--src/cmd/go/internal/work/exec.go8
-rw-r--r--src/cmd/go/internal/work/gc.go14
11 files changed, 157 insertions, 82 deletions
diff --git a/src/cmd/asm/internal/lex/slice.go b/src/cmd/asm/internal/lex/slice.go
index 8ee0c7035f..61b15dd963 100644
--- a/src/cmd/asm/internal/lex/slice.go
+++ b/src/cmd/asm/internal/lex/slice.go
@@ -65,7 +65,7 @@ func (s *Slice) Col() int {
// #define A #define B(x) x
// and
// #define A #define B (x) x
- // The first has definition of B has an argument, the second doesn't. Because we let
+ // The first definition of B has an argument, the second doesn't. Because we let
// text/scanner strip the blanks for us, this is extremely rare, hard to fix, and not worth it.
return s.pos
}
diff --git a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules
index eb1f10de96..9a6fcebdc5 100644
--- a/src/cmd/compile/internal/ssa/_gen/RISCV64.rules
+++ b/src/cmd/compile/internal/ssa/_gen/RISCV64.rules
@@ -836,11 +836,11 @@
//
// Key:
//
-// [+ -](x * y) [+ -] z.
-// _ N A S
-// D U
-// D B
+// [+ -](x * y [+ -] z).
+// _ N A S
+// D U
+// D B
//
// Note: multiplication commutativity handled by rule generator.
-(F(MADD|NMADD|MSUB|NMSUB)D neg:(FNEGD x) y z) && neg.Uses == 1 => (F(NMADD|MADD|NMSUB|MSUB)D x y z)
+(F(MADD|NMADD|MSUB|NMSUB)D neg:(FNEGD x) y z) && neg.Uses == 1 => (F(NMSUB|MSUB|NMADD|MADD)D x y z)
(F(MADD|NMADD|MSUB|NMSUB)D x y neg:(FNEGD z)) && neg.Uses == 1 => (F(MSUB|NMSUB|MADD|NMADD)D x y z)
diff --git a/src/cmd/compile/internal/ssa/rewriteRISCV64.go b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
index f1debe0c21..ffbeb1df47 100644
--- a/src/cmd/compile/internal/ssa/rewriteRISCV64.go
+++ b/src/cmd/compile/internal/ssa/rewriteRISCV64.go
@@ -3322,7 +3322,7 @@ func rewriteValueRISCV64_OpRISCV64FMADDD(v *Value) bool {
v_0 := v.Args[0]
// match: (FMADDD neg:(FNEGD x) y z)
// cond: neg.Uses == 1
- // result: (FNMADDD x y z)
+ // result: (FNMSUBD x y z)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
neg := v_0
@@ -3335,7 +3335,7 @@ func rewriteValueRISCV64_OpRISCV64FMADDD(v *Value) bool {
if !(neg.Uses == 1) {
continue
}
- v.reset(OpRISCV64FNMADDD)
+ v.reset(OpRISCV64FNMSUBD)
v.AddArg3(x, y, z)
return true
}
@@ -3367,7 +3367,7 @@ func rewriteValueRISCV64_OpRISCV64FMSUBD(v *Value) bool {
v_0 := v.Args[0]
// match: (FMSUBD neg:(FNEGD x) y z)
// cond: neg.Uses == 1
- // result: (FNMSUBD x y z)
+ // result: (FNMADDD x y z)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
neg := v_0
@@ -3380,7 +3380,7 @@ func rewriteValueRISCV64_OpRISCV64FMSUBD(v *Value) bool {
if !(neg.Uses == 1) {
continue
}
- v.reset(OpRISCV64FNMSUBD)
+ v.reset(OpRISCV64FNMADDD)
v.AddArg3(x, y, z)
return true
}
@@ -3412,7 +3412,7 @@ func rewriteValueRISCV64_OpRISCV64FNMADDD(v *Value) bool {
v_0 := v.Args[0]
// match: (FNMADDD neg:(FNEGD x) y z)
// cond: neg.Uses == 1
- // result: (FMADDD x y z)
+ // result: (FMSUBD x y z)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
neg := v_0
@@ -3425,7 +3425,7 @@ func rewriteValueRISCV64_OpRISCV64FNMADDD(v *Value) bool {
if !(neg.Uses == 1) {
continue
}
- v.reset(OpRISCV64FMADDD)
+ v.reset(OpRISCV64FMSUBD)
v.AddArg3(x, y, z)
return true
}
@@ -3457,7 +3457,7 @@ func rewriteValueRISCV64_OpRISCV64FNMSUBD(v *Value) bool {
v_0 := v.Args[0]
// match: (FNMSUBD neg:(FNEGD x) y z)
// cond: neg.Uses == 1
- // result: (FMSUBD x y z)
+ // result: (FMADDD x y z)
for {
for _i0 := 0; _i0 <= 1; _i0, v_0, v_1 = _i0+1, v_1, v_0 {
neg := v_0
@@ -3470,7 +3470,7 @@ func rewriteValueRISCV64_OpRISCV64FNMSUBD(v *Value) bool {
if !(neg.Uses == 1) {
continue
}
- v.reset(OpRISCV64FMSUBD)
+ v.reset(OpRISCV64FMADDD)
v.AddArg3(x, y, z)
return true
}
diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go
index b2a9eb0dbc..0a2a49062b 100644
--- a/src/cmd/compile/internal/types2/check.go
+++ b/src/cmd/compile/internal/types2/check.go
@@ -11,6 +11,7 @@ import (
"errors"
"fmt"
"go/constant"
+ "internal/goversion"
. "internal/types/errors"
)
@@ -231,19 +232,19 @@ func NewChecker(conf *Config, pkg *Package, info *Info) *Checker {
info = new(Info)
}
- version, err := parseGoVersion(conf.GoVersion)
- if err != nil {
- panic(fmt.Sprintf("invalid Go version %q (%v)", conf.GoVersion, err))
- }
+ // Note: clients may call NewChecker with the Unsafe package, which is
+ // globally shared and must not be mutated. Therefore NewChecker must not
+ // mutate *pkg.
+ //
+ // (previously, pkg.goVersion was mutated here: go.dev/issue/61212)
return &Checker{
- conf: conf,
- ctxt: conf.Context,
- pkg: pkg,
- Info: info,
- version: version,
- objMap: make(map[Object]*declInfo),
- impMap: make(map[importKey]*Package),
+ conf: conf,
+ ctxt: conf.Context,
+ pkg: pkg,
+ Info: info,
+ objMap: make(map[Object]*declInfo),
+ impMap: make(map[importKey]*Package),
}
}
@@ -333,6 +334,20 @@ func (check *Checker) Files(files []*syntax.File) error { return check.checkFile
var errBadCgo = errors.New("cannot use FakeImportC and go115UsesCgo together")
func (check *Checker) checkFiles(files []*syntax.File) (err error) {
+ if check.pkg == Unsafe {
+ // Defensive handling for Unsafe, which cannot be type checked, and must
+ // not be mutated. See https://go.dev/issue/61212 for an example of where
+ // Unsafe is passed to NewChecker.
+ return nil
+ }
+
+ check.version, err = parseGoVersion(check.conf.GoVersion)
+ if err != nil {
+ return err
+ }
+ if check.version.after(version{1, goversion.Version}) {
+ return fmt.Errorf("package requires newer Go version %v", check.version)
+ }
if check.conf.FakeImportC && check.conf.go115UsesCgo {
return errBadCgo
}
@@ -377,6 +392,7 @@ func (check *Checker) checkFiles(files []*syntax.File) (err error) {
check.monomorph()
}
+ check.pkg.goVersion = check.conf.GoVersion
check.pkg.complete = true
// no longer needed - release memory
diff --git a/src/cmd/compile/internal/types2/issues_test.go b/src/cmd/compile/internal/types2/issues_test.go
index 8bd42a5271..5e0ae213dc 100644
--- a/src/cmd/compile/internal/types2/issues_test.go
+++ b/src/cmd/compile/internal/types2/issues_test.go
@@ -497,14 +497,14 @@ func TestIssue43088(t *testing.T) {
// _ T2
// }
// }
- n1 := NewTypeName(syntax.Pos{}, nil, "T1", nil)
+ n1 := NewTypeName(nopos, nil, "T1", nil)
T1 := NewNamed(n1, nil, nil)
- n2 := NewTypeName(syntax.Pos{}, nil, "T2", nil)
+ n2 := NewTypeName(nopos, nil, "T2", nil)
T2 := NewNamed(n2, nil, nil)
- s1 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", T2, false)}, nil)
+ s1 := NewStruct([]*Var{NewField(nopos, nil, "_", T2, false)}, nil)
T1.SetUnderlying(s1)
- s2 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", T2, false)}, nil)
- s3 := NewStruct([]*Var{NewField(syntax.Pos{}, nil, "_", s2, false)}, nil)
+ s2 := NewStruct([]*Var{NewField(nopos, nil, "_", T2, false)}, nil)
+ s3 := NewStruct([]*Var{NewField(nopos, nil, "_", s2, false)}, nil)
T2.SetUnderlying(s3)
// These calls must terminate (no endless recursion).
@@ -535,38 +535,69 @@ func TestIssue44515(t *testing.T) {
}
func TestIssue43124(t *testing.T) {
- testenv.MustHaveGoBuild(t)
+ // TODO(rFindley) move this to testdata by enhancing support for importing.
+
+ testenv.MustHaveGoBuild(t) // The go command is needed for the importer to determine the locations of stdlib .a files.
// All involved packages have the same name (template). Error messages should
// disambiguate between text/template and html/template by printing the full
// path.
const (
asrc = `package a; import "text/template"; func F(template.Template) {}; func G(int) {}`
- bsrc = `package b; import ("a"; "html/template"); func _() { a.F(template.Template{}) }`
- csrc = `package c; import ("a"; "html/template"); func _() { a.G(template.Template{}) }`
- )
+ bsrc = `
+package b
- a := mustTypecheck(asrc, nil, nil)
- conf := Config{Importer: importHelper{pkg: a, fallback: defaultImporter()}}
+import (
+ "a"
+ "html/template"
+)
+func _() {
// Packages should be fully qualified when there is ambiguity within the
// error string itself.
- _, err := typecheck(bsrc, &conf, nil)
- if err == nil {
- t.Fatal("package b had no errors")
- }
- if !strings.Contains(err.Error(), "text/template") || !strings.Contains(err.Error(), "html/template") {
- t.Errorf("type checking error for b does not disambiguate package template: %q", err)
- }
+ a.F(template /* ERRORx "cannot use.*html/template.* as .*text/template" */ .Template{})
+}
+`
+ csrc = `
+package c
- // ...and also when there is any ambiguity in reachable packages.
- _, err = typecheck(csrc, &conf, nil)
- if err == nil {
- t.Fatal("package c had no errors")
- }
- if !strings.Contains(err.Error(), "html/template") {
- t.Errorf("type checking error for c does not disambiguate package template: %q", err)
+import (
+ "a"
+ "fmt"
+ "html/template"
+)
+
+// go.dev/issue/46905: make sure template is not the first package qualified.
+var _ fmt.Stringer = 1 // ERRORx "cannot use 1.*as fmt\\.Stringer"
+
+// Packages should be fully qualified when there is ambiguity in reachable
+// packages. In this case both a (and for that matter html/template) import
+// text/template.
+func _() { a.G(template /* ERRORx "cannot use .*html/template.*Template" */ .Template{}) }
+`
+
+ tsrc = `
+package template
+
+import "text/template"
+
+type T int
+
+// Verify that the current package name also causes disambiguation.
+var _ T = template /* ERRORx "cannot use.*text/template.* as T value" */.Template{}
+`
+ )
+
+ a := mustTypecheck(asrc, nil, nil)
+ imp := importHelper{pkg: a, fallback: defaultImporter()}
+
+ withImporter := func(cfg *Config) {
+ cfg.Importer = imp
}
+
+ testFiles(t, []string{"b.go"}, [][]byte{[]byte(bsrc)}, 0, false, withImporter)
+ testFiles(t, []string{"c.go"}, [][]byte{[]byte(csrc)}, 0, false, withImporter)
+ testFiles(t, []string{"t.go"}, [][]byte{[]byte(tsrc)}, 0, false, withImporter)
}
func TestIssue50646(t *testing.T) {
diff --git a/src/cmd/compile/internal/types2/package.go b/src/cmd/compile/internal/types2/package.go
index 61670f6718..e08099d81f 100644
--- a/src/cmd/compile/internal/types2/package.go
+++ b/src/cmd/compile/internal/types2/package.go
@@ -10,13 +10,14 @@ import (
// A Package describes a Go package.
type Package struct {
- path string
- name string
- scope *Scope
- imports []*Package
- complete bool
- fake bool // scope lookup errors are silently dropped if package is fake (internal use only)
- cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
+ path string
+ name string
+ scope *Scope
+ imports []*Package
+ complete bool
+ fake bool // scope lookup errors are silently dropped if package is fake (internal use only)
+ cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
+ goVersion string // minimum Go version required for package (by Config.GoVersion, typically from go.mod)
}
// NewPackage returns a new Package for the given package path and name.
@@ -35,6 +36,12 @@ func (pkg *Package) Name() string { return pkg.name }
// SetName sets the package name.
func (pkg *Package) SetName(name string) { pkg.name = name }
+// GoVersion returns the minimum Go version required by this package.
+// If the minimum version is unknown, GoVersion returns the empty string.
+// Individual source files may specify a different minimum Go version,
+// as reported in the [go/ast.File.GoVersion] field.
+func (pkg *Package) GoVersion() string { return pkg.goVersion }
+
// Scope returns the (complete or incomplete) package scope
// holding the objects declared at package level (TypeNames,
// Consts, Vars, and Funcs).
diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go
index af82b3fa7a..740dbc9276 100644
--- a/src/cmd/compile/internal/types2/sizeof_test.go
+++ b/src/cmd/compile/internal/types2/sizeof_test.go
@@ -47,7 +47,7 @@ func TestSizeof(t *testing.T) {
// Misc
{Scope{}, 60, 104},
- {Package{}, 36, 72},
+ {Package{}, 44, 88},
{_TypeSet{}, 28, 56},
}
diff --git a/src/cmd/compile/internal/types2/version.go b/src/cmd/compile/internal/types2/version.go
index 7d01b829a9..e525f16470 100644
--- a/src/cmd/compile/internal/types2/version.go
+++ b/src/cmd/compile/internal/types2/version.go
@@ -6,7 +6,6 @@ package types2
import (
"cmd/compile/internal/syntax"
- "errors"
"fmt"
"strings"
)
@@ -44,23 +43,24 @@ var (
go1_21 = version{1, 21}
)
-var errVersionSyntax = errors.New("invalid Go version syntax")
-
// parseGoVersion parses a Go version string (such as "go1.12")
// and returns the version, or an error. If s is the empty
// string, the version is 0.0.
func parseGoVersion(s string) (v version, err error) {
+ bad := func() (version, error) {
+ return version{}, fmt.Errorf("invalid Go version syntax %q", s)
+ }
if s == "" {
return
}
if !strings.HasPrefix(s, "go") {
- return version{}, errVersionSyntax
+ return bad()
}
s = s[len("go"):]
i := 0
for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
if i >= 10 || i == 0 && s[i] == '0' {
- return version{}, errVersionSyntax
+ return bad()
}
v.major = 10*v.major + int(s[i]) - '0'
}
@@ -68,7 +68,7 @@ func parseGoVersion(s string) (v version, err error) {
return
}
if i == 0 || s[i] != '.' {
- return version{}, errVersionSyntax
+ return bad()
}
s = s[i+1:]
if s == "0" {
@@ -81,14 +81,15 @@ func parseGoVersion(s string) (v version, err error) {
i = 0
for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
if i >= 10 || i == 0 && s[i] == '0' {
- return version{}, errVersionSyntax
+ return bad()
}
v.minor = 10*v.minor + int(s[i]) - '0'
}
- if i > 0 && i == len(s) {
- return
- }
- return version{}, errVersionSyntax
+ // Accept any suffix after the minor number.
+ // We are only looking for the language version (major.minor)
+ // but want to accept any valid Go version, like go1.21.0
+ // and go1.21rc2.
+ return
}
// langCompat reports an error if the representation of a numeric
diff --git a/src/cmd/compile/internal/types2/version_test.go b/src/cmd/compile/internal/types2/version_test.go
new file mode 100644
index 0000000000..651758e1b0
--- /dev/null
+++ b/src/cmd/compile/internal/types2/version_test.go
@@ -0,0 +1,24 @@
+// Copyright 2023 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 types2
+
+import "testing"
+
+var parseGoVersionTests = []struct {
+ in string
+ out version
+}{
+ {"go1.21", version{1, 21}},
+ {"go1.21.0", version{1, 21}},
+ {"go1.21rc2", version{1, 21}},
+}
+
+func TestParseGoVersion(t *testing.T) {
+ for _, tt := range parseGoVersionTests {
+ if out, err := parseGoVersion(tt.in); out != tt.out || err != nil {
+ t.Errorf("parseGoVersion(%q) = %v, %v, want %v, nil", tt.in, out, err, tt.out)
+ }
+ }
+}
diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go
index d38a051b2b..13d2a78a97 100644
--- a/src/cmd/go/internal/work/exec.go
+++ b/src/cmd/go/internal/work/exec.go
@@ -1115,6 +1115,7 @@ type vetConfig struct {
PackageVetx map[string]string // map package path to vetx data from earlier vet run
VetxOnly bool // only compute vetx data; don't report detected problems
VetxOutput string // write vetx data to this output file
+ GoVersion string // Go version for package
SucceedOnTypecheckFailure bool // awful hack; see #18395 and below
}
@@ -1149,6 +1150,13 @@ func buildVetConfig(a *Action, srcfiles []string) {
PackageFile: make(map[string]string),
Standard: make(map[string]bool),
}
+ if a.Package.Module != nil {
+ v := a.Package.Module.GoVersion
+ if v == "" {
+ v = gover.DefaultGoModVersion
+ }
+ vcfg.GoVersion = "go" + v
+ }
a.vetCfg = vcfg
for i, raw := range a.Package.Internal.RawImports {
final := a.Package.Imports[i]
diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go
index 6043ad5353..26b4e0f490 100644
--- a/src/cmd/go/internal/work/gc.go
+++ b/src/cmd/go/internal/work/gc.go
@@ -85,19 +85,7 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg
if p.Module != nil {
v := p.Module.GoVersion
if v == "" {
- // We started adding a 'go' directive to the go.mod file unconditionally
- // as of Go 1.12, so any module that still lacks such a directive must
- // either have been authored before then, or have a hand-edited go.mod
- // file that hasn't been updated by cmd/go since that edit.
- //
- // Unfortunately, through at least Go 1.16 we didn't add versions to
- // vendor/modules.txt. So this could also be a vendored 1.16 dependency.
- //
- // Fortunately, there were no breaking changes to the language between Go
- // 1.11 and 1.16, so if we assume Go 1.16 semantics we will not introduce
- // any spurious errors — we will only mask errors, and not particularly
- // important ones at that.
- v = "1.16"
+ v = gover.DefaultGoModVersion
}
if allowedVersion(v) {
defaultGcFlags = append(defaultGcFlags, "-lang=go"+gover.Lang(v))