1 // Copyright 2021 The Go Authors. All rights reserved.
2 // Use of this source code is governed by a BSD-style
3 // license that can be found in the LICENSE file.
8 "cmd/compile/internal/syntax"
13 // A version represents a released Go version.
18 func (v version) String() string {
19 return fmt.Sprintf("go%d.%d", v.major, v.minor)
22 func (v version) equal(u version) bool {
23 return v.major == u.major && v.minor == u.minor
26 func (v version) before(u version) bool {
27 return v.major < u.major || v.major == u.major && v.minor < u.minor
30 func (v version) after(u version) bool {
31 return v.major > u.major || v.major == u.major && v.minor > u.minor
34 // Go versions that introduced language changes.
36 go0_0 = version{0, 0} // no version specified
38 go1_13 = version{1, 13}
39 go1_14 = version{1, 14}
40 go1_17 = version{1, 17}
41 go1_18 = version{1, 18}
42 go1_20 = version{1, 20}
43 go1_21 = version{1, 21}
46 // parseGoVersion parses a Go version string (such as "go1.12")
47 // and returns the version, or an error. If s is the empty
48 // string, the version is 0.0.
49 func parseGoVersion(s string) (v version, err error) {
50 bad := func() (version, error) {
51 return version{}, fmt.Errorf("invalid Go version syntax %q", s)
56 if !strings.HasPrefix(s, "go") {
61 for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
62 if i >= 10 || i == 0 && s[i] == '0' {
65 v.major = 10*v.major + int(s[i]) - '0'
67 if i > 0 && i == len(s) {
70 if i == 0 || s[i] != '.' {
75 // We really should not accept "go1.0",
76 // but we didn't reject it from the start
77 // and there are now programs that use it.
82 for ; i < len(s) && '0' <= s[i] && s[i] <= '9'; i++ {
83 if i >= 10 || i == 0 && s[i] == '0' {
86 v.minor = 10*v.minor + int(s[i]) - '0'
88 // Accept any suffix after the minor number.
89 // We are only looking for the language version (major.minor)
90 // but want to accept any valid Go version, like go1.21.0
95 // langCompat reports an error if the representation of a numeric
96 // literal is not compatible with the current language version.
97 func (check *Checker) langCompat(lit *syntax.BasicLit) {
99 if len(s) <= 2 || check.allowVersion(check.pkg, lit, go1_13) {
103 if strings.Contains(s, "_") {
104 check.versionErrorf(lit, go1_13, "underscores in numeric literals")
111 if radix == 'b' || radix == 'B' {
112 check.versionErrorf(lit, go1_13, "binary literals")
115 if radix == 'o' || radix == 'O' {
116 check.versionErrorf(lit, go1_13, "0o/0O-style octal literals")
119 if lit.Kind != syntax.IntLit && (radix == 'x' || radix == 'X') {
120 check.versionErrorf(lit, go1_13, "hexadecimal floating-point literals")
124 // allowVersion reports whether the given package
125 // is allowed to use version major.minor.
126 func (check *Checker) allowVersion(pkg *Package, at poser, v version) bool {
127 // We assume that imported packages have all been checked,
128 // so we only have to check for the local package.
129 if pkg != check.pkg {
133 // If the source file declares its Go version, use that to decide.
134 if check.posVers != nil {
135 if src, ok := check.posVers[base(at.Pos())]; ok && src.major >= 1 {
136 return !src.before(v)
140 // Otherwise fall back to the version in the checker.
141 return check.version.equal(go0_0) || !check.version.before(v)
144 // verifyVersionf is like allowVersion but also accepts a format string and arguments
145 // which are used to report a version error if allowVersion returns false. It uses the
147 func (check *Checker) verifyVersionf(at poser, v version, format string, args ...interface{}) bool {
148 if !check.allowVersion(check.pkg, at, v) {
149 check.versionErrorf(at, v, format, args...)
155 // base finds the underlying PosBase of the source file containing pos,
156 // skipping over intermediate PosBase layers created by //line directives.
157 func base(pos syntax.Pos) *syntax.PosBase {
161 if bb == nil || bb == b {