Skip to content

Commit b7d097a

Browse files
committed
cmd/compile: don't apply -lang=go1.X restrictions to imported packages
Previously langSupported applied -lang as though it's a global restriction, but it's actually a per-package restriction. This CL fixes langSupported to take a *types.Pkg parameter to reflect this and updates its callers accordingly. This is relevant for signed shifts (added in Go 1.12), because they can be inlined into a Go 1.11 package; and for overlapping interfaces (added in Go 1.13), because they can be exported as part of the package's API. Today we require all Go packages to be compiled with the same toolchain, and all uses of langSupported are for controlling backwards-compatible features. So we can simply assume that since the imported packages type-checked successfully, they must have been compiled with an appropriate -lang setting. In the future if we ever want to use langSupported to control backwards-incompatible language changes, we might need to record the -lang flag used for compiling a package in its export data. Fixes #35437. Fixes #35442. Change-Id: Ifdf6a62ee80cd5fb4366cbf12933152506d1b36e Reviewed-on: https://go-review.googlesource.com/c/go/+/205977 Reviewed-by: Bryan C. Mills <[email protected]> Reviewed-by: Robert Griesemer <[email protected]>
1 parent 9ee6ba0 commit b7d097a

File tree

5 files changed

+76
-6
lines changed

5 files changed

+76
-6
lines changed

Diff for: src/cmd/compile/internal/gc/align.go

+1-1
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ func expandiface(t *types.Type) {
3434
switch prev := seen[m.Sym]; {
3535
case prev == nil:
3636
seen[m.Sym] = m
37-
case langSupported(1, 14) && !explicit && types.Identical(m.Type, prev.Type):
37+
case langSupported(1, 14, t.Pkg()) && !explicit && types.Identical(m.Type, prev.Type):
3838
return
3939
default:
4040
yyerrorl(m.Pos, "duplicate method %s", m.Sym.Name)

Diff for: src/cmd/compile/internal/gc/main.go

+12-2
Original file line numberDiff line numberDiff line change
@@ -1477,8 +1477,18 @@ type lang struct {
14771477
// any language version is supported.
14781478
var langWant lang
14791479

1480-
// langSupported reports whether language version major.minor is supported.
1481-
func langSupported(major, minor int) bool {
1480+
// langSupported reports whether language version major.minor is
1481+
// supported in a particular package.
1482+
func langSupported(major, minor int, pkg *types.Pkg) bool {
1483+
if pkg == nil {
1484+
// TODO(mdempsky): Set Pkg for local types earlier.
1485+
pkg = localpkg
1486+
}
1487+
if pkg != localpkg {
1488+
// Assume imported packages passed type-checking.
1489+
return true
1490+
}
1491+
14821492
if langWant.major == 0 && langWant.minor == 0 {
14831493
return true
14841494
}

Diff for: src/cmd/compile/internal/gc/noder.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -446,7 +446,7 @@ func (p *noder) typeDecl(decl *syntax.TypeDecl) *Node {
446446
}
447447

448448
nod := p.nod(decl, ODCLTYPE, n, nil)
449-
if param.Alias && !langSupported(1, 9) {
449+
if param.Alias && !langSupported(1, 9, localpkg) {
450450
yyerrorl(nod.Pos, "type aliases only supported as of -lang=go1.9")
451451
}
452452
return nod
@@ -1321,7 +1321,7 @@ func (p *noder) binOp(op syntax.Operator) Op {
13211321
// literal is not compatible with the current language version.
13221322
func checkLangCompat(lit *syntax.BasicLit) {
13231323
s := lit.Value
1324-
if len(s) <= 2 || langSupported(1, 13) {
1324+
if len(s) <= 2 || langSupported(1, 13, localpkg) {
13251325
return
13261326
}
13271327
// len(s) > 2

Diff for: src/cmd/compile/internal/gc/typecheck.go

+18-1
Original file line numberDiff line numberDiff line change
@@ -608,7 +608,7 @@ func typecheck1(n *Node, top int) (res *Node) {
608608
n.Type = nil
609609
return n
610610
}
611-
if t.IsSigned() && !langSupported(1, 13) {
611+
if t.IsSigned() && !langSupported(1, 13, curpkg()) {
612612
yyerrorv("go1.13", "invalid operation: %v (signed shift count type %v)", n, r.Type)
613613
n.Type = nil
614614
return n
@@ -3951,3 +3951,20 @@ func getIotaValue() int64 {
39513951

39523952
return -1
39533953
}
3954+
3955+
// curpkg returns the current package, based on Curfn.
3956+
func curpkg() *types.Pkg {
3957+
fn := Curfn
3958+
if fn == nil {
3959+
// Initialization expressions for package-scope variables.
3960+
return localpkg
3961+
}
3962+
3963+
// TODO(mdempsky): Standardize on either ODCLFUNC or ONAME for
3964+
// Curfn, rather than mixing them.
3965+
if fn.Op == ODCLFUNC {
3966+
fn = fn.Func.Nname
3967+
}
3968+
3969+
return fnpkg(fn)
3970+
}

Diff for: src/cmd/go/testdata/script/mod_go_version_mixed.txt

+43
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,43 @@
1+
# Test that dependencies can use Go language features newer than the
2+
# Go version specified by the main module.
3+
4+
env GO111MODULE=on
5+
6+
go build
7+
8+
-- go.mod --
9+
module m
10+
go 1.12
11+
require (
12+
sub.1 v1.0.0
13+
)
14+
replace (
15+
sub.1 => ./sub
16+
)
17+
18+
-- x.go --
19+
package x
20+
21+
import "sub.1"
22+
23+
func F() { sub.F(0, 0) }
24+
25+
var A sub.Alias
26+
var D sub.Defined
27+
28+
-- sub/go.mod --
29+
module m
30+
go 1.14
31+
32+
-- sub/sub.go --
33+
package sub
34+
35+
// signed shift counts added in Go 1.13
36+
func F(l, r int) int { return l << r }
37+
38+
type m1 interface { M() }
39+
type m2 interface { M() }
40+
41+
// overlapping interfaces added in Go 1.14
42+
type Alias = interface { m1; m2; M() }
43+
type Defined interface { m1; m2; M() }

0 commit comments

Comments
 (0)