1
0
mirror of https://github.com/golang/go synced 2024-11-17 14:14:56 -07:00

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 <bcmills@google.com>
Reviewed-by: Robert Griesemer <gri@golang.org>
This commit is contained in:
Matthew Dempsky 2019-11-07 15:54:59 -08:00
parent 9ee6ba089d
commit b7d097a4cf
5 changed files with 76 additions and 6 deletions

View File

@ -34,7 +34,7 @@ func expandiface(t *types.Type) {
switch prev := seen[m.Sym]; {
case prev == nil:
seen[m.Sym] = m
case langSupported(1, 14) && !explicit && types.Identical(m.Type, prev.Type):
case langSupported(1, 14, t.Pkg()) && !explicit && types.Identical(m.Type, prev.Type):
return
default:
yyerrorl(m.Pos, "duplicate method %s", m.Sym.Name)

View File

@ -1477,8 +1477,18 @@ type lang struct {
// any language version is supported.
var langWant lang
// langSupported reports whether language version major.minor is supported.
func langSupported(major, minor int) bool {
// langSupported reports whether language version major.minor is
// supported in a particular package.
func langSupported(major, minor int, pkg *types.Pkg) bool {
if pkg == nil {
// TODO(mdempsky): Set Pkg for local types earlier.
pkg = localpkg
}
if pkg != localpkg {
// Assume imported packages passed type-checking.
return true
}
if langWant.major == 0 && langWant.minor == 0 {
return true
}

View File

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

View File

@ -608,7 +608,7 @@ func typecheck1(n *Node, top int) (res *Node) {
n.Type = nil
return n
}
if t.IsSigned() && !langSupported(1, 13) {
if t.IsSigned() && !langSupported(1, 13, curpkg()) {
yyerrorv("go1.13", "invalid operation: %v (signed shift count type %v)", n, r.Type)
n.Type = nil
return n
@ -3951,3 +3951,20 @@ func getIotaValue() int64 {
return -1
}
// curpkg returns the current package, based on Curfn.
func curpkg() *types.Pkg {
fn := Curfn
if fn == nil {
// Initialization expressions for package-scope variables.
return localpkg
}
// TODO(mdempsky): Standardize on either ODCLFUNC or ONAME for
// Curfn, rather than mixing them.
if fn.Op == ODCLFUNC {
fn = fn.Func.Nname
}
return fnpkg(fn)
}

View File

@ -0,0 +1,43 @@
# Test that dependencies can use Go language features newer than the
# Go version specified by the main module.
env GO111MODULE=on
go build
-- go.mod --
module m
go 1.12
require (
sub.1 v1.0.0
)
replace (
sub.1 => ./sub
)
-- x.go --
package x
import "sub.1"
func F() { sub.F(0, 0) }
var A sub.Alias
var D sub.Defined
-- sub/go.mod --
module m
go 1.14
-- sub/sub.go --
package sub
// signed shift counts added in Go 1.13
func F(l, r int) int { return l << r }
type m1 interface { M() }
type m2 interface { M() }
// overlapping interfaces added in Go 1.14
type Alias = interface { m1; m2; M() }
type Defined interface { m1; m2; M() }