Commit b7d097a4 authored by Matthew Dempsky's avatar Matthew Dempsky

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/+/205977Reviewed-by: default avatarBryan C. Mills <bcmills@google.com>
Reviewed-by: default avatarRobert Griesemer <gri@golang.org>
parent 9ee6ba08
......@@ -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)
......
......@@ -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
}
......
......@@ -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
......
......@@ -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)
}
# 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() }
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment