The default language version is the current one.
For testing purposes, added a check that type aliases require version
go1.9. There is no consistent support for changes made before 1.12.
Updates #28221
Change-Id: Ia1ef63fff911d5fd29ef79d5fa4e20cfd945feb7
Reviewed-on: https://go-review.googlesource.com/c/144340
Run-TryBot: Ian Lance Taylor <iant@golang.org>
TryBot-Result: Gobot Gobot <gobot@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
instead of $GOROOT/pkg/$GOOS_$GOARCH.
-l
Disable inlining.
+ -lang version
+ Set language version to compile, as in -lang=go1.12.
+ Default is current version.
-largemodel
Generate code that assumes a large memory model.
-linkobj file
--- /dev/null
+// Copyright 2018 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 gc
+
+import (
+ "internal/testenv"
+ "io/ioutil"
+ "os"
+ "os/exec"
+ "path/filepath"
+ "testing"
+)
+
+const aliasSrc = `
+package x
+
+type T = int
+`
+
+func TestInvalidLang(t *testing.T) {
+ t.Parallel()
+
+ testenv.MustHaveGoBuild(t)
+
+ dir, err := ioutil.TempDir("", "TestInvalidLang")
+ if err != nil {
+ t.Fatal(err)
+ }
+ defer os.RemoveAll(dir)
+
+ src := filepath.Join(dir, "alias.go")
+ if err := ioutil.WriteFile(src, []byte(aliasSrc), 0644); err != nil {
+ t.Fatal(err)
+ }
+
+ outfile := filepath.Join(dir, "alias.o")
+
+ if testLang(t, "go9.99", src, outfile) == nil {
+ t.Error("compilation with -lang=go9.99 succeeded unexpectedly")
+ }
+
+ if testLang(t, "go1.8", src, outfile) == nil {
+ t.Error("compilation with -lang=go1.8 succeeded unexpectedly")
+ }
+
+ if err := testLang(t, "go1.9", src, outfile); err != nil {
+ t.Errorf("compilation with -lang=go1.9 failed unexpectedly: %v", err)
+ }
+}
+
+func testLang(t *testing.T, lang, src, outfile string) error {
+ run := []string{testenv.GoToolPath(t), "tool", "compile", "-lang", lang, "-o", outfile, src}
+ t.Log(run)
+ out, err := exec.Command(run[0], run[1:]...).CombinedOutput()
+ t.Logf("%s", out)
+ return err
+}
"cmd/internal/sys"
"flag"
"fmt"
+ "go/build"
"io"
"io/ioutil"
"log"
"os"
"path"
+ "regexp"
"runtime"
"strconv"
"strings"
flag.StringVar(&flag_installsuffix, "installsuffix", "", "set pkg directory `suffix`")
objabi.Flagcount("j", "debug runtime-initialized variables", &Debug['j'])
objabi.Flagcount("l", "disable inlining", &Debug['l'])
+ flag.StringVar(&flag_lang, "lang", defaultLang(), "release to compile for")
flag.StringVar(&linkobj, "linkobj", "", "write linker-specific object to `file`")
objabi.Flagcount("live", "debug liveness analysis", &debuglive)
objabi.Flagcount("m", "print optimization decisions", &Debug['m'])
Exit(2)
}
+ checkLang()
+
thearch.LinkArch.Init(Ctxt)
if outfile == "" {
Ctxt.Data = append(Ctxt.Data, s)
s.P = cmd.Bytes()[1:]
}
+
+// flag_lang is the language version we are compiling for, set by the -lang flag.
+var flag_lang string
+
+// defaultLang returns the default value for the -lang flag.
+func defaultLang() string {
+ tags := build.Default.ReleaseTags
+ return tags[len(tags)-1]
+}
+
+// goVersionRE is a regular expression that matches the valid
+// arguments to the -lang flag.
+var goVersionRE = regexp.MustCompile(`^go([1-9][0-9]*)\.(0|[1-9][0-9]*)$`)
+
+// A lang is a language version broken into major and minor numbers.
+type lang struct {
+ major, minor int
+}
+
+// langWant is the desired language version set by the -lang flag.
+var langWant lang
+
+// langSupported reports whether language version major.minor is supported.
+func langSupported(major, minor int) bool {
+ return langWant.major > major || (langWant.major == major && langWant.minor >= minor)
+}
+
+// checkLang verifies that the -lang flag holds a valid value, and
+// exits if not. It initializes data used by langSupported.
+func checkLang() {
+ var err error
+ langWant, err = parseLang(flag_lang)
+ if err != nil {
+ log.Fatalf("invalid value %q for -lang: %v", flag_lang, err)
+ }
+
+ if def := defaultLang(); flag_lang != def {
+ defVers, err := parseLang(def)
+ if err != nil {
+ log.Fatalf("internal error parsing default lang %q: %v", def, err)
+ }
+ if langWant.major > defVers.major || (langWant.major == defVers.major && langWant.major > defVers.minor) {
+ log.Fatalf("invalid value %q for -lang: max known version is %q", flag_lang, def)
+ }
+ }
+}
+
+// parseLang parses a -lang option into a langVer.
+func parseLang(s string) (lang, error) {
+ matches := goVersionRE.FindStringSubmatch(s)
+ if matches == nil {
+ return lang{}, fmt.Errorf(`should be something like "go1.12"`)
+ }
+ major, err := strconv.Atoi(matches[1])
+ if err != nil {
+ return lang{}, err
+ }
+ minor, err := strconv.Atoi(matches[2])
+ if err != nil {
+ return lang{}, err
+ }
+ return lang{major: major, minor: minor}, nil
+}
param.Pragma = 0
}
- return p.nod(decl, ODCLTYPE, n, nil)
-
+ nod := p.nod(decl, ODCLTYPE, n, nil)
+ if param.Alias && !langSupported(1, 9) {
+ yyerrorl(nod.Pos, "type aliases only supported as of -lang=go1.9")
+ }
+ return nod
}
func (p *noder) declNames(names []*syntax.Name) []*Node {
// which defaults to the list of Go releases the current release is compatible with.
// In addition to the BuildTags and ReleaseTags, build constraints
// consider the values of GOARCH and GOOS as satisfied tags.
+ // The last element in ReleaseTags is assumed to be the current release.
BuildTags []string
ReleaseTags []string
// say "+build go1.x", and code that should only be built before Go 1.x
// (perhaps it is the stub to use in that case) should say "+build !go1.x".
// NOTE: If you add to this list, also update the doc comment in doc.go.
+ // NOTE: The last element in ReleaseTags should be the current release.
const version = 11 // go1.11
for i := 1; i <= version; i++ {
c.ReleaseTags = append(c.ReleaseTags, "go1."+strconv.Itoa(i))