diff --git a/AUTHORS b/AUTHORS index 1a4a57bae7..08caca5f68 100644 --- a/AUTHORS +++ b/AUTHORS @@ -202,7 +202,7 @@ Ben Burkert Ben Haines Ben Lubar Ben Olive -Ben Shi +Ben Shi Benjamin Black Benjamin Cable Benjamin Hsieh @@ -263,6 +263,7 @@ Casey Callendrello Casey Marshall Cezar Sá Espinola ChaiShushan +Changkun Ou Chaoqun Han Charles Fenwick Elliott Charles L. Dorian @@ -569,6 +570,7 @@ Hootsuite Inc. Hsin-Ho Yeh Hu Keping Hugues Bruant +HyperConnect Inc. Ian Gudger Ian Kent IBM @@ -1146,6 +1148,7 @@ Piers Pieter Droogendijk Pietro Gagliardi Piyush Mishra +PlanetScale, Inc. Platform.sh Pontus Leitzler Prasanga Siripala diff --git a/CONTRIBUTORS b/CONTRIBUTORS index 48567eed15..f79c4132b8 100644 --- a/CONTRIBUTORS +++ b/CONTRIBUTORS @@ -365,7 +365,7 @@ Ben Lubar Ben Lynn Ben Olive Ben Schwartz -Ben Shi +Ben Shi Ben Toews Benjamin Barenblat Benjamin Black @@ -451,6 +451,7 @@ Bryan Ford Bryan Heden Bulat Gaifullin Burak Guven +Byoungchan Lee Caine Tighe Caio Marcelo de Oliveira Filho Caleb Martinez @@ -486,7 +487,7 @@ Cedric Staub Cezar Sá Espinola Chad Rosier ChaiShushan -Changkun Ou +Changkun Ou Channing Kimble-Brown Chao Xu Chaoqun Han @@ -1791,7 +1792,7 @@ Matt Jibson Matt Joiner Matt Jones Matt Juran -Matt Layher +Matt Layher Matt Masurka Matt Pearring Matt Reiferson diff --git a/README.md b/README.md index 5aca9587fa..829fe777b9 100644 --- a/README.md +++ b/README.md @@ -16,23 +16,23 @@ BSD-style license found in the LICENSE file. #### Binary Distributions -Official binary distributions are available at https://golang.org/dl/. +Official binary distributions are available at https://go.dev/dl/. -After downloading a binary release, visit https://golang.org/doc/install +After downloading a binary release, visit https://go.dev/doc/install for installation instructions. #### Install From Source If a binary distribution is not available for your combination of operating system and architecture, visit -https://golang.org/doc/install/source +https://go.dev/doc/install/source for source installation instructions. ### Contributing Go is the work of thousands of contributors. We appreciate your help! -To contribute, please read the contribution guidelines at https://golang.org/doc/contribute. +To contribute, please read the contribution guidelines at https://go.dev/doc/contribute. Note that the Go project uses the issue tracker for bug reports and proposals only. See https://golang.org/wiki/Questions for a list of diff --git a/api/README b/api/README index ce24efcd31..1e52f7a843 100644 --- a/api/README +++ b/api/README @@ -8,6 +8,16 @@ shipped. Each file adds new lines but does not remove any. except.txt lists features that may disappear without breaking true compatibility. -next.txt is the only file intended to be mutated. It's a list of -features that may be added to the next version. It only affects -warning output from the go api tool. +Starting with go1.19.txt, each API feature line must end in "#nnnnn" +giving the GitHub issue number of the proposal issue that accepted +the new API. This helps with our end-of-cycle audit of new APIs. +The same requirement applies to next/* (described below), which will +become a go1.XX.txt for XX >= 19. + +The next/ directory contains the only files intended to be mutated. +Each file in that directory contains a list of features that may be added +to the next release of Go. The files in this directory only affect the +warning output from the go api tool. Each file should be named +nnnnn.txt, after the issue number for the accepted proposal. +(The #nnnnn suffix must also appear at the end of each line in the file; +that will be preserved when next/*.txt is concatenated into go1.XX.txt.) diff --git a/api/next/45628.txt b/api/next/45628.txt new file mode 100644 index 0000000000..5065ae4a60 --- /dev/null +++ b/api/next/45628.txt @@ -0,0 +1 @@ +pkg encoding/xml, method (*Decoder) InputPos() (int, int) #45628 diff --git a/api/next/45754.txt b/api/next/45754.txt new file mode 100644 index 0000000000..e980342c04 --- /dev/null +++ b/api/next/45754.txt @@ -0,0 +1,2 @@ +pkg flag, func TextVar(encoding.TextUnmarshaler, string, encoding.TextMarshaler, string) #45754 +pkg flag, method (*FlagSet) TextVar(encoding.TextUnmarshaler, string, encoding.TextMarshaler, string) #45754 diff --git a/api/next/46059.txt b/api/next/46059.txt new file mode 100644 index 0000000000..3cc44966a2 --- /dev/null +++ b/api/next/46059.txt @@ -0,0 +1,2 @@ +pkg net/url, type URL struct, OmitHost bool #46059 + diff --git a/api/next/47005.txt b/api/next/47005.txt new file mode 100644 index 0000000000..0d7695e45c --- /dev/null +++ b/api/next/47005.txt @@ -0,0 +1,2 @@ +pkg net/url, func JoinPath(string, ...string) (string, error) #47005 +pkg net/url, method (*URL) JoinPath(...string) *URL #47005 diff --git a/api/next.txt b/api/next/50601.txt similarity index 66% rename from api/next.txt rename to api/next/50601.txt index 23fd98a9ba..261dce375d 100644 --- a/api/next.txt +++ b/api/next/50601.txt @@ -1,5 +1,5 @@ -pkg encoding/binary, type AppendByteOrder interface { AppendUint16, AppendUint32, AppendUint64, String } -pkg encoding/binary, type AppendByteOrder interface, AppendUint16([]uint8, uint16) []uint8 -pkg encoding/binary, type AppendByteOrder interface, AppendUint32([]uint8, uint32) []uint8 -pkg encoding/binary, type AppendByteOrder interface, AppendUint64([]uint8, uint64) []uint8 -pkg encoding/binary, type AppendByteOrder interface, String() string +pkg encoding/binary, type AppendByteOrder interface { AppendUint16, AppendUint32, AppendUint64, String } #50601 +pkg encoding/binary, type AppendByteOrder interface, AppendUint16([]uint8, uint16) []uint8 #50601 +pkg encoding/binary, type AppendByteOrder interface, AppendUint32([]uint8, uint32) []uint8 #50601 +pkg encoding/binary, type AppendByteOrder interface, AppendUint64([]uint8, uint64) []uint8 #50601 +pkg encoding/binary, type AppendByteOrder interface, String() string #50601 diff --git a/api/next/51414.txt b/api/next/51414.txt new file mode 100644 index 0000000000..7491285bb8 --- /dev/null +++ b/api/next/51414.txt @@ -0,0 +1 @@ +pkg time, method (Duration) Abs() Duration #51414 diff --git a/doc/go1.19.html b/doc/go1.19.html index a68c27ecc8..c71d5e760b 100644 --- a/doc/go1.19.html +++ b/doc/go1.19.html @@ -59,3 +59,18 @@ Do not send CLs removing the interior tags from such phrases.

TODO: complete this section

+
net
+
+

+ The pure Go resolver will now use EDNS(0) to include a suggested + maximum reply packet length, permitting reply packets to contain + up to 1232 bytes (the previous maximum was 512). + In the unlikely event that this causes problems with a local DNS + resolver, setting the environment variable + GODEBUG=netdns=cgo to use the cgo-based resolver + should work. + Please report any such problems on the + issue tracker. +

+
+
diff --git a/doc/go_spec.html b/doc/go_spec.html index 6c6f982854..ad12fcfaa9 100644 --- a/doc/go_spec.html +++ b/doc/go_spec.html @@ -1,26 +1,16 @@ -

Earlier version

- -

-For the pre-Go1.18 specification without generics support see -The Go Programming Language Specification. -

- - -

-[For reviewers: Sections where we know of missing prose are marked like this. The markers will be removed before the release.] -

-

Introduction

-This is a reference manual for the Go programming language. For -more information and other documents, see golang.org. +This is the reference manual for the Go programming language. +The pre-Go1.18 version, without generics, can be found +here. +For more information and other documents, see golang.org.

@@ -766,7 +756,7 @@ type given in its declaration, the type provided in the new call or composite literal, or the type of an element of a structured variable. Variables of interface type also have a distinct dynamic type, -which is the concrete type of the value assigned to the variable at run time +which is the (non-interface) type of the value assigned to the variable at run time (unless the value is the predeclared identifier nil, which has no type). The dynamic type may vary during execution but values stored in interface @@ -812,7 +802,7 @@ TypeLit = ArrayType | StructType | PointerType | FunctionType | InterfaceType

The language predeclares certain type names. Others are introduced with type declarations -or type parameter lists. +or type parameter lists. Composite types—array, struct, pointer, function, interface, slice, map, and channel types—may be constructed using type literals. @@ -987,7 +977,7 @@ built-in function cap(a).

-A new, initialized slice value for a given element type T is +A new, initialized slice value for a given element type T may be made using the built-in function make, which takes a slice type @@ -1422,7 +1412,7 @@ interface { ~int } -// An interface representing all types with underlying type int which implement the String method. +// An interface representing all types with underlying type int that implement the String method. interface { ~int String() string @@ -1455,32 +1445,32 @@ Union elements denote unions of type sets:

-// The Floats interface represents all floating-point types
+// The Float interface represents all floating-point types
 // (including any named types whose underlying types are
 // either float32 or float64).
-type Floats interface {
+type Float interface {
 	~float32 | ~float64
 }
 

-In a union, a term cannot be a type parameter, and the type sets of all +In a union, a term cannot be a type parameter, and the type sets of all non-interface terms must be pairwise disjoint (the pairwise intersection of the type sets must be empty). Given a type parameter P:

 interface {
-	P                 // illegal: the term P is a type parameter
-	int | P           // illegal: the term P is a type parameter
-	~int | MyInt      // illegal: the type sets for ~int and MyInt are not disjoint (~int includes MyInt)
-	float32 | Floats  // overlapping type sets but Floats is an interface
+	P                // illegal: P is a type parameter
+	int | P          // illegal: P is a type parameter
+	~int | MyInt     // illegal: the type sets for ~int and MyInt are not disjoint (~int includes MyInt)
+	float32 | Float  // overlapping type sets but Float is an interface
 }
 

Implementation restriction: -A union with more than one term cannot contain the +A union (with more than one term) cannot contain the predeclared identifier comparable or interfaces that specify methods, or embed comparable or interfaces that specify methods. @@ -1494,12 +1484,12 @@ non-interface types.

-var x Floats                     // illegal: Floats is not a basic interface
+var x Float                     // illegal: Float is not a basic interface
 
-var x interface{} = Floats(nil)  // illegal
+var x interface{} = Float(nil)  // illegal
 
 type Floatish struct {
-	f Floats                 // illegal
+	f Float                 // illegal
 }
 
@@ -1545,7 +1535,7 @@ A type T implements an interface I if

-A value x of type T implements an interface if T +A value of type T implements an interface if T implements the interface.

@@ -1701,10 +1691,9 @@ Each type T has an underlying type: If T is one of the predeclared boolean, numeric, or string types, or a type literal, the corresponding underlying type is T itself. Otherwise, T's underlying type is the underlying type of the -type to which T refers in its type -declaration. The underlying type of a type parameter is the -underlying type of its type constraint, which -is always an interface. +type to which T refers in its declaration. +For a type parameter that is the underlying type of its +type constraint, which is always an interface.

@@ -1755,7 +1744,7 @@ direction.
 
 
 

-All other interfaces don't have a core type. +No other interfaces have a core type.

@@ -1775,7 +1764,7 @@ depending on the direction of the directional channels present.

By definition, a core type is never a defined type, -type parameter, or +type parameter, or interface type.

@@ -1795,7 +1784,7 @@ interface{ ~[]*data; String() string } // []*data

-Examples of interfaces whithout core types: +Examples of interfaces without core types:

@@ -1805,70 +1794,6 @@ interface{ chan int | chan<- string }     // channels have different element
 interface{ <-chan int | chan<- int }      // directional channels have different directions
 
-

Specific types

- -

-[The definition of specific types is not quite correct yet.] -

- -

-An interface specification that contains type elements -defines a (possibly empty) set of specific types. -Loosely speaking, these are the types T that appear in the -interface definition in terms of the form T, ~T, -or in unions of such terms. -

- -

-More precisely, for a given interface, the set of specific types corresponds to -the set 𝑅 of representative types of the interface, if 𝑅 is non-empty and finite. -Otherwise, if 𝑅 is empty or infinite, the interface has no specific types. -

- -

-For a given interface, type element or type term, the set 𝑅 of representative types is defined as follows: -

- -
    -
  • For an interface with no type elements, 𝑅 is the (infinite) set of all types. -
  • - -
  • For an interface with type elements, - 𝑅 is the intersection of the representative types of its type elements. -
  • - -
  • For a non-interface type term T or a term of the form ~T, - 𝑅 is the set consisting of the type T. -
  • - -
  • For a union of terms - t1|t2|…|tn, - 𝑅 is the union of the representative types of the terms. -
  • -
- -

-An interface may have specific types even if its type set -is empty. -

- -

-Examples of interfaces with their specific types: -

- -
-interface{}                    // no specific types
-interface{ int }               // int
-interface{ ~string }           // string
-interface{ int|~string }       // int, string
-interface{ Celsius|Kelvin }    // Celsius, Kelvin
-interface{ float64|any }       // no specific types (union is all types)
-interface{ int; m() }          // int (but type set is empty because int has no method m)
-interface{ ~int; m() }         // int (but type set is infinite because many integer types have a method m)
-interface{ int; any }          // int
-interface{ int; string }       // no specific types (intersection is empty)
-
-

Type identity

@@ -1973,21 +1898,21 @@ defined type while the latter is a type literal

Assignability

-A value x is assignable to a variable of type T +A value x of type V is assignable to a variable of type T ("x is assignable to T") if one of the following conditions applies:

  • -x's type is identical to T. +V and T are identical.
  • -x's type V and T have identical +V and T have identical underlying types and at least one of V or T is not a named type.
  • -x's type V and T are channel types with +V and T are channel types with identical element types, V is a bidirectional channel, and at least one of V or T is not a named type.
  • @@ -2008,25 +1933,24 @@ by a value of type T.

-Additionally, if x's type V or T are type parameters -with specific types, x +Additionally, if x's type V or T are type parameters, x is assignable to a variable of type T if one of the following conditions applies:

  • x is the predeclared identifier nil, T is -a type parameter, and x is assignable to each specific type of -T. +a type parameter, and x is assignable to each type in +T's type set.
  • V is not a named type, T is -a type parameter, and x is assignable to each specific type of -T. +a type parameter, and x is assignable to each type in +T's type set.
  • V is a type parameter and T is not a named type, -and values of each specific type of V are assignable +and values of each type in V's type set are assignable to T.
@@ -2036,7 +1960,7 @@ to T.

A constant x is representable by a value of type T, -where T is not a type parameter, +where T is not a type parameter, if one of the following conditions applies:

@@ -2061,9 +1985,9 @@ are representable by values of T's component type (float32

-If T is a type parameter with specific types, +If T is a type parameter, x is representable by a value of type T if x is representable -by a value of each specific type of T. +by a value of each type in T's type set.

@@ -2176,6 +2100,7 @@ Blocks nest and influence scoping.
 A declaration binds a non-blank identifier to a
 constant,
 type,
+type parameter,
 variable,
 function,
 label, or
@@ -2220,13 +2145,13 @@ Go is lexically scoped using blocks:
 	
  • The scope of an identifier denoting a method receiver, function parameter, or result variable is the function body.
  • -
  • The scope of an identifier denoting a type parameter of a generic function +
  • The scope of an identifier denoting a type parameter of a function or declared by a method receiver is the function body and all parameter lists of the function.
  • -
  • The scope of an identifier denoting a type parameter of a generic type - begins after the name of the generic type and ends at the end +
  • The scope of an identifier denoting a type parameter of a type + begins after the name of the type and ends at the end of the TypeSpec.
  • The scope of a constant or variable identifier declared @@ -2512,7 +2437,7 @@ type ( type TreeNode struct { left, right *TreeNode - value *Comparable + value any } type Block interface { @@ -2573,7 +2498,7 @@ func (tz TimeZone) String() string {
  • -If the type definition specifies type parameters, +If the type definition specifies type parameters, the type name denotes a generic type. Generic types must be instantiated when they are used. @@ -2584,15 +2509,10 @@ type List[T any] struct { next *List[T] value T } - -type Tree[T constraints.Ordered] struct { - left, right *Tree[T] - value T -}

    -The given type cannot be a type parameter in a type definition. +In a type definition the given type cannot be a type parameter.

    @@ -2604,8 +2524,8 @@ func f[T any]() {
     

    -A generic type may also have methods associated with it. In this case, -the method receivers must declare the same number of type parameters as +A generic type may also have methods associated with it. +In this case, the method receivers must declare the same number of type parameters as present in the generic type definition.

    @@ -2614,7 +2534,7 @@ present in the generic type definition. func (l *List[T]) Len() int { … } -

    Type parameter lists

    +

    Type parameter declarations

    A type parameter list declares the type parameters of a generic function or type declaration. @@ -2653,22 +2573,22 @@ has a corresponding (meta-)type which is called its

    A parsing ambiguity arises when the type parameter list for a generic type -declares a single type parameter with a type constraint of the form *C -or (C) where C is not a (possibly parenthesized) -type literal: +declares a single type parameter P with a constraint C +such that the text P C forms a valid expression:

     type T[P *C] …
     type T[P (C)] …
    +type T[P *C|Q] …
    +…
     

    -In these rare cases, the type parameter declaration is indistinguishable from -the expressions P*C or P(C) and the type declaration -is parsed as an array type declaration. -To resolve the ambiguity, embed the constraint in an interface or use a trailing -comma: +In these rare cases, the type parameter list is indistinguishable from an +expression and the type declaration is parsed as an array type declaration. +To resolve the ambiguity, embed the constraint in an +interface or use a trailing comma:

    @@ -2682,6 +2602,11 @@ of a method declaration associated
     with a generic type.
     

    + +

    Type constraints

    @@ -2701,10 +2626,10 @@ the enclosing interface{ … } may be omitted for convenience:

    -[T *P]                             // = [T interface{*P}]
    -[T ~int]                           // = [T interface{~int}]
    -[T int|string]                     // = [T interface{int|string}]
    -type Constraint ~int               // illegal: ~int is not inside a type parameter list
    +[T []P]                      // = [T interface{[]P}]
    +[T ~int]                     // = [T interface{~int}]
    +[T int|string]               // = [T interface{int|string}]
    +type Constraint ~int         // illegal: ~int is not inside a type parameter list
     
    +

    A Pointer is a pointer type but a Pointer value may not be dereferenced. -Any pointer or value of underlying type uintptr can be converted to -a type of underlying type Pointer and vice versa. +Any pointer or value of underlying type uintptr can be +converted to a type of underlying type Pointer and vice versa. The effect of converting between Pointer and uintptr is implementation-defined.

    @@ -8055,7 +7980,8 @@ uintptr(unsafe.Pointer(&x)) % unsafe.Alignof(x) == 0

    A (variable of) type T has variable size if T -is a type parameter, or if it is an array or struct type containing elements +is a type parameter, or if it is an +array or struct type containing elements or fields of variable size. Otherwise the size is constant. Calls to Alignof, Offsetof, and Sizeof are compile-time constant expressions of diff --git a/misc/cgo/testplugin/plugin_test.go b/misc/cgo/testplugin/plugin_test.go index 10c5db2646..53e79a4626 100644 --- a/misc/cgo/testplugin/plugin_test.go +++ b/misc/cgo/testplugin/plugin_test.go @@ -283,6 +283,12 @@ func TestMethod2(t *testing.T) { run(t, "./method2.exe") } +func TestMethod3(t *testing.T) { + goCmd(t, "build", "-buildmode=plugin", "-o", "method3.so", "./method3/plugin.go") + goCmd(t, "build", "-o", "method3.exe", "./method3/main.go") + run(t, "./method3.exe") +} + func TestIssue44956(t *testing.T) { goCmd(t, "build", "-buildmode=plugin", "-o", "issue44956p1.so", "./issue44956/plugin1.go") goCmd(t, "build", "-buildmode=plugin", "-o", "issue44956p2.so", "./issue44956/plugin2.go") diff --git a/misc/cgo/testplugin/testdata/method3/main.go b/misc/cgo/testplugin/testdata/method3/main.go new file mode 100644 index 0000000000..a3a51711cd --- /dev/null +++ b/misc/cgo/testplugin/testdata/method3/main.go @@ -0,0 +1,32 @@ +// Copyright 2022 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. + +// An unexported method can be reachable from the plugin via interface +// when a package is shared. So it need to be live. + +package main + +import ( + "plugin" + + "testplugin/method3/p" +) + +var i p.I + +func main() { + pl, err := plugin.Open("method3.so") + if err != nil { + panic(err) + } + + f, err := pl.Lookup("F") + if err != nil { + panic(err) + } + + f.(func())() + + i = p.T(123) +} diff --git a/misc/cgo/testplugin/testdata/method3/p/p.go b/misc/cgo/testplugin/testdata/method3/p/p.go new file mode 100644 index 0000000000..3846bc07f5 --- /dev/null +++ b/misc/cgo/testplugin/testdata/method3/p/p.go @@ -0,0 +1,17 @@ +// Copyright 2022 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 p + +type T int + +func (T) m() { println("m") } + +type I interface { m() } + +func F() { + i.m() +} + +var i I = T(123) diff --git a/misc/cgo/testplugin/testdata/method3/plugin.go b/misc/cgo/testplugin/testdata/method3/plugin.go new file mode 100644 index 0000000000..bd25b31857 --- /dev/null +++ b/misc/cgo/testplugin/testdata/method3/plugin.go @@ -0,0 +1,11 @@ +// Copyright 2022 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 main + +import "testplugin/method3/p" + +func main() {} + +func F() { p.F() } diff --git a/misc/cgo/testsanitizers/asan_test.go b/misc/cgo/testsanitizers/asan_test.go index 22dcf23c3b..ff578ac63e 100644 --- a/misc/cgo/testsanitizers/asan_test.go +++ b/misc/cgo/testsanitizers/asan_test.go @@ -41,6 +41,9 @@ func TestASAN(t *testing.T) { {src: "asan4_fail.go", memoryAccessError: "use-after-poison", errorLocation: "asan4_fail.go:13"}, {src: "asan5_fail.go", memoryAccessError: "use-after-poison", errorLocation: "asan5_fail.go:18"}, {src: "asan_useAfterReturn.go"}, + {src: "asan_unsafe_fail1.go", memoryAccessError: "use-after-poison", errorLocation: "asan_unsafe_fail1.go:25"}, + {src: "asan_unsafe_fail2.go", memoryAccessError: "use-after-poison", errorLocation: "asan_unsafe_fail2.go:25"}, + {src: "asan_unsafe_fail3.go", memoryAccessError: "use-after-poison", errorLocation: "asan_unsafe_fail3.go:18"}, } for _, tc := range cases { tc := tc diff --git a/misc/cgo/testsanitizers/testdata/asan_unsafe_fail1.go b/misc/cgo/testsanitizers/testdata/asan_unsafe_fail1.go new file mode 100644 index 0000000000..ec54a66880 --- /dev/null +++ b/misc/cgo/testsanitizers/testdata/asan_unsafe_fail1.go @@ -0,0 +1,27 @@ +// Copyright 2022 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 main + +import ( + "fmt" + "unsafe" +) + +func main() { + a := 1 + b := 2 + c := add(a, b) + d := a + b + fmt.Println(c, d) +} + +//go:noinline +func add(a1, b1 int) int { + // The arguments. + // When -asan is enabled, unsafe.Pointer(&a1) conversion is escaping. + var p *int = (*int)(unsafe.Add(unsafe.Pointer(&a1), 1*unsafe.Sizeof(int(1)))) + *p = 10 // BOOM + return a1 + b1 +} diff --git a/misc/cgo/testsanitizers/testdata/asan_unsafe_fail2.go b/misc/cgo/testsanitizers/testdata/asan_unsafe_fail2.go new file mode 100644 index 0000000000..70f21275af --- /dev/null +++ b/misc/cgo/testsanitizers/testdata/asan_unsafe_fail2.go @@ -0,0 +1,28 @@ +// Copyright 2022 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 main + +import ( + "fmt" + "unsafe" +) + +func main() { + a := 1 + b := 2 + c := add(a, b) + d := a + b + fmt.Println(c, d) +} + +//go:noinline +func add(a1, b1 int) (ret int) { + // The return value + // When -asan is enabled, the unsafe.Pointer(&ret) conversion is escaping. + var p *int = (*int)(unsafe.Add(unsafe.Pointer(&ret), 1*unsafe.Sizeof(int(1)))) + *p = 123 // BOOM + ret = a1 + b1 + return +} diff --git a/misc/cgo/testsanitizers/testdata/asan_unsafe_fail3.go b/misc/cgo/testsanitizers/testdata/asan_unsafe_fail3.go new file mode 100644 index 0000000000..47a8a072ef --- /dev/null +++ b/misc/cgo/testsanitizers/testdata/asan_unsafe_fail3.go @@ -0,0 +1,21 @@ +// Copyright 2022 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 main + +import ( + "fmt" + "unsafe" +) + +func main() { + a := 1 + b := 2 + // The local variables. + // When -asan is enabled, the unsafe.Pointer(&a) conversion is escaping. + var p *int = (*int)(unsafe.Add(unsafe.Pointer(&a), 1*unsafe.Sizeof(int(1)))) + *p = 20 // BOOM + d := a + b + fmt.Println(d) +} diff --git a/src/builtin/builtin.go b/src/builtin/builtin.go index 5657be4564..8997902f8f 100644 --- a/src/builtin/builtin.go +++ b/src/builtin/builtin.go @@ -3,10 +3,10 @@ // license that can be found in the LICENSE file. /* - Package builtin provides documentation for Go's predeclared identifiers. - The items documented here are not actually in package builtin - but their descriptions here allow godoc to present documentation - for the language's special identifiers. +Package builtin provides documentation for Go's predeclared identifiers. +The items documented here are not actually in package builtin +but their descriptions here allow godoc to present documentation +for the language's special identifiers. */ package builtin diff --git a/src/bytes/buffer.go b/src/bytes/buffer.go index 549b077708..0bacbda164 100644 --- a/src/bytes/buffer.go +++ b/src/bytes/buffer.go @@ -138,10 +138,8 @@ func (b *Buffer) grow(n int) int { } else if c > maxInt-c-n { panic(ErrTooLarge) } else { - // Not enough space anywhere, we need to allocate. - buf := makeSlice(2*c + n) - copy(buf, b.buf[b.off:]) - b.buf = buf + // Add b.off to account for b.buf[:b.off] being sliced off the front. + b.buf = growSlice(b.buf[b.off:], b.off+n) } // Restore b.off and len(b.buf). b.off = 0 @@ -217,16 +215,31 @@ func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) { } } -// makeSlice allocates a slice of size n. If the allocation fails, it panics -// with ErrTooLarge. -func makeSlice(n int) []byte { - // If the make fails, give a known error. +// growSlice grows b by n, preserving the original content of b. +// If the allocation fails, it panics with ErrTooLarge. +func growSlice(b []byte, n int) []byte { defer func() { if recover() != nil { panic(ErrTooLarge) } }() - return make([]byte, n) + // TODO(http://golang.org/issue/51462): We should rely on the append-make + // pattern so that the compiler can call runtime.growslice. For example: + // return append(b, make([]byte, n)...) + // This avoids unnecessary zero-ing of the first len(b) bytes of the + // allocated slice, but this pattern causes b to escape onto the heap. + // + // Instead use the append-make pattern with a nil slice to ensure that + // we allocate buffers rounded up to the closest size class. + c := len(b) + n // ensure enough space for n elements + if c < 2*cap(b) { + // The growth rate has historically always been 2x. In the future, + // we could rely purely on append to determine the growth rate. + c = 2 * cap(b) + } + b2 := append([]byte(nil), make([]byte, c)...) + copy(b2, b) + return b2[:len(b)] } // WriteTo writes data to w until the buffer is drained or an error occurs. diff --git a/src/bytes/buffer_test.go b/src/bytes/buffer_test.go index 9c9b7440ff..c0855007c1 100644 --- a/src/bytes/buffer_test.go +++ b/src/bytes/buffer_test.go @@ -672,3 +672,18 @@ func BenchmarkBufferFullSmallReads(b *testing.B) { } } } + +func BenchmarkBufferWriteBlock(b *testing.B) { + block := make([]byte, 1024) + for _, n := range []int{1 << 12, 1 << 16, 1 << 20} { + b.Run(fmt.Sprintf("N%d", n), func(b *testing.B) { + b.ReportAllocs() + for i := 0; i < b.N; i++ { + var bb Buffer + for bb.Len() < n { + bb.Write(block) + } + } + }) + } +} diff --git a/src/bytes/bytes.go b/src/bytes/bytes.go index 41323ad549..e3dab4d035 100644 --- a/src/bytes/bytes.go +++ b/src/bytes/bytes.go @@ -909,7 +909,11 @@ func containsRune(s string, r rune) bool { // Trim returns a subslice of s by slicing off all leading and // trailing UTF-8-encoded code points contained in cutset. func Trim(s []byte, cutset string) []byte { - if len(s) == 0 || cutset == "" { + if len(s) == 0 { + // This is what we've historically done. + return nil + } + if cutset == "" { return s } if len(cutset) == 1 && cutset[0] < utf8.RuneSelf { @@ -924,7 +928,11 @@ func Trim(s []byte, cutset string) []byte { // TrimLeft returns a subslice of s by slicing off all leading // UTF-8-encoded code points contained in cutset. func TrimLeft(s []byte, cutset string) []byte { - if len(s) == 0 || cutset == "" { + if len(s) == 0 { + // This is what we've historically done. + return nil + } + if cutset == "" { return s } if len(cutset) == 1 && cutset[0] < utf8.RuneSelf { @@ -940,6 +948,10 @@ func trimLeftByte(s []byte, c byte) []byte { for len(s) > 0 && s[0] == c { s = s[1:] } + if len(s) == 0 { + // This is what we've historically done. + return nil + } return s } @@ -950,6 +962,10 @@ func trimLeftASCII(s []byte, as *asciiSet) []byte { } s = s[1:] } + if len(s) == 0 { + // This is what we've historically done. + return nil + } return s } @@ -964,6 +980,10 @@ func trimLeftUnicode(s []byte, cutset string) []byte { } s = s[n:] } + if len(s) == 0 { + // This is what we've historically done. + return nil + } return s } diff --git a/src/bytes/bytes_test.go b/src/bytes/bytes_test.go index 3bece6adf0..2e6ab31540 100644 --- a/src/bytes/bytes_test.go +++ b/src/bytes/bytes_test.go @@ -1278,24 +1278,69 @@ var trimTests = []TrimTest{ {"TrimSuffix", "aabb", "b", "aab"}, } +type TrimNilTest struct { + f string + in []byte + arg string + out []byte +} + +var trimNilTests = []TrimNilTest{ + {"Trim", nil, "", nil}, + {"Trim", []byte{}, "", nil}, + {"Trim", []byte{'a'}, "a", nil}, + {"Trim", []byte{'a', 'a'}, "a", nil}, + {"Trim", []byte{'a'}, "ab", nil}, + {"Trim", []byte{'a', 'b'}, "ab", nil}, + {"Trim", []byte("☺"), "☺", nil}, + {"TrimLeft", nil, "", nil}, + {"TrimLeft", []byte{}, "", nil}, + {"TrimLeft", []byte{'a'}, "a", nil}, + {"TrimLeft", []byte{'a', 'a'}, "a", nil}, + {"TrimLeft", []byte{'a'}, "ab", nil}, + {"TrimLeft", []byte{'a', 'b'}, "ab", nil}, + {"TrimLeft", []byte("☺"), "☺", nil}, + {"TrimRight", nil, "", nil}, + {"TrimRight", []byte{}, "", []byte{}}, + {"TrimRight", []byte{'a'}, "a", []byte{}}, + {"TrimRight", []byte{'a', 'a'}, "a", []byte{}}, + {"TrimRight", []byte{'a'}, "ab", []byte{}}, + {"TrimRight", []byte{'a', 'b'}, "ab", []byte{}}, + {"TrimRight", []byte("☺"), "☺", []byte{}}, + {"TrimPrefix", nil, "", nil}, + {"TrimPrefix", []byte{}, "", []byte{}}, + {"TrimPrefix", []byte{'a'}, "a", []byte{}}, + {"TrimPrefix", []byte("☺"), "☺", []byte{}}, + {"TrimSuffix", nil, "", nil}, + {"TrimSuffix", []byte{}, "", []byte{}}, + {"TrimSuffix", []byte{'a'}, "a", []byte{}}, + {"TrimSuffix", []byte("☺"), "☺", []byte{}}, +} + func TestTrim(t *testing.T) { - for _, tc := range trimTests { - name := tc.f - var f func([]byte, string) []byte - var fb func([]byte, []byte) []byte + toFn := func(name string) (func([]byte, string) []byte, func([]byte, []byte) []byte) { switch name { case "Trim": - f = Trim + return Trim, nil case "TrimLeft": - f = TrimLeft + return TrimLeft, nil case "TrimRight": - f = TrimRight + return TrimRight, nil case "TrimPrefix": - fb = TrimPrefix + return nil, TrimPrefix case "TrimSuffix": - fb = TrimSuffix + return nil, TrimSuffix default: t.Errorf("Undefined trim function %s", name) + return nil, nil + } + } + + for _, tc := range trimTests { + name := tc.f + f, fb := toFn(name) + if f == nil && fb == nil { + continue } var actual string if f != nil { @@ -1307,6 +1352,36 @@ func TestTrim(t *testing.T) { t.Errorf("%s(%q, %q) = %q; want %q", name, tc.in, tc.arg, actual, tc.out) } } + + for _, tc := range trimNilTests { + name := tc.f + f, fb := toFn(name) + if f == nil && fb == nil { + continue + } + var actual []byte + if f != nil { + actual = f(tc.in, tc.arg) + } else { + actual = fb(tc.in, []byte(tc.arg)) + } + report := func(s []byte) string { + if s == nil { + return "nil" + } else { + return fmt.Sprintf("%q", s) + } + } + if len(actual) != 0 { + t.Errorf("%s(%s, %q) returned non-empty value", name, report(tc.in), tc.arg) + } else { + actualNil := actual == nil + outNil := tc.out == nil + if actualNil != outNil { + t.Errorf("%s(%s, %q) got nil %t; want nil %t", name, report(tc.in), tc.arg, actualNil, outNil) + } + } + } } type predicate struct { diff --git a/src/cmd/api/goapi.go b/src/cmd/api/goapi.go index 5ae059e4ce..b2a023a9b7 100644 --- a/src/cmd/api/goapi.go +++ b/src/cmd/api/goapi.go @@ -2,7 +2,7 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. -// Binary api computes the exported API of a set of Go packages. +// Api computes the exported API of a set of Go packages. package main import ( @@ -24,6 +24,7 @@ import ( "regexp" "runtime" "sort" + "strconv" "strings" "sync" ) @@ -33,21 +34,24 @@ func goCmd() string { if runtime.GOOS == "windows" { exeSuffix = ".exe" } - path := filepath.Join(runtime.GOROOT(), "bin", "go"+exeSuffix) - if _, err := os.Stat(path); err == nil { - return path + if goroot := build.Default.GOROOT; goroot != "" { + path := filepath.Join(goroot, "bin", "go"+exeSuffix) + if _, err := os.Stat(path); err == nil { + return path + } } return "go" } // Flags var ( - checkFile = flag.String("c", "", "optional comma-separated filename(s) to check API against") - allowNew = flag.Bool("allow_new", true, "allow API additions") - exceptFile = flag.String("except", "", "optional filename of packages that are allowed to change without triggering a failure in the tool") - nextFile = flag.String("next", "", "optional filename of tentative upcoming API features for the next release. This file can be lazily maintained. It only affects the delta warnings from the -c file printed on success.") - verbose = flag.Bool("v", false, "verbose debugging") - forceCtx = flag.String("contexts", "", "optional comma-separated list of -[-cgo] to override default contexts.") + checkFiles = flag.String("c", "", "optional comma-separated filename(s) to check API against") + requireApproval = flag.String("approval", "", "require approvals in comma-separated list of `files`") + allowNew = flag.Bool("allow_new", true, "allow API additions") + exceptFile = flag.String("except", "", "optional filename of packages that are allowed to change without triggering a failure in the tool") + nextFiles = flag.String("next", "", "comma-separated list of `files` for upcoming API features for the next release. These files can be lazily maintained. They only affects the delta warnings from the -c file printed on success.") + verbose = flag.Bool("v", false, "verbose debugging") + forceCtx = flag.String("contexts", "", "optional comma-separated list of -[-cgo] to override default contexts.") ) // contexts are the default contexts which are scanned, unless @@ -125,10 +129,14 @@ var internalPkg = regexp.MustCompile(`(^|/)internal($|/)`) func main() { flag.Parse() + if build.Default.GOROOT == "" { + log.Fatalf("GOROOT not found. (If binary was built with -trimpath, $GOROOT must be set.)") + } + if !strings.Contains(runtime.Version(), "weekly") && !strings.Contains(runtime.Version(), "devel") { - if *nextFile != "" { - fmt.Printf("Go version is %q, ignoring -next %s\n", runtime.Version(), *nextFile) - *nextFile = "" + if *nextFiles != "" { + fmt.Printf("Go version is %q, ignoring -next %s\n", runtime.Version(), *nextFiles) + *nextFiles = "" } } @@ -201,7 +209,7 @@ func main() { bw := bufio.NewWriter(os.Stdout) defer bw.Flush() - if *checkFile == "" { + if *checkFiles == "" { sort.Strings(features) for _, f := range features { fmt.Fprintln(bw, f) @@ -210,10 +218,15 @@ func main() { } var required []string - for _, file := range strings.Split(*checkFile, ",") { + for _, file := range strings.Split(*checkFiles, ",") { required = append(required, fileFeatures(file)...) } - optional := fileFeatures(*nextFile) + var optional []string + if *nextFiles != "" { + for _, file := range strings.Split(*nextFiles, ",") { + optional = append(optional, fileFeatures(file)...) + } + } exception := fileFeatures(*exceptFile) fail = !compareAPI(bw, features, required, optional, exception, *allowNew) } @@ -340,6 +353,13 @@ func fileFeatures(filename string) []string { if filename == "" { return nil } + needApproval := false + for _, name := range strings.Split(*requireApproval, ",") { + if filename == name { + needApproval = true + break + } + } bs, err := os.ReadFile(filename) if err != nil { log.Fatalf("Error reading file %s: %v", filename, err) @@ -348,11 +368,23 @@ func fileFeatures(filename string) []string { s = aliasReplacer.Replace(s) lines := strings.Split(s, "\n") var nonblank []string - for _, line := range lines { + for i, line := range lines { line = strings.TrimSpace(line) - if line != "" && !strings.HasPrefix(line, "#") { - nonblank = append(nonblank, line) + if line == "" || strings.HasPrefix(line, "#") { + continue } + if needApproval { + feature, approval, ok := strings.Cut(line, "#") + if !ok { + log.Fatalf("%s:%d: missing proposal approval\n", filename, i+1) + } + _, err := strconv.Atoi(approval) + if err != nil { + log.Fatalf("%s:%d: malformed proposal approval #%s\n", filename, i+1, approval) + } + line = strings.TrimSpace(feature) + } + nonblank = append(nonblank, line) } return nonblank } diff --git a/src/cmd/api/goapi_test.go b/src/cmd/api/goapi_test.go index 16e0058e5e..862ab183b2 100644 --- a/src/cmd/api/goapi_test.go +++ b/src/cmd/api/goapi_test.go @@ -9,6 +9,7 @@ import ( "flag" "fmt" "go/build" + "internal/testenv" "os" "path/filepath" "sort" @@ -22,6 +23,7 @@ func TestMain(m *testing.M) { for _, c := range contexts { c.Compiler = build.Default.Compiler } + build.Default.GOROOT = testenv.GOROOT(nil) // Warm up the import cache in parallel. var wg sync.WaitGroup diff --git a/src/cmd/api/run.go b/src/cmd/api/run.go index 1b94a1b883..3ceaae6b89 100644 --- a/src/cmd/api/run.go +++ b/src/cmd/api/run.go @@ -18,6 +18,7 @@ import ( "os" "path/filepath" "runtime" + "strconv" "strings" ) @@ -41,51 +42,65 @@ func main() { if goroot == "" { log.Fatal("No $GOROOT set.") } + if err := os.Chdir(filepath.Join(goroot, "api")); err != nil { + log.Fatal(err) + } - apiDir := filepath.Join(goroot, "api") - out, err := exec.Command(goCmd(), "tool", "api", - "-c", findAPIDirFiles(apiDir), - allowNew(apiDir), - "-next", filepath.Join(apiDir, "next.txt"), - "-except", filepath.Join(apiDir, "except.txt")).CombinedOutput() + files, err := filepath.Glob("go1*.txt") + if err != nil { + log.Fatal(err) + } + next, err := filepath.Glob(filepath.Join("next", "*.txt")) + if err != nil { + log.Fatal(err) + } + cmd := exec.Command(goCmd(), "tool", "api", + "-c", strings.Join(files, ","), + "-approval", strings.Join(append(approvalNeeded(files), next...), ","), + allowNew(), + "-next", strings.Join(next, ","), + "-except", "except.txt", + ) + out, err := cmd.CombinedOutput() if err != nil { log.Fatalf("Error running API checker: %v\n%s", err, out) } fmt.Print(string(out)) } -// findAPIDirFiles returns a comma-separated list of Go API files -// (go1.txt, go1.1.txt, etc.) located in apiDir. -func findAPIDirFiles(apiDir string) string { - dir, err := os.Open(apiDir) - if err != nil { - log.Fatal(err) - } - defer dir.Close() - fs, err := dir.Readdirnames(-1) - if err != nil { - log.Fatal(err) - } - var apiFiles []string - for _, fn := range fs { - if strings.HasPrefix(fn, "go1") { - apiFiles = append(apiFiles, filepath.Join(apiDir, fn)) +func approvalNeeded(files []string) []string { + var out []string + for _, f := range files { + name := filepath.Base(f) + if name == "go1.txt" { + continue + } + minor := strings.TrimSuffix(strings.TrimPrefix(name, "go1."), ".txt") + n, err := strconv.Atoi(minor) + if err != nil { + log.Fatalf("unexpected api file: %v", f) + } + if n >= 19 { // approvals started being tracked in Go 1.19 + out = append(out, f) } } - return strings.Join(apiFiles, ",") + return out } // allowNew returns the -allow_new flag to use for the 'go tool api' invocation. -func allowNew(apiDir string) string { +func allowNew() string { + // Experiment for Go 1.19: always require api file updates. + return "-allow_new=false" + // Verify that the api/go1.n.txt for previous Go version exists. // It definitely should, otherwise it's a signal that the logic below may be outdated. - if _, err := os.Stat(filepath.Join(apiDir, fmt.Sprintf("go1.%d.txt", goversion.Version-1))); err != nil { + if _, err := os.Stat(fmt.Sprintf("go1.%d.txt", goversion.Version-1)); err != nil { log.Fatalln("Problem with api file for previous release:", err) } // See whether the api/go1.n.txt for this Go version has been created. // (As of April 2021, it gets created during the release of the first Beta.) - _, err := os.Stat(filepath.Join(apiDir, fmt.Sprintf("go1.%d.txt", goversion.Version))) + _, err := os.Stat(fmt.Sprintf("go1.%d.txt", goversion.Version)) if errors.Is(err, fs.ErrNotExist) { // It doesn't exist, so we're in development or before Beta 1. // At this stage, unmentioned API additions are deemed okay. diff --git a/src/cmd/asm/internal/arch/ppc64.go b/src/cmd/asm/internal/arch/ppc64.go index 3139665ba5..616e189b1a 100644 --- a/src/cmd/asm/internal/arch/ppc64.go +++ b/src/cmd/asm/internal/arch/ppc64.go @@ -15,7 +15,7 @@ import ( func jumpPPC64(word string) bool { switch word { - case "BC", "BCL", "BEQ", "BGE", "BGT", "BL", "BLE", "BLT", "BNE", "BR", "BVC", "BVS", "CALL", "JMP": + case "BC", "BCL", "BEQ", "BGE", "BGT", "BL", "BLE", "BLT", "BNE", "BR", "BVC", "BVS", "BDNZ", "BDZ", "CALL", "JMP": return true } return false diff --git a/src/cmd/asm/internal/asm/testdata/arm64.s b/src/cmd/asm/internal/asm/testdata/arm64.s index a4b56b0696..8a7dd299aa 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64.s +++ b/src/cmd/asm/internal/asm/testdata/arm64.s @@ -241,6 +241,10 @@ TEXT foo(SB), DUPOK|NOSPLIT, $-8 FADDS F2, F3, F4 // 6428221e FADDD F1, F2 // 4228611e VDUP V19.S[0], V17.S4 // 7106044e + VTRN1 V3.D2, V2.D2, V20.D2 // 5428c34e + VTRN2 V3.D2, V2.D2, V21.D2 // 5568c34e + VTRN1 V5.D2, V4.D2, V22.D2 // 9628c54e + VTRN2 V5.D2, V4.D2, V23.D2 // 9768c54e // special diff --git a/src/cmd/asm/internal/asm/testdata/arm64error.s b/src/cmd/asm/internal/asm/testdata/arm64error.s index 3d3de1d9b1..033c4cda6c 100644 --- a/src/cmd/asm/internal/asm/testdata/arm64error.s +++ b/src/cmd/asm/internal/asm/testdata/arm64error.s @@ -417,8 +417,8 @@ TEXT errors(SB),$0 CASPD (R2, R4), (R2), (R8, R9) // ERROR "source register pair must be contiguous" CASPD (R2, R3), (R2), (R8, R10) // ERROR "destination register pair must be contiguous" ADD R1>>2, RSP, R3 // ERROR "illegal combination" - ADDS R2<<3, R3, RSP // ERROR "unexpected SP reference" - CMP R1<<5, RSP // ERROR "the left shift amount out of range 0 to 4" + ADDS R2<<3, R3, RSP // ERROR "illegal destination register" + CMP R1<<5, RSP // ERROR "shift amount out of range 0 to 4" MOVD.P y+8(FP), R1 // ERROR "illegal combination" MOVD.W x-8(SP), R1 // ERROR "illegal combination" LDP.P x+8(FP), (R0, R1) // ERROR "illegal combination" diff --git a/src/cmd/asm/internal/asm/testdata/ppc64.s b/src/cmd/asm/internal/asm/testdata/ppc64.s index c140fd025a..5452668791 100644 --- a/src/cmd/asm/internal/asm/testdata/ppc64.s +++ b/src/cmd/asm/internal/asm/testdata/ppc64.s @@ -751,17 +751,23 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0 MOVD XER, R3 // 7c6102a6 MOVFL CR3, CR1 // 4c8c0000 - MOVW CR0, R1 // 7c380026 - MOVW CR7, R1 // 7c301026 - MOVW CR, R1 // 7c200026 + MOVW CR0, R1 // 7c380026 + MOVW CR7, R1 // 7c301026 + MOVW CR, R1 // 7c200026 - MOVW R1, CR // 7c2ff120 - MOVFL R1, CR // 7c2ff120 - MOVW R1, CR2 // 7c320120 - MOVFL R1, CR2 // 7c320120 - MOVFL R1, $255 // 7c2ff120 - MOVFL R1, $1 // 7c301120 - MOVFL R1, $128 // 7c380120 - MOVFL R1, $3 // 7c203120 + MOVW R1, CR // 7c2ff120 + MOVFL R1, CR // 7c2ff120 + MOVW R1, CR2 // 7c320120 + MOVFL R1, CR2 // 7c320120 + MOVFL R1, $255 // 7c2ff120 + MOVFL R1, $1 // 7c301120 + MOVFL R1, $128 // 7c380120 + MOVFL R1, $3 // 7c203120 + + // Verify supported bdnz/bdz encodings. + BC 16,0,0(PC) // BC $16,R0,0(PC) // 42000000 + BDNZ 0(PC) // 42000000 + BDZ 0(PC) // 42400000 + BC 18,0,0(PC) // BC $18,R0,0(PC) // 42400000 RET diff --git a/src/cmd/asm/internal/flags/flags.go b/src/cmd/asm/internal/flags/flags.go index 607166e664..273d422370 100644 --- a/src/cmd/asm/internal/flags/flags.go +++ b/src/cmd/asm/internal/flags/flags.go @@ -30,6 +30,7 @@ var ( var DebugFlags struct { MayMoreStack string `help:"call named function before all stack growth checks"` + PCTab string `help:"print named pc-value table\nOne of: pctospadj, pctofile, pctoline, pctoinline, pctopcdata"` } var ( diff --git a/src/cmd/asm/internal/lex/input.go b/src/cmd/asm/internal/lex/input.go index e373ae817e..276b4b0dcd 100644 --- a/src/cmd/asm/internal/lex/input.go +++ b/src/cmd/asm/internal/lex/input.go @@ -50,7 +50,7 @@ func predefine(defines flags.MultiFlag) map[string]*Macro { // Set macros for GOEXPERIMENTs so we can easily switch // runtime assembly code based on them. if *flags.CompilingRuntime { - for _, exp := range buildcfg.EnabledExperiments() { + for _, exp := range buildcfg.Experiment.Enabled() { // Define macro. name := "GOEXPERIMENT_" + exp macros[name] = &Macro{ diff --git a/src/cmd/asm/main.go b/src/cmd/asm/main.go index 3683527f5b..6a25fd426b 100644 --- a/src/cmd/asm/main.go +++ b/src/cmd/asm/main.go @@ -43,6 +43,7 @@ func main() { ctxt.Flag_linkshared = *flags.Linkshared ctxt.Flag_shared = *flags.Shared || *flags.Dynlink ctxt.Flag_maymorestack = flags.DebugFlags.MayMoreStack + ctxt.Debugpcln = flags.DebugFlags.PCTab ctxt.IsAsm = true ctxt.Pkgpath = *flags.Importpath switch *flags.Spectre { diff --git a/src/cmd/compile/abi-internal.md b/src/cmd/compile/abi-internal.md index 53eaa84d54..be47e9a31b 100644 --- a/src/cmd/compile/abi-internal.md +++ b/src/cmd/compile/abi-internal.md @@ -1,5 +1,7 @@ # Go internal ABI specification +Self-link: [go.dev/s/regabi](https://go.dev/s/regabi) + This document describes Go’s internal application binary interface (ABI), known as ABIInternal. Go's ABI defines the layout of data in memory and the conventions for @@ -730,6 +732,57 @@ The floating point status and control register (FPSCR) is initialized to 0 by the kernel at startup of the Go program and not changed by the Go generated code. +### riscv64 architecture + +The riscv64 architecture uses X10 – X17, X8, X9, X18 – X23 for integer arguments +and results. + +It uses F10 – F17, F8, F9, F18 – F23 for floating-point arguments and results. + +Special-purpose registers used within Go generated code and Go +assembly code are as follows: + +| Register | Call meaning | Return meaning | Body meaning | +| --- | --- | --- | --- | +| X0 | Zero value | Same | Same | +| X1 | Link register | Link register | Scratch | +| X2 | Stack pointer | Same | Same | +| X3 | Global pointer | Same | Used by dynamic linker | +| X4 | TLS (thread pointer) | TLS | Scratch | +| X24,X25 | Scratch | Scratch | Used by duffcopy, duffzero | +| X26 | Closure context pointer | Scratch | Scratch | +| X27 | Current goroutine | Same | Same | +| X31 | Scratch | Scratch | Scratch | + +*Rationale*: These register meanings are compatible with Go’s +stack-based calling convention. Context register X20 will change to X26, +duffcopy, duffzero register will change to X24, X25 before this register ABI been adopted. +X10 – X17, X8, X9, X18 – X23, is the same order as A0 – A7, S0 – S7 in platform ABI. +F10 – F17, F8, F9, F18 – F23, is the same order as FA0 – FA7, FS0 – FS7 in platform ABI. +X8 – X23, F8 – F15 are used for compressed instruction (RVC) which will benefit code size in the future. + +#### Stack layout + +The stack pointer, X2, grows down and is aligned to 8 bytes. + +A function's stack frame, after the frame is created, is laid out as +follows: + + +------------------------------+ + | ... locals ... | + | ... outgoing arguments ... | + | return PC | ← X2 points to + +------------------------------+ ↓ lower addresses + +The "return PC" is loaded to the link register, X1, as part of the +riscv64 `CALL` operation. + +#### Flags + +The riscv64 has Zicsr extension for control and status register (CSR) and +treated as scratch register. +All bits in CSR are system flags and are not modified by Go. + ## Future directions ### Spill path improvements diff --git a/src/cmd/compile/internal/amd64/versions_test.go b/src/cmd/compile/internal/amd64/versions_test.go index a21e5f2e6f..6c2617d844 100644 --- a/src/cmd/compile/internal/amd64/versions_test.go +++ b/src/cmd/compile/internal/amd64/versions_test.go @@ -10,6 +10,7 @@ import ( "bufio" "debug/elf" "debug/macho" + "errors" "fmt" "internal/testenv" "io" @@ -117,9 +118,12 @@ func clobber(t *testing.T, src string, dst *os.File, opcodes map[string]bool) { var err error disasm, err = cmd.StdoutPipe() if err != nil { - t.Skipf("can't run test due to missing objdump: %s", err) + t.Fatal(err) } if err := cmd.Start(); err != nil { + if errors.Is(err, exec.ErrNotFound) { + t.Skipf("can't run test due to missing objdump: %s", err) + } t.Fatal(err) } re = regexp.MustCompile(`^\s*([0-9a-f]+):\s*((?:[0-9a-f][0-9a-f] )+)\s*([a-z0-9]+)`) diff --git a/src/cmd/compile/internal/base/flag.go b/src/cmd/compile/internal/base/flag.go index 6377091ce0..49e004cf18 100644 --- a/src/cmd/compile/internal/base/flag.go +++ b/src/cmd/compile/internal/base/flag.go @@ -16,6 +16,7 @@ import ( "runtime" "strings" + "cmd/internal/obj" "cmd/internal/objabi" "cmd/internal/sys" ) @@ -57,7 +58,7 @@ type CmdFlags struct { E CountFlag "help:\"debug symbol export\"" I func(string) "help:\"add `directory` to import search path\"" K CountFlag "help:\"debug missing line numbers\"" - L CountFlag "help:\"show full file names in error messages\"" + L CountFlag "help:\"also show actual source file names in error messages for positions affected by //line directives\"" N CountFlag "help:\"disable optimizations\"" S CountFlag "help:\"print assembly listing\"" // V is added by objabi.AddVersionFlag @@ -201,6 +202,10 @@ func ParseFlags() { Exit(2) } + if *Flag.LowerP == "" { + *Flag.LowerP = obj.UnlinkablePkg + } + if Flag.LowerO == "" { p := flag.Arg(0) if i := strings.LastIndex(p, "/"); i >= 0 { diff --git a/src/cmd/compile/internal/deadcode/deadcode.go b/src/cmd/compile/internal/deadcode/deadcode.go index 65a48b6803..c37a5a6990 100644 --- a/src/cmd/compile/internal/deadcode/deadcode.go +++ b/src/cmd/compile/internal/deadcode/deadcode.go @@ -163,4 +163,5 @@ func markHiddenClosureDead(n ir.Node) { if clo.Func.IsHiddenClosure() { clo.Func.SetIsDeadcodeClosure(true) } + ir.VisitList(clo.Func.Body, markHiddenClosureDead) } diff --git a/src/cmd/compile/internal/escape/escape.go b/src/cmd/compile/internal/escape/escape.go index bc6f7c93bb..4713ecddca 100644 --- a/src/cmd/compile/internal/escape/escape.go +++ b/src/cmd/compile/internal/escape/escape.go @@ -297,14 +297,6 @@ func (b *batch) finish(fns []*ir.Func) { // TODO(mdempsky): Update tests to expect this. goDeferWrapper := n.Op() == ir.OCLOSURE && n.(*ir.ClosureExpr).Func.Wrapper() - if n.Op() == ir.OCONVIDATA && n.(*ir.ConvExpr).NonEscaping { - // The allocation for the data word of an interface is known to not escape. - // See issue 50182. - // (But we do still need to process that allocation, as pointers inside - // the data word may escape.) - loc.escapes = false - } - if loc.escapes { if n.Op() == ir.ONAME { if base.Flag.CompilingRuntime { diff --git a/src/cmd/compile/internal/escape/expr.go b/src/cmd/compile/internal/escape/expr.go index ced90a47bc..9c3e09d10d 100644 --- a/src/cmd/compile/internal/escape/expr.go +++ b/src/cmd/compile/internal/escape/expr.go @@ -100,9 +100,9 @@ func (e *escape) exprSkipInit(k hole, n ir.Node) { case ir.OCONV, ir.OCONVNOP: n := n.(*ir.ConvExpr) - if ir.ShouldCheckPtr(e.curfn, 2) && n.Type().IsUnsafePtr() && n.X.Type().IsPtr() { - // When -d=checkptr=2 is enabled, treat - // conversions to unsafe.Pointer as an + if (ir.ShouldCheckPtr(e.curfn, 2) || ir.ShouldAsanCheckPtr(e.curfn)) && n.Type().IsUnsafePtr() && n.X.Type().IsPtr() { + // When -d=checkptr=2 or -asan is enabled, + // treat conversions to unsafe.Pointer as an // escaping operation. This allows better // runtime instrumentation, since we can more // easily detect object boundaries on the heap diff --git a/src/cmd/compile/internal/gc/main.go b/src/cmd/compile/internal/gc/main.go index 5a9a889894..1f547130ad 100644 --- a/src/cmd/compile/internal/gc/main.go +++ b/src/cmd/compile/internal/gc/main.go @@ -188,6 +188,9 @@ func Main(archInit func(*ssagen.ArchInfo)) { // Parse and typecheck input. noder.LoadPackage(flag.Args()) + if base.Ctxt.Pkgpath == obj.UnlinkablePkg && types.LocalPkg.Name == "main" { + base.Ctxt.Pkgpath = "main" + } dwarfgen.RecordPackageName() diff --git a/src/cmd/compile/internal/importer/gcimporter_test.go b/src/cmd/compile/internal/importer/gcimporter_test.go index 5d80db244b..9fecf742fb 100644 --- a/src/cmd/compile/internal/importer/gcimporter_test.go +++ b/src/cmd/compile/internal/importer/gcimporter_test.go @@ -8,6 +8,7 @@ import ( "bytes" "cmd/compile/internal/types2" "fmt" + "go/build" "internal/goexperiment" "internal/testenv" "os" @@ -19,6 +20,11 @@ import ( "time" ) +func TestMain(m *testing.M) { + build.Default.GOROOT = testenv.GOROOT(nil) + os.Exit(m.Run()) +} + // skipSpecialPlatforms causes the test to be skipped for platforms where // builders (build.golang.org) don't have access to compiled packages for // import. @@ -38,7 +44,7 @@ func compile(t *testing.T, dirname, filename, outdirname string) string { } basename := filepath.Base(filename) outname := filepath.Join(outdirname, basename[:len(basename)-2]+"o") - cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", outname, filename) + cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=p", "-o", outname, filename) cmd.Dir = dirname out, err := cmd.CombinedOutput() if err != nil { @@ -62,7 +68,7 @@ func testPath(t *testing.T, path, srcDir string) *types2.Package { const maxTime = 30 * time.Second func testDir(t *testing.T, dir string, endTime time.Time) (nimports int) { - dirname := filepath.Join(runtime.GOROOT(), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir) + dirname := filepath.Join(testenv.GOROOT(t), "pkg", runtime.GOOS+"_"+runtime.GOARCH, dir) list, err := os.ReadDir(dirname) if err != nil { t.Fatalf("testDir(%s): %s", dirname, err) diff --git a/src/cmd/compile/internal/importer/iimport.go b/src/cmd/compile/internal/importer/iimport.go index bed4fbb016..576036bdce 100644 --- a/src/cmd/compile/internal/importer/iimport.go +++ b/src/cmd/compile/internal/importer/iimport.go @@ -53,7 +53,7 @@ const ( ) type ident struct { - pkg string + pkg *types2.Package name string } @@ -402,7 +402,7 @@ func (r *importReader) obj(name string) { t := types2.NewTypeParam(tn, nil) // To handle recursive references to the typeparam within its // bound, save the partial type in tparamIndex before reading the bounds. - id := ident{r.currPkg.Name(), name} + id := ident{r.currPkg, name} r.p.tparamIndex[id] = t var implicit bool @@ -687,7 +687,7 @@ func (r *importReader) doType(base *types2.Named) types2.Type { errorf("unexpected type param type") } pkg, name := r.qualifiedIdent() - id := ident{pkg.Name(), name} + id := ident{pkg, name} if t, ok := r.p.tparamIndex[id]; ok { // We're already in the process of importing this typeparam. return t diff --git a/src/cmd/compile/internal/inline/inl.go b/src/cmd/compile/internal/inline/inl.go index 716a7fbcd9..be01914d08 100644 --- a/src/cmd/compile/internal/inline/inl.go +++ b/src/cmd/compile/internal/inline/inl.go @@ -358,8 +358,7 @@ func (v *hairyVisitor) doNode(n ir.Node) bool { return true } - case ir.OSELECT, - ir.OGO, + case ir.OGO, ir.ODEFER, ir.ODCLTYPE, // can't print yet ir.OTAILCALL: @@ -1310,7 +1309,7 @@ func (subst *inlsubst) node(n ir.Node) ir.Node { ir.EditChildren(m, subst.edit) if subst.newclofn == nil { - // Translate any label on FOR, RANGE loops or SWITCH + // Translate any label on FOR, RANGE loops, SWITCH or SELECT switch m.Op() { case ir.OFOR: m := m.(*ir.ForStmt) @@ -1326,8 +1325,12 @@ func (subst *inlsubst) node(n ir.Node) ir.Node { m := m.(*ir.SwitchStmt) m.Label = translateLabel(m.Label) return m - } + case ir.OSELECT: + m := m.(*ir.SelectStmt) + m.Label = translateLabel(m.Label) + return m + } } switch m := m.(type) { diff --git a/src/cmd/compile/internal/ir/expr.go b/src/cmd/compile/internal/ir/expr.go index 156fe96493..82132005f9 100644 --- a/src/cmd/compile/internal/ir/expr.go +++ b/src/cmd/compile/internal/ir/expr.go @@ -186,14 +186,6 @@ type ClosureExpr struct { IsGoWrap bool // whether this is wrapper closure of a go statement } -// Deprecated: Use NewClosureFunc instead. -func NewClosureExpr(pos src.XPos, fn *Func) *ClosureExpr { - n := &ClosureExpr{Func: fn} - n.op = OCLOSURE - n.pos = pos - return n -} - // A CompLitExpr is a composite literal Type{Vals}. // Before type-checking, the type is Ntype. type CompLitExpr struct { @@ -242,7 +234,6 @@ func NewConstExpr(val constant.Value, orig Node) Node { n.orig = orig n.SetType(orig.Type()) n.SetTypecheck(orig.Typecheck()) - n.SetDiag(orig.Diag()) return n } @@ -253,8 +244,7 @@ func (n *ConstExpr) Val() constant.Value { return n.val } // It may end up being a value or a type. type ConvExpr struct { miniExpr - X Node - NonEscaping bool // The allocation needed for the conversion to interface is known not to escape + X Node } func NewConvExpr(pos src.XPos, op Op, typ *types.Type, x Node) *ConvExpr { @@ -973,6 +963,12 @@ var IsIntrinsicCall = func(*CallExpr) bool { return false } // lvalue expression is for OSLICE and OAPPEND optimizations, and it // is correct in those settings. func SameSafeExpr(l Node, r Node) bool { + for l.Op() == OCONVNOP { + l = l.(*ConvExpr).X + } + for r.Op() == OCONVNOP { + r = r.(*ConvExpr).X + } if l.Op() != r.Op() || !types.Identical(l.Type(), r.Type()) { return false } @@ -996,11 +992,6 @@ func SameSafeExpr(l Node, r Node) bool { r := r.(*UnaryExpr) return SameSafeExpr(l.X, r.X) - case OCONVNOP: - l := l.(*ConvExpr) - r := r.(*ConvExpr) - return SameSafeExpr(l.X, r.X) - case OCONV: l := l.(*ConvExpr) r := r.(*ConvExpr) @@ -1035,6 +1026,12 @@ func ShouldCheckPtr(fn *Func, level int) bool { return base.Debug.Checkptr >= level && fn.Pragma&NoCheckPtr == 0 } +// ShouldAsanCheckPtr reports whether pointer checking should be enabled for +// function fn when -asan is enabled. +func ShouldAsanCheckPtr(fn *Func) bool { + return base.Flag.ASan && fn.Pragma&NoCheckPtr == 0 +} + // IsReflectHeaderDataField reports whether l is an expression p.Data // where p has type reflect.SliceHeader or reflect.StringHeader. func IsReflectHeaderDataField(l Node) bool { diff --git a/src/cmd/compile/internal/ir/func.go b/src/cmd/compile/internal/ir/func.go index 29c77444a2..a9a7f19d3f 100644 --- a/src/cmd/compile/internal/ir/func.go +++ b/src/cmd/compile/internal/ir/func.go @@ -50,7 +50,6 @@ import ( type Func struct { miniNode Body Nodes - Iota int64 Nname *Name // ONAME node OClosure *ClosureExpr // OCLOSURE node @@ -140,7 +139,6 @@ func NewFunc(pos src.XPos) *Func { f := new(Func) f.pos = pos f.op = ODCLFUNC - f.Iota = -1 // Most functions are ABIInternal. The importer or symabis // pass may override this. f.ABI = obj.ABIInternal @@ -370,7 +368,9 @@ func NewClosureFunc(pos src.XPos, hidden bool) *Func { fn.Nname.Func = fn fn.Nname.Defn = fn - fn.OClosure = NewClosureExpr(pos, fn) + fn.OClosure = &ClosureExpr{Func: fn} + fn.OClosure.op = OCLOSURE + fn.OClosure.pos = pos return fn } diff --git a/src/cmd/compile/internal/ir/mini.go b/src/cmd/compile/internal/ir/mini.go index eeb74081fb..801a48a78e 100644 --- a/src/cmd/compile/internal/ir/mini.go +++ b/src/cmd/compile/internal/ir/mini.go @@ -54,10 +54,8 @@ func (n *miniNode) Esc() uint16 { return n.esc } func (n *miniNode) SetEsc(x uint16) { n.esc = x } const ( - miniWalkdefShift = 0 // TODO(mdempsky): Move to Name.flags. - miniTypecheckShift = 2 - miniDiag = 1 << 4 - miniWalked = 1 << 5 // to prevent/catch re-walking + miniTypecheckShift = 0 + miniWalked = 1 << 2 // to prevent/catch re-walking ) func (n *miniNode) Typecheck() uint8 { return n.bits.get2(miniTypecheckShift) } @@ -68,9 +66,6 @@ func (n *miniNode) SetTypecheck(x uint8) { n.bits.set2(miniTypecheckShift, x) } -func (n *miniNode) Diag() bool { return n.bits&miniDiag != 0 } -func (n *miniNode) SetDiag(x bool) { n.bits.set(miniDiag, x) } - func (n *miniNode) Walked() bool { return n.bits&miniWalked != 0 } func (n *miniNode) SetWalked(x bool) { n.bits.set(miniWalked, x) } diff --git a/src/cmd/compile/internal/ir/name.go b/src/cmd/compile/internal/ir/name.go index f522d3e76a..183aa6db7c 100644 --- a/src/cmd/compile/internal/ir/name.go +++ b/src/cmd/compile/internal/ir/name.go @@ -166,14 +166,6 @@ func NewNameAt(pos src.XPos, sym *types.Sym) *Name { return newNameAt(pos, ONAME, sym) } -// NewIota returns a new OIOTA Node. -func NewIota(pos src.XPos, sym *types.Sym) *Name { - if sym == nil { - base.Fatalf("NewIota nil") - } - return newNameAt(pos, OIOTA, sym) -} - // NewDeclNameAt returns a new Name associated with symbol s at position pos. // The caller is responsible for setting Curfn. func NewDeclNameAt(pos src.XPos, op Op, sym *types.Sym) *Name { @@ -223,15 +215,6 @@ func (n *Name) SetOffset(x int64) { } func (n *Name) FrameOffset() int64 { return n.Offset_ } func (n *Name) SetFrameOffset(x int64) { n.Offset_ = x } -func (n *Name) Iota() int64 { return n.Offset_ } -func (n *Name) SetIota(x int64) { n.Offset_ = x } -func (n *Name) Walkdef() uint8 { return n.bits.get2(miniWalkdefShift) } -func (n *Name) SetWalkdef(x uint8) { - if x > 3 { - panic(fmt.Sprintf("cannot SetWalkdef %d", x)) - } - n.bits.set2(miniWalkdefShift, x) -} func (n *Name) Linksym() *obj.LSym { return n.sym.Linksym() } func (n *Name) LinksymABI(abi obj.ABI) *obj.LSym { return n.sym.LinksymABI(abi) } diff --git a/src/cmd/compile/internal/ir/node.go b/src/cmd/compile/internal/ir/node.go index e4cff85136..5e5868abb2 100644 --- a/src/cmd/compile/internal/ir/node.go +++ b/src/cmd/compile/internal/ir/node.go @@ -46,8 +46,6 @@ type Node interface { // Storage for analysis passes. Esc() uint16 SetEsc(x uint16) - Diag() bool - SetDiag(x bool) // Typecheck values: // 0 means the node is not typechecked @@ -240,7 +238,6 @@ const ( ORECV // <-X ORUNESTR // Type(X) (Type is string, X is rune) OSELRECV2 // like OAS2: Lhs = Rhs where len(Lhs)=2, len(Rhs)=1, Rhs[0].Op = ORECV (appears as .Var of OCASE) - OIOTA // iota OREAL // real(X) OIMAG // imag(X) OCOMPLEX // complex(X, Y) diff --git a/src/cmd/compile/internal/ir/op_string.go b/src/cmd/compile/internal/ir/op_string.go index f623735f6d..14eb84083a 100644 --- a/src/cmd/compile/internal/ir/op_string.go +++ b/src/cmd/compile/internal/ir/op_string.go @@ -112,62 +112,61 @@ func _() { _ = x[ORECV-101] _ = x[ORUNESTR-102] _ = x[OSELRECV2-103] - _ = x[OIOTA-104] - _ = x[OREAL-105] - _ = x[OIMAG-106] - _ = x[OCOMPLEX-107] - _ = x[OALIGNOF-108] - _ = x[OOFFSETOF-109] - _ = x[OSIZEOF-110] - _ = x[OUNSAFEADD-111] - _ = x[OUNSAFESLICE-112] - _ = x[OMETHEXPR-113] - _ = x[OMETHVALUE-114] - _ = x[OBLOCK-115] - _ = x[OBREAK-116] - _ = x[OCASE-117] - _ = x[OCONTINUE-118] - _ = x[ODEFER-119] - _ = x[OFALL-120] - _ = x[OFOR-121] - _ = x[OFORUNTIL-122] - _ = x[OGOTO-123] - _ = x[OIF-124] - _ = x[OLABEL-125] - _ = x[OGO-126] - _ = x[ORANGE-127] - _ = x[ORETURN-128] - _ = x[OSELECT-129] - _ = x[OSWITCH-130] - _ = x[OTYPESW-131] - _ = x[OFUNCINST-132] - _ = x[OTFUNC-133] - _ = x[OINLCALL-134] - _ = x[OEFACE-135] - _ = x[OITAB-136] - _ = x[OIDATA-137] - _ = x[OSPTR-138] - _ = x[OCFUNC-139] - _ = x[OCHECKNIL-140] - _ = x[OVARDEF-141] - _ = x[OVARKILL-142] - _ = x[OVARLIVE-143] - _ = x[ORESULT-144] - _ = x[OINLMARK-145] - _ = x[OLINKSYMOFFSET-146] - _ = x[ODYNAMICDOTTYPE-147] - _ = x[ODYNAMICDOTTYPE2-148] - _ = x[ODYNAMICTYPE-149] - _ = x[OTAILCALL-150] - _ = x[OGETG-151] - _ = x[OGETCALLERPC-152] - _ = x[OGETCALLERSP-153] - _ = x[OEND-154] + _ = x[OREAL-104] + _ = x[OIMAG-105] + _ = x[OCOMPLEX-106] + _ = x[OALIGNOF-107] + _ = x[OOFFSETOF-108] + _ = x[OSIZEOF-109] + _ = x[OUNSAFEADD-110] + _ = x[OUNSAFESLICE-111] + _ = x[OMETHEXPR-112] + _ = x[OMETHVALUE-113] + _ = x[OBLOCK-114] + _ = x[OBREAK-115] + _ = x[OCASE-116] + _ = x[OCONTINUE-117] + _ = x[ODEFER-118] + _ = x[OFALL-119] + _ = x[OFOR-120] + _ = x[OFORUNTIL-121] + _ = x[OGOTO-122] + _ = x[OIF-123] + _ = x[OLABEL-124] + _ = x[OGO-125] + _ = x[ORANGE-126] + _ = x[ORETURN-127] + _ = x[OSELECT-128] + _ = x[OSWITCH-129] + _ = x[OTYPESW-130] + _ = x[OFUNCINST-131] + _ = x[OTFUNC-132] + _ = x[OINLCALL-133] + _ = x[OEFACE-134] + _ = x[OITAB-135] + _ = x[OIDATA-136] + _ = x[OSPTR-137] + _ = x[OCFUNC-138] + _ = x[OCHECKNIL-139] + _ = x[OVARDEF-140] + _ = x[OVARKILL-141] + _ = x[OVARLIVE-142] + _ = x[ORESULT-143] + _ = x[OINLMARK-144] + _ = x[OLINKSYMOFFSET-145] + _ = x[ODYNAMICDOTTYPE-146] + _ = x[ODYNAMICDOTTYPE2-147] + _ = x[ODYNAMICTYPE-148] + _ = x[OTAILCALL-149] + _ = x[OGETG-150] + _ = x[OGETCALLERPC-151] + _ = x[OGETCALLERSP-152] + _ = x[OEND-153] } -const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2IOTAREALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTTFUNCINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERPCGETCALLERSPEND" +const _Op_name = "XXXNAMENONAMETYPELITERALNILADDSUBORXORADDSTRADDRANDANDAPPENDBYTES2STRBYTES2STRTMPRUNES2STRSTR2BYTESSTR2BYTESTMPSTR2RUNESSLICE2ARRPTRASAS2AS2DOTTYPEAS2FUNCAS2MAPRAS2RECVASOPCALLCALLFUNCCALLMETHCALLINTERCAPCLOSECLOSURECOMPLITMAPLITSTRUCTLITARRAYLITSLICELITPTRLITCONVCONVIFACECONVIDATACONVNOPCOPYDCLDCLFUNCDCLCONSTDCLTYPEDELETEDOTDOTPTRDOTMETHDOTINTERXDOTDOTTYPEDOTTYPE2EQNELTLEGEGTDEREFINDEXINDEXMAPKEYSTRUCTKEYLENMAKEMAKECHANMAKEMAPMAKESLICEMAKESLICECOPYMULDIVMODLSHRSHANDANDNOTNEWNOTBITNOTPLUSNEGORORPANICPRINTPRINTNPARENSENDSLICESLICEARRSLICESTRSLICE3SLICE3ARRSLICEHEADERRECOVERRECOVERFPRECVRUNESTRSELRECV2REALIMAGCOMPLEXALIGNOFOFFSETOFSIZEOFUNSAFEADDUNSAFESLICEMETHEXPRMETHVALUEBLOCKBREAKCASECONTINUEDEFERFALLFORFORUNTILGOTOIFLABELGORANGERETURNSELECTSWITCHTYPESWFUNCINSTTFUNCINLCALLEFACEITABIDATASPTRCFUNCCHECKNILVARDEFVARKILLVARLIVERESULTINLMARKLINKSYMOFFSETDYNAMICDOTTYPEDYNAMICDOTTYPE2DYNAMICTYPETAILCALLGETGGETCALLERPCGETCALLERSPEND" -var _Op_index = [...]uint16{0, 3, 7, 13, 17, 24, 27, 30, 33, 35, 38, 44, 48, 54, 60, 69, 81, 90, 99, 111, 120, 132, 134, 137, 147, 154, 161, 168, 172, 176, 184, 192, 201, 204, 209, 216, 223, 229, 238, 246, 254, 260, 264, 273, 282, 289, 293, 296, 303, 311, 318, 324, 327, 333, 340, 348, 352, 359, 367, 369, 371, 373, 375, 377, 379, 384, 389, 397, 400, 409, 412, 416, 424, 431, 440, 453, 456, 459, 462, 465, 468, 471, 477, 480, 483, 489, 493, 496, 500, 505, 510, 516, 521, 525, 530, 538, 546, 552, 561, 572, 579, 588, 592, 599, 607, 611, 615, 619, 626, 633, 641, 647, 656, 667, 675, 684, 689, 694, 698, 706, 711, 715, 718, 726, 730, 732, 737, 739, 744, 750, 756, 762, 768, 776, 781, 788, 793, 797, 802, 806, 811, 819, 825, 832, 839, 845, 852, 865, 879, 894, 905, 913, 917, 928, 939, 942} +var _Op_index = [...]uint16{0, 3, 7, 13, 17, 24, 27, 30, 33, 35, 38, 44, 48, 54, 60, 69, 81, 90, 99, 111, 120, 132, 134, 137, 147, 154, 161, 168, 172, 176, 184, 192, 201, 204, 209, 216, 223, 229, 238, 246, 254, 260, 264, 273, 282, 289, 293, 296, 303, 311, 318, 324, 327, 333, 340, 348, 352, 359, 367, 369, 371, 373, 375, 377, 379, 384, 389, 397, 400, 409, 412, 416, 424, 431, 440, 453, 456, 459, 462, 465, 468, 471, 477, 480, 483, 489, 493, 496, 500, 505, 510, 516, 521, 525, 530, 538, 546, 552, 561, 572, 579, 588, 592, 599, 607, 611, 615, 622, 629, 637, 643, 652, 663, 671, 680, 685, 690, 694, 702, 707, 711, 714, 722, 726, 728, 733, 735, 740, 746, 752, 758, 764, 772, 777, 784, 789, 793, 798, 802, 807, 815, 821, 828, 835, 841, 848, 861, 875, 890, 901, 909, 913, 924, 935, 938} func (i Op) String() string { if i >= Op(len(_Op_index)-1) { diff --git a/src/cmd/compile/internal/ir/sizeof_test.go b/src/cmd/compile/internal/ir/sizeof_test.go index fca11ffc7c..c1167f23f8 100644 --- a/src/cmd/compile/internal/ir/sizeof_test.go +++ b/src/cmd/compile/internal/ir/sizeof_test.go @@ -20,7 +20,7 @@ func TestSizeof(t *testing.T) { _32bit uintptr // size on 32bit platforms _64bit uintptr // size on 64bit platforms }{ - {Func{}, 192, 328}, + {Func{}, 184, 320}, {Name{}, 108, 192}, } diff --git a/src/cmd/compile/internal/ir/stmt.go b/src/cmd/compile/internal/ir/stmt.go index e7d0d873b7..80bd205436 100644 --- a/src/cmd/compile/internal/ir/stmt.go +++ b/src/cmd/compile/internal/ir/stmt.go @@ -362,7 +362,7 @@ func NewSendStmt(pos src.XPos, ch, value Node) *SendStmt { return n } -// A SwitchStmt is a switch statement: switch Init; Expr { Cases }. +// A SwitchStmt is a switch statement: switch Init; Tag { Cases }. type SwitchStmt struct { miniStmt Tag Node diff --git a/src/cmd/compile/internal/ir/val.go b/src/cmd/compile/internal/ir/val.go index bfe7d2bb43..925222b113 100644 --- a/src/cmd/compile/internal/ir/val.go +++ b/src/cmd/compile/internal/ir/val.go @@ -6,7 +6,6 @@ package ir import ( "go/constant" - "math" "cmd/compile/internal/base" "cmd/compile/internal/types" @@ -19,27 +18,6 @@ func ConstType(n Node) constant.Kind { return n.Val().Kind() } -// ConstValue returns the constant value stored in n as an interface{}. -// It returns int64s for ints and runes, float64s for floats, -// and complex128s for complex values. -func ConstValue(n Node) interface{} { - switch v := n.Val(); v.Kind() { - default: - base.Fatalf("unexpected constant: %v", v) - panic("unreachable") - case constant.Bool: - return constant.BoolVal(v) - case constant.String: - return constant.StringVal(v) - case constant.Int: - return IntVal(n.Type(), v) - case constant.Float: - return Float64Val(v) - case constant.Complex: - return complex(Float64Val(constant.Real(v)), Float64Val(constant.Imag(v))) - } -} - // IntVal returns v converted to int64. // Note: if t is uint64, very large values will be converted to negative int64. func IntVal(t *types.Type, v constant.Value) int64 { @@ -56,14 +34,6 @@ func IntVal(t *types.Type, v constant.Value) int64 { panic("unreachable") } -func Float64Val(v constant.Value) float64 { - if x, _ := constant.Float64Val(v); !math.IsInf(x, 0) { - return x + 0 // avoid -0 (should not be needed, but be conservative) - } - base.Fatalf("bad float64 value: %v", v) - panic("unreachable") -} - func AssertValidTypeForConst(t *types.Type, v constant.Value) { if !ValidTypeForConst(t, v) { base.Fatalf("%v (%v) does not represent %v (%v)", t, t.Kind(), v, v.Kind()) @@ -114,18 +84,6 @@ func idealType(ct constant.Kind) *types.Type { var OKForConst [types.NTYPE]bool -// CanInt64 reports whether it is safe to call Int64Val() on n. -func CanInt64(n Node) bool { - if !IsConst(n, constant.Int) { - return false - } - - // if the value inside n cannot be represented as an int64, the - // return value of Int64 is undefined - _, ok := constant.Int64Val(n.Val()) - return ok -} - // Int64Val returns n as an int64. // n must be an integer or rune constant. func Int64Val(n Node) int64 { diff --git a/src/cmd/compile/internal/logopt/log_opts.go b/src/cmd/compile/internal/logopt/log_opts.go index 97ebf56944..9fee83426f 100644 --- a/src/cmd/compile/internal/logopt/log_opts.go +++ b/src/cmd/compile/internal/logopt/log_opts.go @@ -405,7 +405,7 @@ func uriIfy(f string) DocumentURI { // Return filename, replacing a first occurrence of $GOROOT with the // actual value of the GOROOT (because LSP does not speak "$GOROOT"). func uprootedPath(filename string) string { - if !strings.HasPrefix(filename, "$GOROOT/") { + if buildcfg.GOROOT == "" || !strings.HasPrefix(filename, "$GOROOT/") { return filename } return buildcfg.GOROOT + filename[len("$GOROOT"):] diff --git a/src/cmd/compile/internal/logopt/logopt_test.go b/src/cmd/compile/internal/logopt/logopt_test.go index 902cbc8091..8d07a49cc0 100644 --- a/src/cmd/compile/internal/logopt/logopt_test.go +++ b/src/cmd/compile/internal/logopt/logopt_test.go @@ -226,7 +226,7 @@ func s15a8(x *[15]int64) [15]int64 { } func testLogOpt(t *testing.T, flag, src, outfile string) (string, error) { - run := []string{testenv.GoToolPath(t), "tool", "compile", flag, "-o", outfile, src} + run := []string{testenv.GoToolPath(t), "tool", "compile", "-p=p", flag, "-o", outfile, src} t.Log(run) cmd := exec.Command(run[0], run[1:]...) out, err := cmd.CombinedOutput() @@ -236,7 +236,7 @@ func testLogOpt(t *testing.T, flag, src, outfile string) (string, error) { func testLogOptDir(t *testing.T, dir, flag, src, outfile string) (string, error) { // Notice the specified import path "x" - run := []string{testenv.GoToolPath(t), "tool", "compile", "-p", "x", flag, "-o", outfile, src} + run := []string{testenv.GoToolPath(t), "tool", "compile", "-p=x", flag, "-o", outfile, src} t.Log(run) cmd := exec.Command(run[0], run[1:]...) cmd.Dir = dir @@ -247,7 +247,7 @@ func testLogOptDir(t *testing.T, dir, flag, src, outfile string) (string, error) func testCopy(t *testing.T, dir, goarch, goos, src, outfile string) (string, error) { // Notice the specified import path "x" - run := []string{testenv.GoToolPath(t), "tool", "compile", "-p", "x", "-json=0,file://log/opt", "-o", outfile, src} + run := []string{testenv.GoToolPath(t), "tool", "compile", "-p=x", "-json=0,file://log/opt", "-o", outfile, src} t.Log(run) cmd := exec.Command(run[0], run[1:]...) cmd.Dir = dir diff --git a/src/cmd/compile/internal/noder/codes.go b/src/cmd/compile/internal/noder/codes.go index bc0831dd78..8f54a07ca4 100644 --- a/src/cmd/compile/internal/noder/codes.go +++ b/src/cmd/compile/internal/noder/codes.go @@ -29,9 +29,6 @@ const ( stmtFor stmtSwitch stmtSelect - - // TODO(mdempsky): Remove after we don't care about toolstash -cmp. - stmtTypeDeclHack ) type codeExpr int diff --git a/src/cmd/compile/internal/noder/decl.go b/src/cmd/compile/internal/noder/decl.go index a9522d09af..f985648c66 100644 --- a/src/cmd/compile/internal/noder/decl.go +++ b/src/cmd/compile/internal/noder/decl.go @@ -114,11 +114,11 @@ func (g *irgen) funcDecl(out *ir.Nodes, decl *syntax.FuncDecl) { // the Fields to represent the receiver's method set. if recv := fn.Type().Recv(); recv != nil { typ := types.ReceiverBaseType(recv.Type) - if typ.OrigSym() != nil { + if orig := typ.OrigType(); orig != nil { // For a generic method, we mark the methods on the // base generic type, since those are the methods // that will be stenciled. - typ = typ.OrigSym().Def.Type() + typ = orig } meth := typecheck.Lookdot1(fn, typecheck.Lookup(decl.Name.Value), typ, typ.Methods(), 0) meth.SetNointerface(true) diff --git a/src/cmd/compile/internal/noder/expr.go b/src/cmd/compile/internal/noder/expr.go index 4b5ae706c1..566abda963 100644 --- a/src/cmd/compile/internal/noder/expr.go +++ b/src/cmd/compile/internal/noder/expr.go @@ -439,7 +439,6 @@ func (g *irgen) funcLit(typ2 types2.Type, expr *syntax.FuncLit) ir.Node { for _, cv := range fn.ClosureVars { cv.SetType(cv.Canonical().Type()) cv.SetTypecheck(1) - cv.SetWalkdef(1) } if g.topFuncIsGeneric { diff --git a/src/cmd/compile/internal/noder/import.go b/src/cmd/compile/internal/noder/import.go index 0898a298eb..7ba1b23d12 100644 --- a/src/cmd/compile/internal/noder/import.go +++ b/src/cmd/compile/internal/noder/import.go @@ -369,16 +369,8 @@ func addFingerprint(path string, f *os.File, end int64) error { } copy(fingerprint[:], buf[:]) + base.Ctxt.AddImport(path, fingerprint) - // assume files move (get installed) so don't record the full path - if base.Flag.Cfg.PackageFile != nil { - // If using a packageFile map, assume path_ can be recorded directly. - base.Ctxt.AddImport(path, fingerprint) - } else { - // For file "/Users/foo/go/pkg/darwin_amd64/math.a" record "math.a". - file := f.Name() - base.Ctxt.AddImport(file[len(file)-len(path)-len(".a"):], fingerprint) - } return nil } diff --git a/src/cmd/compile/internal/noder/irgen.go b/src/cmd/compile/internal/noder/irgen.go index 993c254218..5499ccd405 100644 --- a/src/cmd/compile/internal/noder/irgen.go +++ b/src/cmd/compile/internal/noder/irgen.go @@ -99,8 +99,8 @@ type subDictInfo struct { } // dictInfo is the dictionary format for an instantiation of a generic function with -// particular shapes. shapeParams, derivedTypes, subDictCalls, and itabConvs describe -// the actual dictionary entries in order, and the remaining fields are other info +// particular shapes. shapeParams, derivedTypes, subDictCalls, itabConvs, and methodExprClosures +// describe the actual dictionary entries in order, and the remaining fields are other info // needed in doing dictionary processing during compilation. type dictInfo struct { // Types substituted for the type parameters, which are shape types. @@ -114,6 +114,11 @@ type dictInfo struct { // Nodes in the instantiation that are a conversion from a typeparam/derived // type to a specific interface. itabConvs []ir.Node + // Method expression closures. For a generic type T with method M(arg1, arg2) res, + // these closures are func(rcvr T, arg1, arg2) res. + // These closures capture no variables, they are just the generic version of ·f symbols + // that live in the dictionary instead of in the readonly globals section. + methodExprClosures []methodExprClosure // Mapping from each shape type that substitutes a type param, to its // type bound (which is also substituted with shapes if it is parameterized) @@ -123,9 +128,15 @@ type dictInfo struct { // HasShape type, to the interface type we're switching from. type2switchType map[ir.Node]*types.Type - startSubDict int // Start of dict entries for subdictionaries - startItabConv int // Start of dict entries for itab conversions - dictLen int // Total number of entries in dictionary + startSubDict int // Start of dict entries for subdictionaries + startItabConv int // Start of dict entries for itab conversions + startMethodExprClosures int // Start of dict entries for closures for method expressions + dictLen int // Total number of entries in dictionary +} + +type methodExprClosure struct { + idx int // index in list of shape parameters + name string // method name } // instInfo is information gathered on an shape instantiation of a function. @@ -182,7 +193,7 @@ type genInst struct { instInfoMap map[*types.Sym]*instInfo // Dictionary syms which we need to finish, by writing out any itabconv - // entries. + // or method expression closure entries. dictSymsToFinalize []*delayInfo // New instantiations created during this round of buildInstantiations(). diff --git a/src/cmd/compile/internal/noder/noder.go b/src/cmd/compile/internal/noder/noder.go index 1d7c1f44a4..f8f802936b 100644 --- a/src/cmd/compile/internal/noder/noder.go +++ b/src/cmd/compile/internal/noder/noder.go @@ -472,7 +472,7 @@ func checkEmbed(decl *syntax.VarDecl, haveEmbed, withinFunc bool) error { return errors.New("go:embed cannot apply to var without type") case withinFunc: return errors.New("go:embed cannot apply to var inside func") - case !types.AllowsGoVersion(types.LocalPkg, 1, 16): + case !types.AllowsGoVersion(1, 16): return fmt.Errorf("go:embed requires go1.16 or later (-lang was set to %s; check go.mod)", base.Flag.Lang) default: diff --git a/src/cmd/compile/internal/noder/object.go b/src/cmd/compile/internal/noder/object.go index 37a995b519..e8dbaac161 100644 --- a/src/cmd/compile/internal/noder/object.go +++ b/src/cmd/compile/internal/noder/object.go @@ -171,7 +171,6 @@ func (g *irgen) objFinish(name *ir.Name, class ir.Class, typ *types.Type) { } name.SetTypecheck(1) - name.SetWalkdef(1) if ir.IsBlank(name) { return diff --git a/src/cmd/compile/internal/noder/reader.go b/src/cmd/compile/internal/noder/reader.go index 2b1636588e..01e795183d 100644 --- a/src/cmd/compile/internal/noder/reader.go +++ b/src/cmd/compile/internal/noder/reader.go @@ -26,12 +26,6 @@ import ( "cmd/internal/src" ) -// TODO(mdempsky): Suppress duplicate type/const errors that can arise -// during typecheck due to naive type substitution (e.g., see #42758). -// I anticipate these will be handled as a consequence of adding -// dictionaries support, so it's probably not important to focus on -// this until after that's done. - type pkgReader struct { pkgbits.PkgDecoder @@ -147,6 +141,13 @@ type readerDict struct { funcs []objInfo funcsObj []ir.Node + + itabs []itabInfo2 +} + +type itabInfo2 struct { + typ *types.Type + lsym *obj.LSym } func setType(n ir.Node, typ *types.Type) { @@ -154,7 +155,6 @@ func setType(n ir.Node, typ *types.Type) { n.SetTypecheck(1) if name, ok := n.(*ir.Name); ok { - name.SetWalkdef(1) name.Ntype = ir.TypeNode(name.Type()) } } @@ -209,7 +209,7 @@ func (pr *pkgReader) posBaseIdx(idx int) *src.PosBase { // require being more consistent about when we use native vs UNIX // file paths. const dollarGOROOT = "$GOROOT" - if strings.HasPrefix(filename, dollarGOROOT) { + if buildcfg.GOROOT != "" && strings.HasPrefix(filename, dollarGOROOT) { filename = buildcfg.GOROOT + filename[len(dollarGOROOT):] } @@ -643,6 +643,10 @@ func (pr *pkgReader) objIdx(idx int, implicits, explicits []*types.Type) ir.Node name.Func = ir.NewFunc(r.pos()) name.Func.Nname = name + if r.hasTypeParams() { + name.Func.SetDupok(true) + } + rext.funcExt(name) return name @@ -745,6 +749,22 @@ func (pr *pkgReader) objDictIdx(sym *types.Sym, idx int, implicits, explicits [] dict.funcs[i] = objInfo{idx: objIdx, explicits: targs} } + dict.itabs = make([]itabInfo2, r.Len()) + for i := range dict.itabs { + typ := pr.typIdx(typeInfo{idx: r.Len(), derived: true}, &dict, true) + ifaceInfo := r.typInfo() + + var lsym *obj.LSym + if typ.IsInterface() { + lsym = reflectdata.TypeLinksym(typ) + } else { + iface := pr.typIdx(ifaceInfo, &dict, true) + lsym = reflectdata.ITabLsym(typ, iface) + } + + dict.itabs[i] = itabInfo2{typ: typ, lsym: lsym} + } + return &dict } @@ -773,6 +793,10 @@ func (r *reader) method(rext *reader) *types.Field { name.Func = ir.NewFunc(r.pos()) name.Func.Nname = name + if r.hasTypeParams() { + name.Func.SetDupok(true) + } + rext.funcExt(name) meth := types.NewField(name.Func.Pos(), sym, typ) @@ -930,11 +954,6 @@ var bodyReader = map[*ir.Func]pkgReaderIndex{} // constructed. var todoBodies []*ir.Func -// todoBodiesDone signals that we constructed all function in todoBodies. -// This is necessary to prevent reader.addBody adds thing to todoBodies -// when nested inlining happens. -var todoBodiesDone = false - func (r *reader) addBody(fn *ir.Func) { pri := pkgReaderIndex{r.p, r.Reloc(pkgbits.RelocBody), r.dict} bodyReader[fn] = pri @@ -945,7 +964,7 @@ func (r *reader) addBody(fn *ir.Func) { return } - if r.curfn == nil && !todoBodiesDone { + if r.curfn == nil { todoBodies = append(todoBodies, fn) return } @@ -1412,25 +1431,22 @@ func (r *reader) switchStmt(label *types.Sym) ir.Node { init := r.stmt() var tag ir.Node + var ident *ir.Ident + var iface *types.Type if r.Bool() { pos := r.pos() - var ident *ir.Ident if r.Bool() { pos := r.pos() sym := typecheck.Lookup(r.String()) ident = ir.NewIdent(pos, sym) } x := r.expr() + iface = x.Type() tag = ir.NewTypeSwitchGuard(pos, ident, x) } else { tag = r.expr() } - tswitch, ok := tag.(*ir.TypeSwitchGuard) - if ok && tswitch.Tag == nil { - tswitch = nil - } - clauses := make([]*ir.CaseClause, r.Len()) for i := range clauses { if i > 0 { @@ -1439,18 +1455,30 @@ func (r *reader) switchStmt(label *types.Sym) ir.Node { r.openScope() pos := r.pos() - cases := r.exprList() + var cases []ir.Node + if iface != nil { + cases = make([]ir.Node, r.Len()) + if len(cases) == 0 { + cases = nil // TODO(mdempsky): Unclear if this matters. + } + for i := range cases { + cases[i] = r.exprType(true) + } + } else { + cases = r.exprList() + } clause := ir.NewCaseStmt(pos, cases, nil) - if tswitch != nil { + + if ident != nil { pos := r.pos() typ := r.typ() - name := ir.NewNameAt(pos, tswitch.Tag.Sym()) + name := ir.NewNameAt(pos, ident.Sym()) setType(name, typ) r.addLocal(name, ir.PAUTO) clause.Var = name - name.Defn = tswitch + name.Defn = tag } clause.Body = r.stmts() @@ -1534,10 +1562,7 @@ func (r *reader) expr() (res ir.Node) { return typecheck.Callee(r.obj()) case exprType: - // TODO(mdempsky): ir.TypeNode should probably return a typecheck'd node. - n := ir.TypeNode(r.typ()) - n.SetTypecheck(1) - return n + return r.exprType(false) case exprConst: pos := r.pos() @@ -1557,6 +1582,15 @@ func (r *reader) expr() (res ir.Node) { x := r.expr() pos := r.pos() _, sym := r.selector() + + // Method expression with derived receiver type. + if x.Op() == ir.ODYNAMICTYPE { + // TODO(mdempsky): Handle with runtime dictionary lookup. + n := ir.TypeNode(x.Type()) + n.SetTypecheck(1) + x = n + } + n := typecheck.Expr(ir.NewSelectorExpr(pos, ir.OXDOT, x, sym)).(*ir.SelectorExpr) if n.Op() == ir.OMETHVALUE { wrapper := methodValueWrapper{ @@ -1593,8 +1627,12 @@ func (r *reader) expr() (res ir.Node) { case exprAssert: x := r.expr() pos := r.pos() - typ := r.expr().(ir.Ntype) - return typecheck.Expr(ir.NewTypeAssertExpr(pos, x, typ)) + typ := r.exprType(false) + + if typ, ok := typ.(*ir.DynamicType); ok && typ.Op() == ir.ODYNAMICTYPE { + return typed(typ.Type(), ir.NewDynamicTypeAssertExpr(pos, ir.ODYNAMICDOTTYPE, x, typ.X)) + } + return typecheck.Expr(ir.NewTypeAssertExpr(pos, x, typ.(ir.Ntype))) case exprUnaryOp: op := r.op() @@ -1637,6 +1675,20 @@ func (r *reader) expr() (res ir.Node) { typ := r.typ() pos := r.pos() x := r.expr() + + // TODO(mdempsky): Stop constructing expressions of untyped type. + x = typecheck.DefaultLit(x, typ) + + if op, why := typecheck.Convertop(x.Op() == ir.OLITERAL, x.Type(), typ); op == ir.OXXX { + // types2 ensured that x is convertable to typ under standard Go + // semantics, but cmd/compile also disallows some conversions + // involving //go:notinheap. + // + // TODO(mdempsky): This can be removed after #46731 is implemented. + base.ErrorfAt(pos, "cannot convert %L to type %v%v", x, typ, why) + base.ErrorExit() // harsh, but prevents constructing invalid IR + } + return typecheck.Expr(ir.NewConvExpr(pos, ir.OCONV, typ, x)) } } @@ -1739,6 +1791,39 @@ func (r *reader) exprs() []ir.Node { return nodes } +func (r *reader) exprType(nilOK bool) ir.Node { + r.Sync(pkgbits.SyncExprType) + + if nilOK && r.Bool() { + return typecheck.Expr(types.BuiltinPkg.Lookup("nil").Def.(*ir.NilExpr)) + } + + pos := r.pos() + + var typ *types.Type + var lsym *obj.LSym + + if r.Bool() { + itab := r.dict.itabs[r.Len()] + typ, lsym = itab.typ, itab.lsym + } else { + info := r.typInfo() + typ = r.p.typIdx(info, r.dict, true) + + if !info.derived { + // TODO(mdempsky): ir.TypeNode should probably return a typecheck'd node. + n := ir.TypeNode(typ) + n.SetTypecheck(1) + return n + } + + lsym = reflectdata.TypeLinksym(typ) + } + + ptr := typecheck.Expr(typecheck.NodAddr(ir.NewLinksymExpr(pos, lsym, types.Types[types.TUINT8]))) + return typed(typ, ir.NewDynamicType(pos, ptr)) +} + func (r *reader) op() ir.Op { r.Sync(pkgbits.SyncOp) return ir.Op(r.Len()) @@ -1974,6 +2059,13 @@ func InlineCall(call *ir.CallExpr, fn *ir.Func, inlIndex int) *ir.InlinedCallExp r.curfn.Body = r.stmts() r.curfn.Endlineno = r.pos() + // TODO(mdempsky): This shouldn't be necessary. Inlining might + // read in new function/method declarations, which could + // potentially be recursively inlined themselves; but we shouldn't + // need to read in the non-inlined bodies for the declarations + // themselves. But currently it's an easy fix to #50552. + readBodies(typecheck.Target) + deadcode.Func(r.curfn) // Replace any "return" statements within the function body. diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 9d17d5ffd1..eeac8d8de7 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -193,8 +193,7 @@ func (g *genInst) scanForGenCalls(decl ir.Node) { targs := deref(meth.Type().Recv().Type).RParams() t := meth.X.Type() - baseSym := deref(t).OrigSym() - baseType := baseSym.Def.(*ir.Name).Type() + baseType := deref(t).OrigType() var gf *ir.Name for _, m := range baseType.Methods().Slice() { if meth.Sel == m.Sym { @@ -348,7 +347,7 @@ func (g *genInst) buildClosure(outer *ir.Func, x ir.Node) ir.Node { // actually generic, so no need to build a closure. return x } - baseType := recv.OrigSym().Def.Type() + baseType := recv.OrigType() var gf *ir.Name for _, m := range baseType.Methods().Slice() { if se.Sel == m.Sym { @@ -543,8 +542,7 @@ func (g *genInst) instantiateMethods() { typecheck.NeedRuntimeType(typ) // Lookup the method on the base generic type, since methods may // not be set on imported instantiated types. - baseSym := typ.OrigSym() - baseType := baseSym.Def.(*ir.Name).Type() + baseType := typ.OrigType() for j, _ := range typ.Methods().Slice() { if baseType.Methods().Slice()[j].Nointerface() { typ.Methods().Slice()[j].SetNointerface(true) @@ -644,7 +642,7 @@ func (g *genInst) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMe if recvType.IsFullyInstantiated() { // Get the type of the base generic type, so we get // its original typeparams. - recvType = recvType.OrigSym().Def.(*ir.Name).Type() + recvType = recvType.OrigType() } tparams = recvType.RParams() } else { @@ -890,6 +888,13 @@ func getDictionaryEntry(pos src.XPos, dict *ir.Name, i int, size int) ir.Node { return r } +// getDictionaryEntryAddr gets the address of the i'th entry in dictionary dict. +func getDictionaryEntryAddr(pos src.XPos, dict *ir.Name, i int, size int) ir.Node { + a := ir.NewAddrExpr(pos, getDictionaryEntry(pos, dict, i, size)) + typed(types.Types[types.TUINTPTR].PtrTo(), a) + return a +} + // getDictionaryType returns a *runtime._type from the dictionary entry i (which // refers to a type param or a derived type that uses type params). It uses the // specified dictionary dictParam, rather than the one in info.dictParam. @@ -898,7 +903,7 @@ func getDictionaryType(info *instInfo, dictParam *ir.Name, pos src.XPos, i int) base.Fatalf(fmt.Sprintf("bad dict index %d", i)) } - r := getDictionaryEntry(pos, info.dictParam, i, info.dictInfo.startSubDict) + r := getDictionaryEntry(pos, dictParam, i, info.dictInfo.startSubDict) // change type of retrieved dictionary entry to *byte, which is the // standard typing of a *runtime._type in the compiler typed(types.Types[types.TUINT8].PtrTo(), r) @@ -1179,6 +1184,26 @@ func (subst *subster) node(n ir.Node) ir.Node { subst.g.newInsts = append(subst.g.newInsts, m.(*ir.ClosureExpr).Func) m.(*ir.ClosureExpr).SetInit(subst.list(x.Init())) + case ir.OSWITCH: + m := m.(*ir.SwitchStmt) + if m.Tag != nil && m.Tag.Op() == ir.OTYPESW { + break // Nothing to do here for type switches. + } + if m.Tag != nil && !m.Tag.Type().IsInterface() && m.Tag.Type().HasShape() { + // To implement a switch on a value that is or has a type parameter, we first convert + // that thing we're switching on to an interface{}. + m.Tag = assignconvfn(m.Tag, types.Types[types.TINTER]) + } + for _, c := range m.Cases { + for i, x := range c.List { + // If we have a case that is or has a type parameter, convert that case + // to an interface{}. + if !x.Type().IsInterface() && x.Type().HasShape() { + c.List[i] = assignconvfn(x, types.Types[types.TINTER]) + } + } + } + } return m } @@ -1192,8 +1217,14 @@ func (g *genInst) dictPass(info *instInfo) { savef := ir.CurFunc ir.CurFunc = info.fun + callMap := make(map[ir.Node]bool) + var edit func(ir.Node) ir.Node edit = func(m ir.Node) ir.Node { + if m.Op() == ir.OCALL && m.(*ir.CallExpr).X.Op() == ir.OXDOT { + callMap[m.(*ir.CallExpr).X] = true + } + ir.EditChildren(m, edit) switch m.Op() { @@ -1221,9 +1252,10 @@ func (g *genInst) dictPass(info *instInfo) { if mse.X.Op() == ir.OTYPE { // Method expression T.M - m = g.buildClosure2(info, m) - // No need for transformDot - buildClosure2 has already - // transformed to OCALLINTER/ODOTINTER. + idx := findMethodExprClosure(info.dictInfo, mse) + c := getDictionaryEntryAddr(m.Pos(), info.dictParam, info.dictInfo.startMethodExprClosures+idx, info.dictInfo.dictLen) + m = ir.NewConvExpr(m.Pos(), ir.OCONVNOP, mse.Type(), c) + m.SetTypecheck(1) } else { // If we can't find the selected method in the // AllMethods of the bound, then this must be an access @@ -1231,20 +1263,23 @@ func (g *genInst) dictPass(info *instInfo) { // dictionary lookups - transformDot() will convert to // the desired direct field access. if isBoundMethod(info.dictInfo, mse) { + if callMap[m] { + // The OCALL surrounding this XDOT will rewrite the call + // to use the method expression closure directly. + break + } + // Convert this method value to a closure. + // TODO: use method expression closure. dst := info.dictInfo.shapeToBound[mse.X.Type()] // Implement x.M as a conversion-to-bound-interface // 1) convert x to the bound interface - // 2) call M on that interface + // 2) select method value M on that interface if src.IsInterface() { // If type arg is an interface (unusual case), // we do a type assert to the type bound. mse.X = assertToBound(info, info.dictParam, m.Pos(), mse.X, dst) } else { - mse.X = convertUsingDictionary(info, info.dictParam, m.Pos(), mse.X, m, dst, true) - // Note: we set nonEscaping==true, because we can assume the backing store for the - // interface conversion doesn't escape. The method call will immediately go to - // a wrapper function which copies all the data out of the interface value. - // (It only matters for non-pointer-shaped interface conversions. See issue 50182.) + mse.X = convertUsingDictionary(info, info.dictParam, m.Pos(), mse.X, m, dst) } } transformDot(mse, false) @@ -1252,6 +1287,25 @@ func (g *genInst) dictPass(info *instInfo) { case ir.OCALL: call := m.(*ir.CallExpr) op := call.X.Op() + if op == ir.OXDOT { + // This is a call of a method value where the value has a type parameter type. + // We transform to a call of the appropriate method expression closure + // in the dictionary. + // So if x has a type parameter type: + // _ = x.m(a) + // Rewrite to: + // _ = methexpr(x, a) + se := call.X.(*ir.SelectorExpr) + call.SetOp(ir.OCALLFUNC) + idx := findMethodExprClosure(info.dictInfo, se) + c := getDictionaryEntryAddr(se.Pos(), info.dictParam, info.dictInfo.startMethodExprClosures+idx, info.dictInfo.dictLen) + t := typecheck.NewMethodType(se.Type(), se.X.Type()) + call.X = ir.NewConvExpr(se.Pos(), ir.OCONVNOP, t, c) + typed(t, call.X) + call.Args.Prepend(se.X) + break + // TODO: deref case? + } if op == ir.OMETHVALUE { // Redo the transformation of OXDOT, now that we // know the method value is being called. @@ -1271,7 +1325,7 @@ func (g *genInst) dictPass(info *instInfo) { // Note: x's argument is still typed as a type parameter. // m's argument now has an instantiated type. if mce.X.Type().HasShape() || (mce.X.Type().IsInterface() && m.Type().HasShape()) { - m = convertUsingDictionary(info, info.dictParam, m.Pos(), m.(*ir.ConvExpr).X, m, m.Type(), false) + m = convertUsingDictionary(info, info.dictParam, m.Pos(), m.(*ir.ConvExpr).X, m, m.Type()) } case ir.ODOTTYPE, ir.ODOTTYPE2: if !m.Type().HasShape() { @@ -1364,9 +1418,7 @@ func findDictType(info *instInfo, t *types.Type) int { // type dst, by returning a new set of nodes that make use of a dictionary entry. in is the // instantiated node of the CONVIFACE node or XDOT node (for a bound method call) that is causing the // conversion. -// If nonEscaping is true, the caller guarantees that the backing store needed for the interface data -// word will not escape. -func convertUsingDictionary(info *instInfo, dictParam *ir.Name, pos src.XPos, v ir.Node, in ir.Node, dst *types.Type, nonEscaping bool) ir.Node { +func convertUsingDictionary(info *instInfo, dictParam *ir.Name, pos src.XPos, v ir.Node, in ir.Node, dst *types.Type) ir.Node { assert(v.Type().HasShape() || v.Type().IsInterface() && in.Type().HasShape()) assert(dst.IsInterface()) @@ -1436,7 +1488,6 @@ func convertUsingDictionary(info *instInfo, dictParam *ir.Name, pos src.XPos, v // Figure out what the data field of the interface will be. data := ir.NewConvExpr(pos, ir.OCONVIDATA, nil, v) typed(types.Types[types.TUNSAFEPTR], data) - data.NonEscaping = nonEscaping // Build an interface from the type and data parts. var i ir.Node = ir.NewBinaryExpr(pos, ir.OEFACE, rt, data) @@ -1608,7 +1659,7 @@ func (g *genInst) getDictionarySym(gf *ir.Name, targs []*types.Type, isMeth bool // instantiated type, so we need a // sub-dictionary. targs := recvType.RParams() - genRecvType := recvType.OrigSym().Def.Type() + genRecvType := recvType.OrigType() nameNode = typecheck.Lookdot1(call.X, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name) sym = g.getDictionarySym(nameNode, targs, true) } else { @@ -1687,7 +1738,7 @@ func (g *genInst) getSymForMethodCall(se *ir.SelectorExpr, subst *typecheck.Tsub // also give the receiver type. For method expressions with embedded types, we // need to look at the type of the selection to get the final receiver type. recvType := deref(se.Selection.Type.Recv().Type) - genRecvType := recvType.OrigSym().Def.Type() + genRecvType := recvType.OrigType() nameNode := typecheck.Lookdot1(se, se.Sel, genRecvType, genRecvType.Methods(), 1).Nname.(*ir.Name) subtargs := recvType.RParams() s2targs := make([]*types.Type, len(subtargs)) @@ -1702,6 +1753,7 @@ func (g *genInst) getSymForMethodCall(se *ir.SelectorExpr, subst *typecheck.Tsub // dictionaries and method instantiations to be complete, so, to avoid recursive // dependencies, we finalize the itab lsyms only after all dictionaries syms and // instantiations have been created. +// Also handles writing method expression closures into the dictionaries. func (g *genInst) finalizeSyms() { for _, d := range g.dictSymsToFinalize { infoPrint("=== Finalizing dictionary %s\n", d.sym.Name) @@ -1750,6 +1802,31 @@ func (g *genInst) finalizeSyms() { } } + // Emit an entry for each method expression closure. + // Each entry is a (captureless) closure pointing to the method on the instantiating type. + // In other words, the entry is a runtime.funcval whose fn field is set to the method + // in question, and has no other fields. The address of this dictionary entry can be + // cast to a func of the appropriate type. + // TODO: do these need to be done when finalizing, or can we do them earlier? + for _, bf := range info.methodExprClosures { + rcvr := d.targs[bf.idx] + rcvr2 := deref(rcvr) + found := false + typecheck.CalcMethods(rcvr2) // Ensure methods on all instantiating types are computed. + for _, f := range rcvr2.AllMethods().Slice() { + if f.Sym.Name == bf.name { + codePtr := ir.MethodSym(rcvr, f.Sym).Linksym() + d.off = objw.SymPtr(lsym, d.off, codePtr, 0) + infoPrint(" + MethodExprClosure for %v.%s\n", rcvr, bf.name) + found = true + break + } + } + if !found { + base.Fatalf("method %s on %v not found", bf.name, rcvr) + } + } + objw.Global(lsym, int32(d.off), obj.DUPOK|obj.RODATA) infoPrint("=== Finalized dictionary %s\n", d.sym.Name) } @@ -1806,7 +1883,7 @@ func hasShapeTypes(targs []*types.Type) bool { } // getInstInfo get the dictionary format for a function instantiation- type params, derived -// types, and needed subdictionaries and itabs. +// types, and needed subdictionaries, itabs, and method expression closures. func (g *genInst) getInstInfo(st *ir.Func, shapes []*types.Type, instInfo *instInfo) { info := instInfo.dictInfo info.shapeParams = shapes @@ -1902,10 +1979,22 @@ func (g *genInst) getInstInfo(st *ir.Func, shapes []*types.Type, instInfo *instI } case ir.OXDOT: se := n.(*ir.SelectorExpr) + if se.X.Op() == ir.OTYPE && se.X.Type().IsShape() { + // Method expression. + addMethodExprClosure(info, se) + break + } if isBoundMethod(info, se) { + if callMap[n] { + // Method value called directly. Use method expression closure. + addMethodExprClosure(info, se) + break + } + // Method value not called directly. Still doing the old way. infoPrint(" Itab for bound call: %v\n", n) info.itabConvs = append(info.itabConvs, n) } + case ir.ODOTTYPE, ir.ODOTTYPE2: if !n.(*ir.TypeAssertExpr).Type().IsInterface() && !n.(*ir.TypeAssertExpr).X.Type().IsEmptyInterface() { infoPrint(" Itab for dot type: %v\n", n) @@ -1955,7 +2044,8 @@ func (g *genInst) getInstInfo(st *ir.Func, shapes []*types.Type, instInfo *instI } info.startSubDict = len(info.shapeParams) + len(info.derivedTypes) info.startItabConv = len(info.shapeParams) + len(info.derivedTypes) + len(info.subDictCalls) - info.dictLen = len(info.shapeParams) + len(info.derivedTypes) + len(info.subDictCalls) + len(info.itabConvs) + info.startMethodExprClosures = len(info.shapeParams) + len(info.derivedTypes) + len(info.subDictCalls) + len(info.itabConvs) + info.dictLen = len(info.shapeParams) + len(info.derivedTypes) + len(info.subDictCalls) + len(info.itabConvs) + len(info.methodExprClosures) } // isBoundMethod returns true if the selection indicated by se is a bound method of @@ -1967,6 +2057,46 @@ func isBoundMethod(info *dictInfo, se *ir.SelectorExpr) bool { return typecheck.Lookdot1(se, se.Sel, bound, bound.AllMethods(), 1) != nil } +func shapeIndex(info *dictInfo, t *types.Type) int { + for i, s := range info.shapeParams { + if s == t { + return i + } + } + base.Fatalf("can't find type %v in shape params", t) + return -1 +} + +// addMethodExprClosure adds the T.M method expression to the list of bound method expressions +// used in the generic body. +// isBoundMethod must have returned true on the same arguments. +func addMethodExprClosure(info *dictInfo, se *ir.SelectorExpr) { + idx := shapeIndex(info, se.X.Type()) + name := se.Sel.Name + for _, b := range info.methodExprClosures { + if idx == b.idx && name == b.name { + return + } + } + infoPrint(" Method expression closure for %v.%s\n", info.shapeParams[idx], name) + info.methodExprClosures = append(info.methodExprClosures, methodExprClosure{idx: idx, name: name}) +} + +// findMethodExprClosure finds the entry in the dictionary to use for the T.M +// method expression encoded in se. +// isBoundMethod must have returned true on the same arguments. +func findMethodExprClosure(info *dictInfo, se *ir.SelectorExpr) int { + idx := shapeIndex(info, se.X.Type()) + name := se.Sel.Name + for i, b := range info.methodExprClosures { + if idx == b.idx && name == b.name { + return i + } + } + base.Fatalf("can't find method expression closure for %s %s", se.X.Type(), name) + return -1 +} + // addType adds t to info.derivedTypes if it is parameterized type (which is not // just a simple shape) that is different from any existing type on // info.derivedTypes. @@ -2136,68 +2266,3 @@ func assertToBound(info *instInfo, dictVar *ir.Name, pos src.XPos, rcvr ir.Node, } return rcvr } - -// buildClosure2 makes a closure to implement a method expression m (generic form x) -// which has a shape type as receiver. If the receiver is exactly a shape (i.e. from -// a typeparam), then the body of the closure converts m.X (the receiver) to the -// interface bound type, and makes an interface call with the remaining arguments. -// -// The returned closure is fully substituted and has already had any needed -// transformations done. -func (g *genInst) buildClosure2(info *instInfo, m ir.Node) ir.Node { - outer := info.fun - pos := m.Pos() - typ := m.Type() // type of the closure - - fn, formalParams, formalResults := startClosure(pos, outer, typ) - - // Capture dictionary calculated in the outer function - dictVar := ir.CaptureName(pos, fn, info.dictParam) - typed(types.Types[types.TUINTPTR], dictVar) - - // Build arguments to call inside the closure. - var args []ir.Node - for i := 0; i < typ.NumParams(); i++ { - args = append(args, formalParams[i].Nname.(*ir.Name)) - } - - // Build call itself. This involves converting the first argument to the - // bound type (an interface) using the dictionary, and then making an - // interface call with the remaining arguments. - var innerCall ir.Node - rcvr := args[0] - args = args[1:] - assert(m.(*ir.SelectorExpr).X.Type().IsShape()) - dst := info.dictInfo.shapeToBound[m.(*ir.SelectorExpr).X.Type()] - if m.(*ir.SelectorExpr).X.Type().IsInterface() { - // If type arg is an interface (unusual case), we do a type assert to - // the type bound. - rcvr = assertToBound(info, dictVar, pos, rcvr, dst) - } else { - rcvr = convertUsingDictionary(info, dictVar, pos, rcvr, m, dst, false) - } - dot := ir.NewSelectorExpr(pos, ir.ODOTINTER, rcvr, m.(*ir.SelectorExpr).Sel) - dot.Selection = typecheck.Lookdot1(dot, dot.Sel, dot.X.Type(), dot.X.Type().AllMethods(), 1) - - typed(dot.Selection.Type, dot) - innerCall = ir.NewCallExpr(pos, ir.OCALLINTER, dot, args) - t := m.Type() - if t.NumResults() == 0 { - innerCall.SetTypecheck(1) - } else if t.NumResults() == 1 { - typed(t.Results().Field(0).Type, innerCall) - } else { - typed(t.Results(), innerCall) - } - if len(formalResults) > 0 { - innerCall = ir.NewReturnStmt(pos, []ir.Node{innerCall}) - innerCall.SetTypecheck(1) - } - fn.Body = []ir.Node{innerCall} - - // We're all done with the captured dictionary - ir.FinishCaptureNames(pos, outer, fn) - - // Do final checks on closure and return it. - return ir.UseClosure(fn.OClosure, typecheck.Target) -} diff --git a/src/cmd/compile/internal/noder/transform.go b/src/cmd/compile/internal/noder/transform.go index 208630271d..43fd73fdbc 100644 --- a/src/cmd/compile/internal/noder/transform.go +++ b/src/cmd/compile/internal/noder/transform.go @@ -242,7 +242,7 @@ func transformCompare(n *ir.BinaryExpr) { aop, _ := typecheck.Assignop(rt, lt) if aop != ir.OXXX { types.CalcSize(rt) - if rt.HasTParam() || rt.IsInterface() == lt.IsInterface() || rt.Size() >= 1<<16 { + if rt.HasShape() || rt.IsInterface() == lt.IsInterface() || rt.Size() >= 1<<16 { r = ir.NewConvExpr(base.Pos, aop, lt, r) r.SetTypecheck(1) } diff --git a/src/cmd/compile/internal/noder/types.go b/src/cmd/compile/internal/noder/types.go index e7ce4c1089..ff3a4d982d 100644 --- a/src/cmd/compile/internal/noder/types.go +++ b/src/cmd/compile/internal/noder/types.go @@ -166,7 +166,7 @@ func (g *irgen) typ0(typ types2.Type) *types.Type { //fmt.Printf("Saw new type %v %v\n", instName, ntyp.HasTParam()) // Save the symbol for the base generic type. - ntyp.SetOrigSym(g.pkg(typ.Obj().Pkg()).Lookup(typ.Obj().Name())) + ntyp.SetOrigType(base.Type()) ntyp.SetUnderlying(g.typ1(typ.Underlying())) if typ.NumMethods() != 0 { // Save a delayed call to g.fillinMethods() (once diff --git a/src/cmd/compile/internal/noder/unified.go b/src/cmd/compile/internal/noder/unified.go index ac82f2df03..ca01c0da95 100644 --- a/src/cmd/compile/internal/noder/unified.go +++ b/src/cmd/compile/internal/noder/unified.go @@ -116,6 +116,28 @@ func unified(noders []*noder) { } } + readBodies(target) + + // Check that nothing snuck past typechecking. + for _, n := range target.Decls { + if n.Typecheck() == 0 { + base.FatalfAt(n.Pos(), "missed typecheck: %v", n) + } + + // For functions, check that at least their first statement (if + // any) was typechecked too. + if fn, ok := n.(*ir.Func); ok && len(fn.Body) != 0 { + if stmt := fn.Body[0]; stmt.Typecheck() == 0 { + base.FatalfAt(stmt.Pos(), "missed typecheck: %v", stmt) + } + } + } + + base.ExitIfErrors() // just in case +} + +// readBodies reads in bodies for any +func readBodies(target *ir.Package) { // Don't use range--bodyIdx can add closures to todoBodies. for len(todoBodies) > 0 { // The order we expand bodies doesn't matter, so pop from the end @@ -134,24 +156,6 @@ func unified(noders []*noder) { } } todoBodies = nil - todoBodiesDone = true - - // Check that nothing snuck past typechecking. - for _, n := range target.Decls { - if n.Typecheck() == 0 { - base.FatalfAt(n.Pos(), "missed typecheck: %v", n) - } - - // For functions, check that at least their first statement (if - // any) was typechecked too. - if fn, ok := n.(*ir.Func); ok && len(fn.Body) != 0 { - if stmt := fn.Body[0]; stmt.Typecheck() == 0 { - base.FatalfAt(stmt.Pos(), "missed typecheck: %v", stmt) - } - } - } - - base.ExitIfErrors() // just in case } // writePkgStub type checks the given parsed source files, diff --git a/src/cmd/compile/internal/noder/writer.go b/src/cmd/compile/internal/noder/writer.go index 59e9409b97..c5c346b784 100644 --- a/src/cmd/compile/internal/noder/writer.go +++ b/src/cmd/compile/internal/noder/writer.go @@ -103,6 +103,10 @@ type writerDict struct { // instantiated with derived types (i.e., that require // sub-dictionaries when called at run time). funcs []objInfo + + // itabs lists itabs that are needed for dynamic type assertions + // (including type switches). + itabs []itabInfo } type derivedInfo struct { @@ -120,6 +124,11 @@ type objInfo struct { explicits []typeInfo // info for the type arguments } +type itabInfo struct { + typIdx int // always a derived type index + iface typeInfo // always a non-empty interface type +} + func (info objInfo) anyDerived() bool { for _, explicit := range info.explicits { if explicit.derived { @@ -284,10 +293,7 @@ func (pw *pkgWriter) typIdx(typ types2.Type, dict *writerDict) typeInfo { } case *types2.Named: - // Type aliases can refer to uninstantiated generic types, so we - // might see len(TParams) != 0 && len(TArgs) == 0 here. - // TODO(mdempsky): Revisit after #46477 is resolved. - assert(typ.TypeParams().Len() == typ.TypeArgs().Len() || typ.TypeArgs().Len() == 0) + assert(typ.TypeParams().Len() == typ.TypeArgs().Len()) // TODO(mdempsky): Why do we need to loop here? orig := typ @@ -636,6 +642,13 @@ func (w *writer) objDict(obj types2.Object, dict *writerDict) { } } + nitabs := len(dict.itabs) + w.Len(nitabs) + for _, itab := range dict.itabs { + w.Len(itab.typIdx) + w.typInfo(itab.iface) + } + assert(len(dict.derived) == nderived) assert(len(dict.funcs) == nfuncs) } @@ -1076,7 +1089,12 @@ func (w *writer) switchStmt(stmt *syntax.SwitchStmt) { w.pos(stmt) w.stmt(stmt.Init) + var iface types2.Type if guard, ok := stmt.Tag.(*syntax.TypeSwitchGuard); w.Bool(ok) { + tv, ok := w.p.info.Types[guard.X] + assert(ok && tv.IsValue()) + iface = tv.Type + w.pos(guard) if tag := guard.Lhs; w.Bool(tag != nil) { w.pos(tag) @@ -1095,7 +1113,16 @@ func (w *writer) switchStmt(stmt *syntax.SwitchStmt) { w.openScope(clause.Pos()) w.pos(clause) - w.exprList(clause.Cases) + + if iface != nil { + cases := unpackListExpr(clause.Cases) + w.Len(len(cases)) + for _, cas := range cases { + w.exprType(iface, cas, true) + } + } else { + w.exprList(clause.Cases) + } if obj, ok := w.p.info.Implicits[clause]; ok { // TODO(mdempsky): These pos details are quirkish, but also @@ -1155,13 +1182,13 @@ func (w *writer) expr(expr syntax.Expr) { if tv.IsType() { w.Code(exprType) - w.typ(tv.Type) + w.exprType(nil, expr, false) return } if tv.Value != nil { w.Code(exprConst) - w.pos(expr.Pos()) + w.pos(expr) w.typ(tv.Type) w.Value(tv.Value) @@ -1235,10 +1262,13 @@ func (w *writer) expr(expr syntax.Expr) { } case *syntax.AssertExpr: + tv, ok := w.p.info.Types[expr.X] + assert(ok && tv.IsValue()) + w.Code(exprAssert) w.expr(expr.X) w.pos(expr) - w.expr(expr.Type) + w.exprType(tv.Type, expr.Type, false) case *syntax.Operation: if expr.Y == nil { @@ -1373,6 +1403,55 @@ func (w *writer) exprs(exprs []syntax.Expr) { } } +func (w *writer) exprType(iface types2.Type, typ syntax.Expr, nilOK bool) { + base.Assertf(iface == nil || isInterface(iface), "%v must be nil or an interface type", iface) + + tv, ok := w.p.info.Types[typ] + assert(ok) + + w.Sync(pkgbits.SyncExprType) + + if nilOK && w.Bool(tv.IsNil()) { + return + } + + assert(tv.IsType()) + info := w.p.typIdx(tv.Type, w.dict) + + w.pos(typ) + + if w.Bool(info.derived && iface != nil && !iface.Underlying().(*types2.Interface).Empty()) { + ifaceInfo := w.p.typIdx(iface, w.dict) + + idx := -1 + for i, itab := range w.dict.itabs { + if itab.typIdx == info.idx && itab.iface == ifaceInfo { + idx = i + } + } + if idx < 0 { + idx = len(w.dict.itabs) + w.dict.itabs = append(w.dict.itabs, itabInfo{typIdx: info.idx, iface: ifaceInfo}) + } + w.Len(idx) + return + } + + w.typInfo(info) +} + +func isInterface(typ types2.Type) bool { + if _, ok := typ.(*types2.TypeParam); ok { + // typ is a type parameter and may be instantiated as either a + // concrete or interface type, so the writer can't depend on + // knowing this. + base.Fatalf("%v is a type parameter", typ) + } + + _, ok := typ.Underlying().(*types2.Interface) + return ok +} + func (w *writer) op(op ir.Op) { // TODO(mdempsky): Remove in favor of explicit codes? Would make // export data more stable against internal refactorings, but low @@ -1630,15 +1709,6 @@ func (w *writer) pkgDecl(decl syntax.Decl) { break } - // Skip aliases to uninstantiated generic types. - // TODO(mdempsky): Revisit after #46477 is resolved. - if name.IsAlias() { - named, ok := name.Type().(*types2.Named) - if ok && named.TypeParams().Len() != 0 && named.TypeArgs().Len() == 0 { - break - } - } - w.Code(declOther) w.pkgObjs(decl.Name) diff --git a/src/cmd/compile/internal/reflectdata/reflect.go b/src/cmd/compile/internal/reflectdata/reflect.go index c809f4658d..633700afb0 100644 --- a/src/cmd/compile/internal/reflectdata/reflect.go +++ b/src/cmd/compile/internal/reflectdata/reflect.go @@ -1223,10 +1223,17 @@ func writeType(t *types.Type) *obj.LSym { } } - ot = dextratypeData(lsym, ot, t) - objw.Global(lsym, int32(ot), int16(obj.DUPOK|obj.RODATA)) // Note: DUPOK is required to ensure that we don't end up with more - // than one type descriptor for a given type. + // than one type descriptor for a given type, if the type descriptor + // can be defined in multiple packages, that is, unnamed types and + // instantiated types. + dupok := 0 + if tbase.Sym() == nil || tbase.IsFullyInstantiated() { + dupok = obj.DUPOK + } + + ot = dextratypeData(lsym, ot, t) + objw.Global(lsym, int32(ot), int16(dupok|obj.RODATA)) // The linker will leave a table of all the typelinks for // types in the binary, so the runtime can find them. @@ -1846,16 +1853,17 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy newnam := ir.MethodSym(rcvr, method.Sym) lsym := newnam.Linksym() - if newnam.Siggen() { - return lsym - } - newnam.SetSiggen(true) // Unified IR creates its own wrappers. if base.Debug.Unified != 0 { return lsym } + if newnam.Siggen() { + return lsym + } + newnam.SetSiggen(true) + methodrcvr := method.Type.Recv().Type // For generic methods, we need to generate the wrapper even if the receiver // types are identical, because we want to add the dictionary. @@ -1946,7 +1954,7 @@ func methodWrapper(rcvr *types.Type, method *types.Field, forItab bool) *obj.LSy // Target method uses shaped names. targs2 := make([]*types.Type, len(targs)) - origRParams := deref(orig).OrigSym().Def.(*ir.Name).Type().RParams() + origRParams := deref(orig).OrigType().RParams() for i, t := range targs { targs2[i] = typecheck.Shapify(t, i, origRParams[i]) } diff --git a/src/cmd/compile/internal/riscv64/galign.go b/src/cmd/compile/internal/riscv64/galign.go index 846ed8fb38..4244afba3e 100644 --- a/src/cmd/compile/internal/riscv64/galign.go +++ b/src/cmd/compile/internal/riscv64/galign.go @@ -21,4 +21,6 @@ func Init(arch *ssagen.ArchInfo) { arch.SSAMarkMoves = ssaMarkMoves arch.SSAGenValue = ssaGenValue arch.SSAGenBlock = ssaGenBlock + arch.LoadRegResult = loadRegResult + arch.SpillArgReg = spillArgReg } diff --git a/src/cmd/compile/internal/riscv64/ggen.go b/src/cmd/compile/internal/riscv64/ggen.go index 9df739456b..0f37f65fcf 100644 --- a/src/cmd/compile/internal/riscv64/ggen.go +++ b/src/cmd/compile/internal/riscv64/ggen.go @@ -29,7 +29,7 @@ func zeroRange(pp *objw.Progs, p *obj.Prog, off, cnt int64, _ *uint32) *obj.Prog } if cnt <= int64(128*types.PtrSize) { - p = pp.Append(p, riscv.AADDI, obj.TYPE_CONST, 0, off, obj.TYPE_REG, riscv.REG_A0, 0) + p = pp.Append(p, riscv.AADDI, obj.TYPE_CONST, 0, off, obj.TYPE_REG, riscv.REG_X25, 0) p.Reg = riscv.REG_SP p = pp.Append(p, obj.ADUFFZERO, obj.TYPE_NONE, 0, 0, obj.TYPE_MEM, 0, 0) p.To.Name = obj.NAME_EXTERN diff --git a/src/cmd/compile/internal/riscv64/ssa.go b/src/cmd/compile/internal/riscv64/ssa.go index 1359b6a0c3..b6e6dc1a03 100644 --- a/src/cmd/compile/internal/riscv64/ssa.go +++ b/src/cmd/compile/internal/riscv64/ssa.go @@ -7,6 +7,7 @@ package riscv64 import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" + "cmd/compile/internal/objw" "cmd/compile/internal/ssa" "cmd/compile/internal/ssagen" "cmd/compile/internal/types" @@ -230,6 +231,19 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { p.From.Type = obj.TYPE_REG p.From.Reg = v.Args[0].Reg() ssagen.AddrAuto(&p.To, v) + case ssa.OpArgIntReg, ssa.OpArgFloatReg: + // The assembler needs to wrap the entry safepoint/stack growth code with spill/unspill + // The loop only runs once. + for _, a := range v.Block.Func.RegArgs { + // Pass the spill/unspill information along to the assembler, offset by size of + // the saved LR slot. + addr := ssagen.SpillSlotAddr(a, riscv.REG_SP, base.Ctxt.FixedFrameSize()) + s.FuncInfo().AddSpill( + obj.RegSpill{Reg: a.Reg, Addr: addr, Unspill: loadByType(a.Type), Spill: storeByType(a.Type)}) + } + v.Block.Func.RegArgs = nil + + ssagen.CheckArgReg(v) case ssa.OpSP, ssa.OpSB, ssa.OpGetG: // nothing to do case ssa.OpRISCV64MOVBreg, ssa.OpRISCV64MOVHreg, ssa.OpRISCV64MOVWreg, @@ -648,7 +662,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) { } case ssa.OpRISCV64LoweredGetClosurePtr: - // Closure pointer is S4 (riscv.REG_CTXT). + // Closure pointer is S10 (riscv.REG_CTXT). ssagen.CheckLoweredGetClosurePtr(v) case ssa.OpRISCV64LoweredGetCallerSP: @@ -773,3 +787,22 @@ func ssaGenBlock(s *ssagen.State, b, next *ssa.Block) { b.Fatalf("Unhandled block: %s", b.LongString()) } } + +func loadRegResult(s *ssagen.State, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog { + p := s.Prog(loadByType(t)) + p.From.Type = obj.TYPE_MEM + p.From.Name = obj.NAME_AUTO + p.From.Sym = n.Linksym() + p.From.Offset = n.FrameOffset() + off + p.To.Type = obj.TYPE_REG + p.To.Reg = reg + return p +} + +func spillArgReg(pp *objw.Progs, p *obj.Prog, f *ssa.Func, t *types.Type, reg int16, n *ir.Name, off int64) *obj.Prog { + p = pp.Append(p, storeByType(t), obj.TYPE_REG, reg, 0, obj.TYPE_MEM, 0, n.FrameOffset()+off) + p.To.Name = obj.NAME_PARAM + p.To.Sym = n.Linksym() + p.Pos = p.Pos.WithNotStmt() + return p +} diff --git a/src/cmd/compile/internal/ssa/config.go b/src/cmd/compile/internal/ssa/config.go index 5ab7240acf..fa5b02b325 100644 --- a/src/cmd/compile/internal/ssa/config.go +++ b/src/cmd/compile/internal/ssa/config.go @@ -296,6 +296,8 @@ func NewConfig(arch string, types Types, ctxt *obj.Link, optimize, softfloat boo c.registers = registersRISCV64[:] c.gpRegMask = gpRegMaskRISCV64 c.fpRegMask = fpRegMaskRISCV64 + // c.intParamRegs = paramIntRegRISCV64 + // c.floatParamRegs = paramFloatRegRISCV64 c.FPReg = framepointerRegRISCV64 c.hasGReg = true case "wasm": diff --git a/src/cmd/compile/internal/ssa/gen/AMD64.rules b/src/cmd/compile/internal/ssa/gen/AMD64.rules index 47a6af003c..87fe0fbee1 100644 --- a/src/cmd/compile/internal/ssa/gen/AMD64.rules +++ b/src/cmd/compile/internal/ssa/gen/AMD64.rules @@ -2073,7 +2073,7 @@ (CMPXCHGLlock [off1+off2] {sym} ptr old new_ mem) // We don't need the conditional move if we know the arg of BSF is not zero. -(CMOVQEQ x _ (Select1 (BSFQ (ORQconst [c] _)))) && c != 0 => x +(CMOVQEQ x _ (Select1 (BS(F|R)Q (ORQconst [c] _)))) && c != 0 => x // Extension is unnecessary for trailing zeros. (BSFQ (ORQconst [1<<8] (MOVBQZX x))) => (BSFQ (ORQconst [1<<8] x)) (BSFQ (ORQconst [1<<16] (MOVWQZX x))) => (BSFQ (ORQconst [1<<16] x)) diff --git a/src/cmd/compile/internal/ssa/gen/ARM64.rules b/src/cmd/compile/internal/ssa/gen/ARM64.rules index be8be4ebe3..1163ae837b 100644 --- a/src/cmd/compile/internal/ssa/gen/ARM64.rules +++ b/src/cmd/compile/internal/ssa/gen/ARM64.rules @@ -1918,7 +1918,11 @@ // (x & ac) >> sc (SRLconst [sc] (ANDconst [ac] x)) && isARM64BFMask(sc, ac, sc) => (UBFX [armBFAuxInt(sc, arm64BFWidth(ac, sc))] x) - +// merge ANDconst and ubfx into ubfx +(ANDconst [c] (UBFX [bfc] x)) && isARM64BFMask(0, c, 0) => + (UBFX [armBFAuxInt(bfc.getARM64BFlsb(), min(bfc.getARM64BFwidth(), arm64BFWidth(c, 0)))] x) +(UBFX [bfc] (ANDconst [c] x)) && isARM64BFMask(0, c, 0) && bfc.getARM64BFlsb() + bfc.getARM64BFwidth() <= arm64BFWidth(c, 0) => + (UBFX [bfc] x) // merge ubfx and zerso-extension into ubfx (MOVWUreg (UBFX [bfc] x)) && bfc.getARM64BFwidth() <= 32 => (UBFX [bfc] x) (MOVHUreg (UBFX [bfc] x)) && bfc.getARM64BFwidth() <= 16 => (UBFX [bfc] x) diff --git a/src/cmd/compile/internal/ssa/gen/PPC64.rules b/src/cmd/compile/internal/ssa/gen/PPC64.rules index c3f07a4e22..eb9fe3cf72 100644 --- a/src/cmd/compile/internal/ssa/gen/PPC64.rules +++ b/src/cmd/compile/internal/ssa/gen/PPC64.rules @@ -1479,7 +1479,11 @@ && clobber(call) => (Move [sz] dst src mem) -// Prefetch instructions (aux is option: 0 - DCBT ; 8 - DCBT stream) +// Prefetch instructions (TH specified using aux field) +// For DCBT Ra,Rb,TH, A value of TH indicates: +// 0, hint this cache line will be used soon. (PrefetchCache) +// 16, hint this cache line will not be used for long. (PrefetchCacheStreamed) +// See ISA 3.0 Book II 4.3.2 for more detail. https://openpower.foundation/specifications/isa/ (PrefetchCache ptr mem) => (DCBT ptr mem [0]) -(PrefetchCacheStreamed ptr mem) => (DCBT ptr mem [8]) +(PrefetchCacheStreamed ptr mem) => (DCBT ptr mem [16]) diff --git a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go index 59d8af1a9d..ff78be263e 100644 --- a/src/cmd/compile/internal/ssa/gen/PPC64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/PPC64Ops.go @@ -82,7 +82,9 @@ var regNamesPPC64 = []string{ "F28", "F29", "F30", - "F31", + // "F31", the allocator is limited to 64 entries. We sacrifice this FPR to support XER. + + "XER", // If you add registers, update asyncPreempt in runtime. @@ -124,7 +126,7 @@ func init() { var ( gp = buildReg("R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29") - fp = buildReg("F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26") + fp = buildReg("F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30") sp = buildReg("SP") sb = buildReg("SB") gr = buildReg("g") diff --git a/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go b/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go index 076919773b..f09910782d 100644 --- a/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go +++ b/src/cmd/compile/internal/ssa/gen/RISCV64Ops.go @@ -26,7 +26,7 @@ import ( const ( riscv64REG_G = 27 - riscv64REG_CTXT = 20 + riscv64REG_CTXT = 26 riscv64REG_LR = 1 riscv64REG_SP = 2 riscv64REG_GP = 3 @@ -115,7 +115,7 @@ func init() { panic("Too many RISCV64 registers") } - regCtxt := regNamed["X20"] + regCtxt := regNamed["X26"] callerSave := gpMask | fpMask | regNamed["g"] var ( @@ -241,13 +241,13 @@ func init() { {name: "MOVconvert", argLength: 2, reg: gp11, asm: "MOV"}, // arg0, but converted to int/ptr as appropriate; arg1=mem // Calls - {name: "CALLstatic", argLength: 1, reg: call, aux: "CallOff", call: true}, // call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem - {name: "CALLtail", argLength: 1, reg: call, aux: "CallOff", call: true, tailCall: true}, // tail call static function aux.(*gc.Sym). arg0=mem, auxint=argsize, returns mem - {name: "CALLclosure", argLength: 3, reg: callClosure, aux: "CallOff", call: true}, // call function via closure. arg0=codeptr, arg1=closure, arg2=mem, auxint=argsize, returns mem - {name: "CALLinter", argLength: 2, reg: callInter, aux: "CallOff", call: true}, // call fn by pointer. arg0=codeptr, arg1=mem, auxint=argsize, returns mem + {name: "CALLstatic", argLength: -1, reg: call, aux: "CallOff", call: true}, // call static function aux.(*gc.Sym). last arg=mem, auxint=argsize, returns mem + {name: "CALLtail", argLength: -1, reg: call, aux: "CallOff", call: true, tailCall: true}, // tail call static function aux.(*gc.Sym). last arg=mem, auxint=argsize, returns mem + {name: "CALLclosure", argLength: -1, reg: callClosure, aux: "CallOff", call: true}, // call function via closure. arg0=codeptr, arg1=closure, last arg=mem, auxint=argsize, returns mem + {name: "CALLinter", argLength: -1, reg: callInter, aux: "CallOff", call: true}, // call fn by pointer. arg0=codeptr, last arg=mem, auxint=argsize, returns mem // duffzero - // arg0 = address of memory to zero (in X10, changed as side effect) + // arg0 = address of memory to zero (in X25, changed as side effect) // arg1 = mem // auxint = offset into duffzero code to start executing // X1 (link register) changed because of function call @@ -257,16 +257,16 @@ func init() { aux: "Int64", argLength: 2, reg: regInfo{ - inputs: []regMask{regNamed["X10"]}, - clobbers: regNamed["X1"] | regNamed["X10"], + inputs: []regMask{regNamed["X25"]}, + clobbers: regNamed["X1"] | regNamed["X25"], }, typ: "Mem", faultOnNilArg0: true, }, // duffcopy - // arg0 = address of dst memory (in X11, changed as side effect) - // arg1 = address of src memory (in X10, changed as side effect) + // arg0 = address of dst memory (in X25, changed as side effect) + // arg1 = address of src memory (in X24, changed as side effect) // arg2 = mem // auxint = offset into duffcopy code to start executing // X1 (link register) changed because of function call @@ -276,8 +276,8 @@ func init() { aux: "Int64", argLength: 3, reg: regInfo{ - inputs: []regMask{regNamed["X11"], regNamed["X10"]}, - clobbers: regNamed["X1"] | regNamed["X10"] | regNamed["X11"], + inputs: []regMask{regNamed["X25"], regNamed["X24"]}, + clobbers: regNamed["X1"] | regNamed["X24"] | regNamed["X25"], }, typ: "Mem", faultOnNilArg0: true, @@ -477,5 +477,9 @@ func init() { gpregmask: gpMask, fpregmask: fpMask, framepointerreg: -1, // not used + // Integer parameters passed in register X10-X17, X8-X9, X18-X23 + ParamIntRegNames: "X10 X11 X12 X13 X14 X15 X16 X17 X8 X9 X18 X19 X20 X21 X22 X23", + // Float parameters passed in register F10-F17, F8-F9, F18-F23 + ParamFloatRegNames: "F10 F11 F12 F13 F14 F15 F16 F17 F8 F9 F18 F19 F20 F21 F22 F23", }) } diff --git a/src/cmd/compile/internal/ssa/opGen.go b/src/cmd/compile/internal/ssa/opGen.go index 81fe5d4c23..5b379a7fd3 100644 --- a/src/cmd/compile/internal/ssa/opGen.go +++ b/src/cmd/compile/internal/ssa/opGen.go @@ -25088,11 +25088,11 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFADD, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -25103,11 +25103,11 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFADDS, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -25145,11 +25145,11 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFSUB, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -25159,11 +25159,11 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFSUBS, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -25322,11 +25322,11 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFMUL, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -25337,11 +25337,11 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFMULS, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -25351,12 +25351,12 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFMADD, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {2, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {2, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -25366,12 +25366,12 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFMADDS, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {2, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {2, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -25381,12 +25381,12 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFMSUB, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {2, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {2, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -25396,12 +25396,12 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFMSUBS, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {2, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {2, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -25845,11 +25845,11 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFDIV, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -25859,11 +25859,11 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFDIVS, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -25985,10 +25985,10 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFCTIDZ, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -25998,10 +25998,10 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFCTIWZ, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26011,10 +26011,10 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFCFID, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26024,10 +26024,10 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFCFIDS, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26037,10 +26037,10 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFRSP, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26050,7 +26050,7 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AMFVSRD, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ {0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 @@ -26066,7 +26066,7 @@ var opcodeTable = [...]opInfo{ {0, 1073733624}, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26228,10 +26228,10 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFNEG, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26241,10 +26241,10 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFSQRT, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26254,10 +26254,10 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFSQRTS, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26267,10 +26267,10 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFRIM, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26280,10 +26280,10 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFRIP, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26293,10 +26293,10 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFRIZ, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26306,10 +26306,10 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFRIN, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26319,10 +26319,10 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFABS, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26332,10 +26332,10 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFNABS, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26345,11 +26345,11 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFCPSGN, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26765,7 +26765,7 @@ var opcodeTable = [...]opInfo{ {1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26779,7 +26779,7 @@ var opcodeTable = [...]opInfo{ {1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26849,7 +26849,7 @@ var opcodeTable = [...]opInfo{ {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26865,7 +26865,7 @@ var opcodeTable = [...]opInfo{ {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26934,8 +26934,8 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFMOVD, reg: regInfo{ inputs: []inputInfo{ - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 + {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -26948,8 +26948,8 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFMOVS, reg: regInfo{ inputs: []inputInfo{ - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 + {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -27007,9 +27007,9 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFMOVD, reg: regInfo{ inputs: []inputInfo{ - {2, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 - {1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 + {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 + {1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 + {2, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -27019,9 +27019,9 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFMOVS, reg: regInfo{ inputs: []inputInfo{ - {2, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 - {1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 + {0, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 + {1, 1073733630}, // SP SB R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 + {2, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -27149,7 +27149,7 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFMOVD, reg: regInfo{ outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -27161,7 +27161,7 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFMOVS, reg: regInfo{ outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -27171,8 +27171,8 @@ var opcodeTable = [...]opInfo{ asm: ppc64.AFCMPU, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 - {1, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 + {1, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -27433,10 +27433,10 @@ var opcodeTable = [...]opInfo{ zeroWidth: true, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -27447,10 +27447,10 @@ var opcodeTable = [...]opInfo{ zeroWidth: true, reg: regInfo{ inputs: []inputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, outputs: []outputInfo{ - {0, 576460743713488896}, // F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + {0, 9223372032559808512}, // F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, }, @@ -27461,7 +27461,7 @@ var opcodeTable = [...]opInfo{ clobberFlags: true, call: true, reg: regInfo{ - clobbers: 576460745860964344, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + clobbers: 9223372034707283960, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, { @@ -27472,7 +27472,7 @@ var opcodeTable = [...]opInfo{ call: true, tailCall: true, reg: regInfo{ - clobbers: 576460745860964344, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + clobbers: 9223372034707283960, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, { @@ -27486,7 +27486,7 @@ var opcodeTable = [...]opInfo{ {0, 4096}, // R12 {1, 2048}, // R11 }, - clobbers: 576460745860964344, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + clobbers: 9223372034707283960, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, { @@ -27499,7 +27499,7 @@ var opcodeTable = [...]opInfo{ inputs: []inputInfo{ {0, 4096}, // R12 }, - clobbers: 576460745860964344, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + clobbers: 9223372034707283960, // R3 R4 R5 R6 R7 R8 R9 R10 R11 R12 R14 R15 R16 R17 R18 R19 R20 R21 R22 R23 R24 R25 R26 R27 R28 R29 g F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, { @@ -27882,7 +27882,7 @@ var opcodeTable = [...]opInfo{ {0, 1048576}, // R20 {1, 2097152}, // R21 }, - clobbers: 576460746931312640, // R11 R12 R18 R19 R22 R23 R24 R25 R26 R27 R28 R29 R31 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 + clobbers: 9223372035777632256, // R11 R12 R18 R19 R22 R23 R24 R25 R26 R27 R28 R29 R31 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 }, }, { @@ -28875,7 +28875,7 @@ var opcodeTable = [...]opInfo{ { name: "CALLstatic", auxType: auxCallOff, - argLen: 1, + argLen: -1, call: true, reg: regInfo{ clobbers: 9223372035781033968, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 @@ -28884,7 +28884,7 @@ var opcodeTable = [...]opInfo{ { name: "CALLtail", auxType: auxCallOff, - argLen: 1, + argLen: -1, call: true, tailCall: true, reg: regInfo{ @@ -28894,11 +28894,11 @@ var opcodeTable = [...]opInfo{ { name: "CALLclosure", auxType: auxCallOff, - argLen: 3, + argLen: -1, call: true, reg: regInfo{ inputs: []inputInfo{ - {1, 524288}, // X20 + {1, 33554432}, // X26 {0, 1006632946}, // SP X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 X28 X29 X30 }, clobbers: 9223372035781033968, // X5 X6 X7 X8 X9 X10 X11 X12 X13 X14 X15 X16 X17 X18 X19 X20 X21 X22 X23 X24 X25 X26 g X28 X29 X30 F0 F1 F2 F3 F4 F5 F6 F7 F8 F9 F10 F11 F12 F13 F14 F15 F16 F17 F18 F19 F20 F21 F22 F23 F24 F25 F26 F27 F28 F29 F30 F31 @@ -28907,7 +28907,7 @@ var opcodeTable = [...]opInfo{ { name: "CALLinter", auxType: auxCallOff, - argLen: 2, + argLen: -1, call: true, reg: regInfo{ inputs: []inputInfo{ @@ -28923,9 +28923,9 @@ var opcodeTable = [...]opInfo{ faultOnNilArg0: true, reg: regInfo{ inputs: []inputInfo{ - {0, 512}, // X10 + {0, 16777216}, // X25 }, - clobbers: 512, // X10 + clobbers: 16777216, // X25 }, }, { @@ -28936,10 +28936,10 @@ var opcodeTable = [...]opInfo{ faultOnNilArg1: true, reg: regInfo{ inputs: []inputInfo{ - {0, 1024}, // X11 - {1, 512}, // X10 + {0, 16777216}, // X25 + {1, 8388608}, // X24 }, - clobbers: 1536, // X10 X11 + clobbers: 25165824, // X24 X25 }, }, { @@ -29189,7 +29189,7 @@ var opcodeTable = [...]opInfo{ argLen: 0, reg: regInfo{ outputs: []outputInfo{ - {0, 524288}, // X20 + {0, 33554432}, // X26 }, }, }, @@ -37281,12 +37281,12 @@ var registersPPC64 = [...]Register{ {60, ppc64.REG_F28, -1, "F28"}, {61, ppc64.REG_F29, -1, "F29"}, {62, ppc64.REG_F30, -1, "F30"}, - {63, ppc64.REG_F31, -1, "F31"}, + {63, ppc64.REG_XER, -1, "XER"}, } var paramIntRegPPC64 = []int8{3, 4, 5, 6, 7, 8, 9, 10, 14, 15, 16, 17} var paramFloatRegPPC64 = []int8{33, 34, 35, 36, 37, 38, 39, 40, 41, 42, 43, 44} var gpRegMaskPPC64 = regMask(1073733624) -var fpRegMaskPPC64 = regMask(576460743713488896) +var fpRegMaskPPC64 = regMask(9223372032559808512) var specialRegMaskPPC64 = regMask(0) var framepointerRegPPC64 = int8(-1) var linkRegPPC64 = int8(-1) @@ -37356,8 +37356,8 @@ var registersRISCV64 = [...]Register{ {62, riscv.REG_F31, -1, "F31"}, {63, 0, -1, "SB"}, } -var paramIntRegRISCV64 = []int8(nil) -var paramFloatRegRISCV64 = []int8(nil) +var paramIntRegRISCV64 = []int8{9, 10, 11, 12, 13, 14, 15, 16, 7, 8, 17, 18, 19, 20, 21, 22} +var paramFloatRegRISCV64 = []int8{41, 42, 43, 44, 45, 46, 47, 48, 39, 40, 49, 50, 51, 52, 53, 54} var gpRegMaskRISCV64 = regMask(1006632944) var fpRegMaskRISCV64 = regMask(9223372034707292160) var specialRegMaskRISCV64 = regMask(0) diff --git a/src/cmd/compile/internal/ssa/prove.go b/src/cmd/compile/internal/ssa/prove.go index b203584c6b..98af586cab 100644 --- a/src/cmd/compile/internal/ssa/prove.go +++ b/src/cmd/compile/internal/ssa/prove.go @@ -824,6 +824,9 @@ func prove(f *Func) { } lensVars[b] = append(lensVars[b], v) } + case OpCtz64, OpCtz32, OpCtz16, OpCtz8, OpBitLen64, OpBitLen32, OpBitLen16, OpBitLen8: + ft.update(b, v, ft.zero, signed, gt|eq) + // TODO: we could also do <= 64/32/16/8, if that helped. } } } @@ -1372,7 +1375,9 @@ func isNonNegative(v *Value) bool { case OpStringLen, OpSliceLen, OpSliceCap, OpZeroExt8to64, OpZeroExt16to64, OpZeroExt32to64, OpZeroExt8to32, OpZeroExt16to32, OpZeroExt8to16, - OpCtz64, OpCtz32, OpCtz16, OpCtz8: + OpCtz64, OpCtz32, OpCtz16, OpCtz8, + OpCtz64NonZero, OpCtz32NonZero, OpCtz16NonZero, OpCtz8NonZero, + OpBitLen64, OpBitLen32, OpBitLen16, OpBitLen8: return true case OpRsh64Ux64, OpRsh32Ux64: diff --git a/src/cmd/compile/internal/ssa/rewrite.go b/src/cmd/compile/internal/ssa/rewrite.go index 9136c59e65..eb8fa0c02a 100644 --- a/src/cmd/compile/internal/ssa/rewrite.go +++ b/src/cmd/compile/internal/ssa/rewrite.go @@ -40,6 +40,7 @@ func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter, deadcode deadValu var states map[string]bool for { change := false + deadChange := false for _, b := range f.Blocks { var b0 *Block if debug > 1 { @@ -73,7 +74,7 @@ func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter, deadcode deadValu // Not quite a deadcode pass, because it does not handle cycles. // But it should help Uses==1 rules to fire. v.reset(OpInvalid) - change = true + deadChange = true } // No point rewriting values which aren't used. continue @@ -145,15 +146,16 @@ func applyRewrite(f *Func, rb blockRewriter, rv valueRewriter, deadcode deadValu } } } - if !change { + if !change && !deadChange { break } iters++ - if iters > 1000 || debug >= 2 { + if (iters > 1000 || debug >= 2) && change { // We've done a suspiciously large number of rewrites (or we're in debug mode). // As of Sep 2021, 90% of rewrites complete in 4 iterations or fewer // and the maximum value encountered during make.bash is 12. // Start checking for cycles. (This is too expensive to do routinely.) + // Note: we avoid this path for deadChange-only iterations, to fix #51639. if states == nil { states = make(map[string]bool) } diff --git a/src/cmd/compile/internal/ssa/rewriteAMD64.go b/src/cmd/compile/internal/ssa/rewriteAMD64.go index 0c789d6b49..c17d8b03e2 100644 --- a/src/cmd/compile/internal/ssa/rewriteAMD64.go +++ b/src/cmd/compile/internal/ssa/rewriteAMD64.go @@ -5191,6 +5191,29 @@ func rewriteValueAMD64_OpAMD64CMOVQEQ(v *Value) bool { v.copyOf(x) return true } + // match: (CMOVQEQ x _ (Select1 (BSRQ (ORQconst [c] _)))) + // cond: c != 0 + // result: x + for { + x := v_0 + if v_2.Op != OpSelect1 { + break + } + v_2_0 := v_2.Args[0] + if v_2_0.Op != OpAMD64BSRQ { + break + } + v_2_0_0 := v_2_0.Args[0] + if v_2_0_0.Op != OpAMD64ORQconst { + break + } + c := auxIntToInt32(v_2_0_0.AuxInt) + if !(c != 0) { + break + } + v.copyOf(x) + return true + } return false } func rewriteValueAMD64_OpAMD64CMOVQGE(v *Value) bool { diff --git a/src/cmd/compile/internal/ssa/rewriteARM64.go b/src/cmd/compile/internal/ssa/rewriteARM64.go index c5f53e5507..2ed1c0a04a 100644 --- a/src/cmd/compile/internal/ssa/rewriteARM64.go +++ b/src/cmd/compile/internal/ssa/rewriteARM64.go @@ -2283,6 +2283,24 @@ func rewriteValueARM64_OpARM64ANDconst(v *Value) bool { v.AddArg(x) return true } + // match: (ANDconst [c] (UBFX [bfc] x)) + // cond: isARM64BFMask(0, c, 0) + // result: (UBFX [armBFAuxInt(bfc.getARM64BFlsb(), min(bfc.getARM64BFwidth(), arm64BFWidth(c, 0)))] x) + for { + c := auxIntToInt64(v.AuxInt) + if v_0.Op != OpARM64UBFX { + break + } + bfc := auxIntToArm64BitField(v_0.AuxInt) + x := v_0.Args[0] + if !(isARM64BFMask(0, c, 0)) { + break + } + v.reset(OpARM64UBFX) + v.AuxInt = arm64BitFieldToAuxInt(armBFAuxInt(bfc.getARM64BFlsb(), min(bfc.getARM64BFwidth(), arm64BFWidth(c, 0)))) + v.AddArg(x) + return true + } return false } func rewriteValueARM64_OpARM64ANDshiftLL(v *Value) bool { @@ -21802,6 +21820,24 @@ func rewriteValueARM64_OpARM64UBFIZ(v *Value) bool { } func rewriteValueARM64_OpARM64UBFX(v *Value) bool { v_0 := v.Args[0] + // match: (UBFX [bfc] (ANDconst [c] x)) + // cond: isARM64BFMask(0, c, 0) && bfc.getARM64BFlsb() + bfc.getARM64BFwidth() <= arm64BFWidth(c, 0) + // result: (UBFX [bfc] x) + for { + bfc := auxIntToArm64BitField(v.AuxInt) + if v_0.Op != OpARM64ANDconst { + break + } + c := auxIntToInt64(v_0.AuxInt) + x := v_0.Args[0] + if !(isARM64BFMask(0, c, 0) && bfc.getARM64BFlsb()+bfc.getARM64BFwidth() <= arm64BFWidth(c, 0)) { + break + } + v.reset(OpARM64UBFX) + v.AuxInt = arm64BitFieldToAuxInt(bfc) + v.AddArg(x) + return true + } // match: (UBFX [bfc] (SRLconst [sc] x)) // cond: sc+bfc.getARM64BFwidth()+bfc.getARM64BFlsb() < 64 // result: (UBFX [armBFAuxInt(bfc.getARM64BFlsb()+sc, bfc.getARM64BFwidth())] x) diff --git a/src/cmd/compile/internal/ssa/rewritePPC64.go b/src/cmd/compile/internal/ssa/rewritePPC64.go index 7592b4f505..5da6d9641c 100644 --- a/src/cmd/compile/internal/ssa/rewritePPC64.go +++ b/src/cmd/compile/internal/ssa/rewritePPC64.go @@ -14140,12 +14140,12 @@ func rewriteValuePPC64_OpPrefetchCacheStreamed(v *Value) bool { v_1 := v.Args[1] v_0 := v.Args[0] // match: (PrefetchCacheStreamed ptr mem) - // result: (DCBT ptr mem [8]) + // result: (DCBT ptr mem [16]) for { ptr := v_0 mem := v_1 v.reset(OpPPC64DCBT) - v.AuxInt = int64ToAuxInt(8) + v.AuxInt = int64ToAuxInt(16) v.AddArg2(ptr, mem) return true } diff --git a/src/cmd/compile/internal/ssagen/ssa.go b/src/cmd/compile/internal/ssagen/ssa.go index 60747d93ca..a214a1e8f9 100644 --- a/src/cmd/compile/internal/ssagen/ssa.go +++ b/src/cmd/compile/internal/ssagen/ssa.go @@ -224,11 +224,6 @@ func AbiForBodylessFuncStackMap(fn *ir.Func) *abi.ABIConfig { return ssaConfig.ABI0.Copy() // No idea what races will result, be safe } -// These are disabled but remain ready for use in case they are needed for the next regabi port. -// TODO if they are not needed for 1.18 / next register abi port, delete them. -const magicNameDotSuffix = ".*disabled*MagicMethodNameForTestingRegisterABI" -const magicLastTypeName = "*disabled*MagicLastTypeNameForTestingRegisterABI" - // abiForFunc implements ABI policy for a function, but does not return a copy of the ABI. // Passing a nil function returns the default ABI based on experiment configuration. func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig { @@ -251,36 +246,13 @@ func abiForFunc(fn *ir.Func, abi0, abi1 *abi.ABIConfig) *abi.ABIConfig { a := abi0 if fn != nil { - name := ir.FuncName(fn) - magicName := strings.HasSuffix(name, magicNameDotSuffix) if fn.Pragma&ir.RegisterParams != 0 { // TODO(register args) remove after register abi is working - if strings.Contains(name, ".") { - if !magicName { - base.ErrorfAt(fn.Pos(), "Calls to //go:registerparams method %s won't work, remove the pragma from the declaration.", name) - } - } - a = abi1 - } else if magicName { - if base.FmtPos(fn.Pos()) == ":1" { - // no way to put a pragma here, and it will error out in the real source code if they did not do it there. - a = abi1 - } else { - base.ErrorfAt(fn.Pos(), "Methods with magic name %s (method %s) must also specify //go:registerparams", magicNameDotSuffix[1:], name) - } - } - if regAbiForFuncType(fn.Type().FuncType()) { - // fmt.Printf("Saw magic last type name for function %s\n", name) a = abi1 } } return a } -func regAbiForFuncType(ft *types.Func) bool { - np := ft.Params.NumFields() - return np > 0 && strings.Contains(ft.Params.FieldType(np-1).String(), magicLastTypeName) -} - // dvarint writes a varint v to the funcdata in symbol x and returns the new offset func dvarint(x *obj.LSym, off int, v int64) int { if v < 0 || v > 1e9 { @@ -4950,24 +4922,6 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val callABI := s.f.ABIDefault - if !buildcfg.Experiment.RegabiArgs { - var magicFnNameSym *types.Sym - if fn.Name() != nil { - magicFnNameSym = fn.Name().Sym() - ss := magicFnNameSym.Name - if strings.HasSuffix(ss, magicNameDotSuffix) { - callABI = s.f.ABI1 - } - } - if magicFnNameSym == nil && n.Op() == ir.OCALLINTER { - magicFnNameSym = fn.(*ir.SelectorExpr).Sym() - ss := magicFnNameSym.Name - if strings.HasSuffix(ss, magicNameDotSuffix[1:]) { - callABI = s.f.ABI1 - } - } - } - if k != callNormal && k != callTail && (len(n.Args) != 0 || n.Op() == ir.OCALLINTER || n.X.Type().NumResults() != 0) { s.Fatalf("go/defer call with arguments: %v", n) } @@ -5016,13 +4970,6 @@ func (s *state) call(n *ir.CallExpr, k callKind, returnResultAddr bool) *ssa.Val } } - if !buildcfg.Experiment.RegabiArgs { - if regAbiForFuncType(n.X.Type().FuncType()) { - // Magic last type in input args to call - callABI = s.f.ABI1 - } - } - params := callABI.ABIAnalyze(n.X.Type(), false /* Do not set (register) nNames from caller side -- can cause races. */) types.CalcSize(fn.Type()) stksize := params.ArgWidth() // includes receiver, args, and results diff --git a/src/cmd/compile/internal/syntax/parser_test.go b/src/cmd/compile/internal/syntax/parser_test.go index e258a17c38..66690a527a 100644 --- a/src/cmd/compile/internal/syntax/parser_test.go +++ b/src/cmd/compile/internal/syntax/parser_test.go @@ -8,6 +8,7 @@ import ( "bytes" "flag" "fmt" + "internal/testenv" "io/ioutil" "path/filepath" "regexp" @@ -74,11 +75,14 @@ func TestStdLib(t *testing.T) { lines uint } + goroot := testenv.GOROOT(t) + results := make(chan parseResult) go func() { defer close(results) for _, dir := range []string{ - runtime.GOROOT(), + filepath.Join(goroot, "src"), + filepath.Join(goroot, "misc"), } { walkDirs(t, dir, func(filename string) { if skipRx != nil && skipRx.MatchString(filename) { diff --git a/src/cmd/compile/internal/syntax/scanner.go b/src/cmd/compile/internal/syntax/scanner.go index 218bc24e61..807d838386 100644 --- a/src/cmd/compile/internal/syntax/scanner.go +++ b/src/cmd/compile/internal/syntax/scanner.go @@ -39,8 +39,8 @@ type scanner struct { lit string // valid if tok is _Name, _Literal, or _Semi ("semicolon", "newline", or "EOF"); may be malformed if bad is true bad bool // valid if tok is _Literal, true if a syntax error occurred, lit may be malformed kind LitKind // valid if tok is _Literal - op Operator // valid if tok is _Operator, _AssignOp, or _IncOp - prec int // valid if tok is _Operator, _AssignOp, or _IncOp + op Operator // valid if tok is _Operator, _Star, _AssignOp, or _IncOp + prec int // valid if tok is _Operator, _Star, _AssignOp, or _IncOp } func (s *scanner) init(src io.Reader, errh func(line, col uint, msg string), mode uint) { diff --git a/src/cmd/compile/internal/test/fixedbugs_test.go b/src/cmd/compile/internal/test/fixedbugs_test.go index 376b45edfc..cd0d5fc353 100644 --- a/src/cmd/compile/internal/test/fixedbugs_test.go +++ b/src/cmd/compile/internal/test/fixedbugs_test.go @@ -72,7 +72,7 @@ func TestIssue16214(t *testing.T) { t.Fatalf("could not write file: %v", err) } - cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-S", "-o", filepath.Join(dir, "out.o"), src) + cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=main", "-S", "-o", filepath.Join(dir, "out.o"), src) out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("go tool compile: %v\n%s", err, out) diff --git a/src/cmd/compile/internal/test/lang_test.go b/src/cmd/compile/internal/test/lang_test.go index 67c1551292..66ab8401c6 100644 --- a/src/cmd/compile/internal/test/lang_test.go +++ b/src/cmd/compile/internal/test/lang_test.go @@ -56,7 +56,7 @@ func TestInvalidLang(t *testing.T) { } func testLang(t *testing.T, lang, src, outfile string) error { - run := []string{testenv.GoToolPath(t), "tool", "compile", "-lang", lang, "-o", outfile, src} + run := []string{testenv.GoToolPath(t), "tool", "compile", "-p=p", "-lang", lang, "-o", outfile, src} t.Log(run) out, err := exec.Command(run[0], run[1:]...).CombinedOutput() t.Logf("%s", out) diff --git a/src/cmd/compile/internal/test/reproduciblebuilds_test.go b/src/cmd/compile/internal/test/reproduciblebuilds_test.go index 4d84f9cdef..0a1a5e9b99 100644 --- a/src/cmd/compile/internal/test/reproduciblebuilds_test.go +++ b/src/cmd/compile/internal/test/reproduciblebuilds_test.go @@ -41,7 +41,7 @@ func TestReproducibleBuilds(t *testing.T) { for i := 0; i < iters; i++ { // Note: use -c 2 to expose any nondeterminism which is the result // of the runtime scheduler. - out, err := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-c", "2", "-o", tmp.Name(), filepath.Join("testdata", "reproducible", test)).CombinedOutput() + out, err := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=p", "-c", "2", "-o", tmp.Name(), filepath.Join("testdata", "reproducible", test)).CombinedOutput() if err != nil { t.Fatalf("failed to compile: %v\n%s", err, out) } @@ -89,7 +89,7 @@ func TestIssue38068(t *testing.T) { s := &scenarios[i] s.libpath = filepath.Join(tmpdir, s.tag+".a") // Note: use of "-p" required in order for DWARF to be generated. - cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-trimpath", "-p=issue38068", "-buildid=", s.args, "-o", s.libpath, src) + cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=issue38068", "-buildid=", s.args, "-o", s.libpath, src) out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("%v: %v:\n%s", cmd.Args, err, out) diff --git a/src/cmd/compile/internal/typecheck/const.go b/src/cmd/compile/internal/typecheck/const.go index fbe7c02c49..1422ab0031 100644 --- a/src/cmd/compile/internal/typecheck/const.go +++ b/src/cmd/compile/internal/typecheck/const.go @@ -16,7 +16,6 @@ import ( "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/types" - "cmd/internal/src" ) func roundFloat(v constant.Value, sz int64) constant.Value { @@ -99,10 +98,7 @@ func convlit1(n ir.Node, t *types.Type, explicit bool, context func() string) ir } n = ir.Copy(n) if t == nil { - base.Errorf("use of untyped nil") - n.SetDiag(true) - n.SetType(nil) - return n + base.Fatalf("use of untyped nil") } if !t.HasNil() { @@ -199,18 +195,14 @@ func convlit1(n ir.Node, t *types.Type, explicit bool, context func() string) ir return n } - if !n.Diag() { - if !t.Broke() { - if explicit { - base.Errorf("cannot convert %L to type %v", n, t) - } else if context != nil { - base.Errorf("cannot use %L as type %v in %s", n, t, context()) - } else { - base.Errorf("cannot use %L as type %v", n, t) - } - } - n.SetDiag(true) + if explicit { + base.Fatalf("cannot convert %L to type %v", n, t) + } else if context != nil { + base.Fatalf("cannot use %L as type %v in %s", n, t, context()) + } else { + base.Fatalf("cannot use %L as type %v", n, t) } + n.SetType(nil) return n } @@ -773,94 +765,6 @@ func anyCallOrChan(n ir.Node) bool { }) } -// A constSet represents a set of Go constant expressions. -type constSet struct { - m map[constSetKey]src.XPos -} - -type constSetKey struct { - typ *types.Type - val interface{} -} - -// add adds constant expression n to s. If a constant expression of -// equal value and identical type has already been added, then add -// reports an error about the duplicate value. -// -// pos provides position information for where expression n occurred -// (in case n does not have its own position information). what and -// where are used in the error message. -// -// n must not be an untyped constant. -func (s *constSet) add(pos src.XPos, n ir.Node, what, where string) { - if conv := n; conv.Op() == ir.OCONVIFACE { - conv := conv.(*ir.ConvExpr) - if conv.Implicit() { - n = conv.X - } - } - - if !ir.IsConstNode(n) || n.Type() == nil { - return - } - if n.Type().IsUntyped() { - base.Fatalf("%v is untyped", n) - } - - // Consts are only duplicates if they have the same value and - // identical types. - // - // In general, we have to use types.Identical to test type - // identity, because == gives false negatives for anonymous - // types and the byte/uint8 and rune/int32 builtin type - // aliases. However, this is not a problem here, because - // constant expressions are always untyped or have a named - // type, and we explicitly handle the builtin type aliases - // below. - // - // This approach may need to be revisited though if we fix - // #21866 by treating all type aliases like byte/uint8 and - // rune/int32. - - typ := n.Type() - switch typ { - case types.ByteType: - typ = types.Types[types.TUINT8] - case types.RuneType: - typ = types.Types[types.TINT32] - } - k := constSetKey{typ, ir.ConstValue(n)} - - if ir.HasUniquePos(n) { - pos = n.Pos() - } - - if s.m == nil { - s.m = make(map[constSetKey]src.XPos) - } - - if prevPos, isDup := s.m[k]; isDup { - base.ErrorfAt(pos, "duplicate %s %s in %s\n\tprevious %s at %v", - what, nodeAndVal(n), where, - what, base.FmtPos(prevPos)) - } else { - s.m[k] = pos - } -} - -// nodeAndVal reports both an expression and its constant value, if -// the latter is non-obvious. -// -// TODO(mdempsky): This could probably be a fmt.go flag. -func nodeAndVal(n ir.Node) string { - show := fmt.Sprint(n) - val := ir.ConstValue(n) - if s := fmt.Sprintf("%#v", val); show != s { - show += " (value " + s + ")" - } - return show -} - // evalunsafe evaluates a package unsafe operation and returns the result. func evalunsafe(n ir.Node) int64 { switch n.Op() { diff --git a/src/cmd/compile/internal/typecheck/crawler.go b/src/cmd/compile/internal/typecheck/crawler.go index 4394c6e698..40b518983a 100644 --- a/src/cmd/compile/internal/typecheck/crawler.go +++ b/src/cmd/compile/internal/typecheck/crawler.go @@ -66,9 +66,9 @@ func (p *crawler) markObject(n *ir.Name) { // inline bodies may be needed. For instantiated generic types, it visits the base // generic type, which has the relevant methods. func (p *crawler) markType(t *types.Type) { - if t.OrigSym() != nil { + if orig := t.OrigType(); orig != nil { // Convert to the base generic type. - t = t.OrigSym().Def.Type() + t = orig } if p.marked[t] { return @@ -154,9 +154,9 @@ func (p *crawler) markEmbed(t *types.Type) { t = t.Elem() } - if t.OrigSym() != nil { + if orig := t.OrigType(); orig != nil { // Convert to the base generic type. - t = t.OrigSym().Def.Type() + t = orig } if p.embedded[t] { @@ -194,9 +194,9 @@ func (p *crawler) markGeneric(t *types.Type) { if t.IsPtr() { t = t.Elem() } - if t.OrigSym() != nil { + if orig := t.OrigType(); orig != nil { // Convert to the base generic type. - t = t.OrigSym().Def.Type() + t = orig } if p.generic[t] { return @@ -229,7 +229,7 @@ func (p *crawler) checkForFullyInst(t *types.Type) { // them available for import, and so will not need // another round of method and dictionary // instantiation after inlining. - baseType := t.OrigSym().Def.(*ir.Name).Type() + baseType := t.OrigType() shapes := make([]*types.Type, len(t.RParams())) for i, t1 := range t.RParams() { shapes[i] = Shapify(t1, i, baseType.RParams()[i]) diff --git a/src/cmd/compile/internal/typecheck/dcl.go b/src/cmd/compile/internal/typecheck/dcl.go index d1eec6d322..45e7a695ab 100644 --- a/src/cmd/compile/internal/typecheck/dcl.go +++ b/src/cmd/compile/internal/typecheck/dcl.go @@ -70,8 +70,6 @@ func Declare(n *ir.Name, ctxt ir.Class) { n.SetFrameOffset(0) } - s.Block = types.Block - s.Lastlineno = base.Pos s.Def = n n.Class = ctxt if ctxt == ir.PFUNC { diff --git a/src/cmd/compile/internal/typecheck/expr.go b/src/cmd/compile/internal/typecheck/expr.go index 0fe8f91696..e6adc05a65 100644 --- a/src/cmd/compile/internal/typecheck/expr.go +++ b/src/cmd/compile/internal/typecheck/expr.go @@ -58,10 +58,6 @@ func tcShift(n, l, r ir.Node) (ir.Node, ir.Node, *types.Type) { base.Errorf("invalid operation: %v (shift count type %v, must be integer)", n, r.Type()) return l, r, nil } - if t.IsSigned() && !types.AllowsGoVersion(curpkg(), 1, 13) { - base.ErrorfVers("go1.13", "invalid operation: %v (signed shift count type %v)", n, r.Type()) - return l, r, nil - } t = l.Type() if t != nil && t.Kind() != types.TIDEAL && !t.IsInteger() { base.Errorf("invalid operation: %v (shift of type %v)", n, t) @@ -245,7 +241,6 @@ func tcCompLit(n *ir.CompLitExpr) (res ir.Node) { n.Len = length case types.TMAP: - var cs constSet for i3, l := range n.List { ir.SetPos(l) if l.Op() != ir.OKEY { @@ -259,7 +254,6 @@ func tcCompLit(n *ir.CompLitExpr) (res ir.Node) { r = pushtype(r, t.Key()) r = Expr(r) l.Key = AssignConv(r, t.Key(), "map key") - cs.add(base.Pos, l.Key, "key", "map literal") r = l.Value r = pushtype(r, t.Elem()) @@ -415,13 +409,7 @@ func tcConv(n *ir.ConvExpr) ir.Node { } op, why := Convertop(n.X.Op() == ir.OLITERAL, t, n.Type()) if op == ir.OXXX { - if !n.Diag() && !n.Type().Broke() && !n.X.Diag() { - base.Errorf("cannot convert %L to type %v%s", n.X, n.Type(), why) - n.SetDiag(true) - } - n.SetOp(ir.OCONV) - n.SetType(nil) - return n + base.Fatalf("cannot convert %L to type %v%s", n.X, n.Type(), why) } n.SetOp(op) diff --git a/src/cmd/compile/internal/typecheck/func.go b/src/cmd/compile/internal/typecheck/func.go index c6fd273bd1..6bfa7e6d83 100644 --- a/src/cmd/compile/internal/typecheck/func.go +++ b/src/cmd/compile/internal/typecheck/func.go @@ -241,12 +241,6 @@ func tcClosure(clo *ir.ClosureExpr, top int) ir.Node { base.FatalfAt(fn.Pos(), "underlying closure func already typechecked: %v", fn) } - // Set current associated iota value, so iota can be used inside - // function in ConstSpec, see issue #22344 - if x := getIotaValue(); x >= 0 { - fn.Iota = x - } - ir.NameClosure(clo, ir.CurFunc) Func(fn) @@ -301,16 +295,19 @@ func tcFunc(n *ir.Func) { defer tracePrint("tcFunc", n)(nil) } - n.Nname = AssignExpr(n.Nname).(*ir.Name) + if name := n.Nname; name.Typecheck() == 0 { + if name.Ntype != nil { + name.Ntype = typecheckNtype(name.Ntype) + name.SetType(name.Ntype.Type()) + } + name.SetTypecheck(1) + } } // tcCall typechecks an OCALL node. func tcCall(n *ir.CallExpr, top int) ir.Node { Stmts(n.Init()) // imported rewritten f(g()) calls (#30907) n.X = typecheck(n.X, ctxExpr|ctxType|ctxCallee) - if n.X.Diag() { - n.SetDiag(true) - } l := n.X @@ -360,10 +357,7 @@ func tcCall(n *ir.CallExpr, top int) ir.Node { l = n.X if l.Op() == ir.OTYPE { if n.IsDDD { - if !l.Type().Broke() { - base.Errorf("invalid use of ... in type conversion to %v", l.Type()) - } - n.SetDiag(true) + base.Fatalf("invalid use of ... in type conversion to %v", l.Type()) } // pick off before type-checking arguments @@ -909,12 +903,6 @@ func tcRecoverFP(n *ir.CallExpr) ir.Node { // tcUnsafeAdd typechecks an OUNSAFEADD node. func tcUnsafeAdd(n *ir.BinaryExpr) *ir.BinaryExpr { - if !types.AllowsGoVersion(curpkg(), 1, 17) { - base.ErrorfVers("go1.17", "unsafe.Add") - n.SetType(nil) - return n - } - n.X = AssignConv(Expr(n.X), types.Types[types.TUNSAFEPTR], "argument to unsafe.Add") n.Y = DefaultLit(Expr(n.Y), types.Types[types.TINT]) if n.X.Type() == nil || n.Y.Type() == nil { @@ -931,12 +919,6 @@ func tcUnsafeAdd(n *ir.BinaryExpr) *ir.BinaryExpr { // tcUnsafeSlice typechecks an OUNSAFESLICE node. func tcUnsafeSlice(n *ir.BinaryExpr) *ir.BinaryExpr { - if !types.AllowsGoVersion(curpkg(), 1, 17) { - base.ErrorfVers("go1.17", "unsafe.Slice") - n.SetType(nil) - return n - } - n.X = Expr(n.X) n.Y = Expr(n.Y) if n.X.Type() == nil || n.Y.Type() == nil { diff --git a/src/cmd/compile/internal/typecheck/iexport.go b/src/cmd/compile/internal/typecheck/iexport.go index fe0c80ac58..5d319eaca3 100644 --- a/src/cmd/compile/internal/typecheck/iexport.go +++ b/src/cmd/compile/internal/typecheck/iexport.go @@ -948,7 +948,7 @@ func (w *exportWriter) startType(k itag) { func (w *exportWriter) doTyp(t *types.Type) { s := t.Sym() - if s != nil && t.OrigSym() != nil { + if s != nil && t.OrigType() != nil { // This is an instantiated type - could be a re-instantiation like // Value[T2] or a full instantiation like Value[int]. if strings.Index(s.Name, "[") < 0 { @@ -964,7 +964,7 @@ func (w *exportWriter) doTyp(t *types.Type) { // types or existing typeparams from the function/method header. w.typeList(t.RParams()) // Export a reference to the base type. - baseType := t.OrigSym().Def.(*ir.Name).Type() + baseType := t.OrigType() w.typ(baseType) return } @@ -1835,7 +1835,10 @@ func (w *exportWriter) expr(n ir.Node) { n := n.(*ir.ClosureExpr) w.op(ir.OCLOSURE) w.pos(n.Pos()) + old := w.currPkg + w.setPkg(n.Type().Pkg(), true) w.signature(n.Type()) + w.setPkg(old, true) // Write out id for the Outer of each conditional variable. The // conditional variable itself for this closure will be re-created diff --git a/src/cmd/compile/internal/typecheck/iimport.go b/src/cmd/compile/internal/typecheck/iimport.go index ef91f550a5..654aff899d 100644 --- a/src/cmd/compile/internal/typecheck/iimport.go +++ b/src/cmd/compile/internal/typecheck/iimport.go @@ -761,7 +761,7 @@ func (p *iimporter) typAt(off uint64) *types.Type { // No need to calc sizes for re-instantiated generic types, and // they are not necessarily resolved until the top-level type is // defined (because of recursive types). - if t.OrigSym() == nil || !t.HasTParam() { + if t.OrigType() == nil || !t.HasTParam() { types.CheckSize(t) } p.typCache[off] = t @@ -1374,7 +1374,9 @@ func (r *importReader) node() ir.Node { case ir.OCLOSURE: //println("Importing CLOSURE") pos := r.pos() + r.setPkg() typ := r.signature(nil, nil) + r.setPkg() // All the remaining code below is similar to (*noder).funcLit(), but // with Dcls and ClosureVars lists already set up @@ -1480,7 +1482,7 @@ func (r *importReader) node() ir.Node { } else { genType := types.ReceiverBaseType(n1.X.Type()) if genType.IsInstantiatedGeneric() { - genType = genType.OrigSym().Def.Type() + genType = genType.OrigType() } m = Lookdot1(n1, sel, genType, genType.Methods(), 1) } @@ -1911,7 +1913,7 @@ func Instantiate(pos src.XPos, baseType *types.Type, targs []*types.Type) *types t := NewIncompleteNamedType(baseType.Pos(), instSym) t.SetRParams(targs) - t.SetOrigSym(baseSym) + t.SetOrigType(baseType) // baseType may still be TFORW or its methods may not be fully filled in // (since we are in the middle of importing it). So, delay call to @@ -1936,7 +1938,7 @@ func resumeDoInst() { for len(deferredInstStack) > 0 { t := deferredInstStack[0] deferredInstStack = deferredInstStack[1:] - substInstType(t, t.OrigSym().Def.(*ir.Name).Type(), t.RParams()) + substInstType(t, t.OrigType(), t.RParams()) } } deferInst-- @@ -1948,7 +1950,7 @@ func resumeDoInst() { // instantiations of mutually recursive types. func doInst(t *types.Type) *types.Type { assert(t.Kind() == types.TFORW) - return Instantiate(t.Pos(), t.OrigSym().Def.(*ir.Name).Type(), t.RParams()) + return Instantiate(t.Pos(), t.OrigType(), t.RParams()) } // substInstType completes the instantiation of a generic type by doing a diff --git a/src/cmd/compile/internal/typecheck/stmt.go b/src/cmd/compile/internal/typecheck/stmt.go index 9a02c1752c..16e24a0491 100644 --- a/src/cmd/compile/internal/typecheck/stmt.go +++ b/src/cmd/compile/internal/typecheck/stmt.go @@ -309,16 +309,13 @@ func tcGoDefer(n *ir.GoDeferStmt) { // type is broken or missing, most likely a method call on a broken type // we will warn about the broken type elsewhere. no need to emit a potentially confusing error - if n.Call.Type() == nil || n.Call.Type().Broke() { + if n.Call.Type() == nil { return } - if !n.Diag() { - // The syntax made sure it was a call, so this must be - // a conversion. - n.SetDiag(true) - base.ErrorfAt(n.Pos(), "%s requires function call, not conversion", what) - } + // The syntax made sure it was a call, so this must be + // a conversion. + base.FatalfAt(n.Pos(), "%s requires function call, not conversion", what) } // tcIf typechecks an OIF node. @@ -519,7 +516,6 @@ func tcSwitchExpr(n *ir.SwitchStmt) { } var defCase ir.Node - var cs constSet for _, ncase := range n.Cases { ls := ncase.List if len(ls) == 0 { // default: @@ -554,16 +550,6 @@ func tcSwitchExpr(n *ir.SwitchStmt) { } } } - - // Don't check for duplicate bools. Although the spec allows it, - // (1) the compiler hasn't checked it in the past, so compatibility mandates it, and - // (2) it would disallow useful things like - // case GOARCH == "arm" && GOARM == "5": - // case GOARCH == "arm": - // which would both evaluate to false for non-ARM compiles. - if !n1.Type().IsBoolean() { - cs.add(ncase.Pos(), n1, "case", "switch") - } } Stmts(ncase.Body) @@ -615,12 +601,15 @@ func tcSwitchType(n *ir.SwitchStmt) { } continue } + if n1.Op() == ir.ODYNAMICTYPE { + continue + } if n1.Op() != ir.OTYPE { base.ErrorfAt(ncase.Pos(), "%L is not a type", n1) continue } - if !n1.Type().IsInterface() && !implements(n1.Type(), t, &missing, &have, &ptr) && !missing.Broke() { - if have != nil && !have.Broke() { + if !n1.Type().IsInterface() && !implements(n1.Type(), t, &missing, &have, &ptr) { + if have != nil { base.ErrorfAt(ncase.Pos(), "impossible type switch case: %L cannot have dynamic type %v"+ " (wrong type for %v method)\n\thave %v%S\n\twant %v%S", guard.X, n1.Type(), missing.Sym, have.Sym, have.Type, missing.Sym, missing.Type) } else if ptr != 0 { @@ -640,7 +629,7 @@ func tcSwitchType(n *ir.SwitchStmt) { // Assign the clause variable's type. vt := t if len(ls) == 1 { - if ls[0].Op() == ir.OTYPE { + if ls[0].Op() == ir.OTYPE || ls[0].Op() == ir.ODYNAMICTYPE { vt = ls[0].Type() } else if !ir.IsNil(ls[0]) { // Invalid single-type case; @@ -656,7 +645,6 @@ func tcSwitchType(n *ir.SwitchStmt) { } else { // Clause variable is broken; prevent typechecking. nvar.SetTypecheck(1) - nvar.SetWalkdef(1) } ncase.Var = nvar } diff --git a/src/cmd/compile/internal/typecheck/subr.go b/src/cmd/compile/internal/typecheck/subr.go index bc39015846..e9690a5551 100644 --- a/src/cmd/compile/internal/typecheck/subr.go +++ b/src/cmd/compile/internal/typecheck/subr.go @@ -135,9 +135,6 @@ func NodNil() ir.Node { // modifies the tree with missing field names. func AddImplicitDots(n *ir.SelectorExpr) *ir.SelectorExpr { n.X = typecheck(n.X, ctxType|ctxExpr) - if n.X.Diag() { - n.SetDiag(true) - } t := n.X.Type() if t == nil { return n @@ -291,7 +288,7 @@ var dotlist = make([]dlist, 10) // Convert node n for assignment to type t. func assignconvfn(n ir.Node, t *types.Type, context func() string) ir.Node { - if n == nil || n.Type() == nil || n.Type().Broke() { + if n == nil || n.Type() == nil { return n } @@ -396,11 +393,6 @@ func Assignop1(src, dst *types.Type) (ir.Op, string) { return ir.OCONVIFACE, "" } - // we'll have complained about this method anyway, suppress spurious messages. - if have != nil && have.Sym == missing.Sym && (have.Type.Broke() || missing.Type.Broke()) { - return ir.OCONVIFACE, "" - } - var why string if isptrto(src, types.TINTER) { why = fmt.Sprintf(":\n\t%v is pointer to interface, not interface", src) @@ -593,9 +585,6 @@ func Convertop(srcConstant bool, src, dst *types.Type) (ir.Op, string) { // They must have same element type. if src.IsSlice() && dst.IsPtr() && dst.Elem().IsArray() && types.Identical(src.Elem(), dst.Elem().Elem()) { - if !types.AllowsGoVersion(curpkg(), 1, 17) { - return ir.OXXX, ":\n\tconversion of slices to array pointers only supported as of -lang=go1.17" - } return ir.OSLICE2ARRPTR, "" } @@ -785,9 +774,6 @@ func implements(t, iface *types.Type, m, samename **types.Field, ptr *int) bool } i := 0 for _, im := range iface.AllMethods().Slice() { - if im.Broke() { - continue - } for i < len(tms) && tms[i].Sym != im.Sym { i++ } @@ -1116,10 +1102,10 @@ func (ts *Tsubster) typ1(t *types.Type) *types.Type { forw = NewIncompleteNamedType(t.Pos(), newsym) //println("Creating new type by sub", newsym.Name, forw.HasTParam()) forw.SetRParams(neededTargs) - // Copy the OrigSym from the re-instantiated type (which is the sym of + // Copy the OrigType from the re-instantiated type (which is the sym of // the base generic type). - assert(t.OrigSym() != nil) - forw.SetOrigSym(t.OrigSym()) + assert(t.OrigType() != nil) + forw.SetOrigType(t.OrigType()) } var newt *types.Type @@ -1532,13 +1518,10 @@ func Shapify(t *types.Type, index int, tparam *types.Type) *types.Type { // Note: pointers to arrays are special because of slice-to-array-pointer // conversions. See issue 49295. if u.Kind() == types.TPTR && u.Elem().Kind() != types.TARRAY && - tparam.Bound().StructuralType() == nil { + tparam.Bound().StructuralType() == nil && !u.Elem().NotInHeap() { u = types.Types[types.TUINT8].PtrTo() } - if shapeMap == nil { - shapeMap = map[int]map[*types.Type]*types.Type{} - } submap := shapeMap[index] if submap == nil { submap = map[*types.Type]*types.Type{} @@ -1569,4 +1552,4 @@ func Shapify(t *types.Type, index int, tparam *types.Type) *types.Type { return s } -var shapeMap map[int]map[*types.Type]*types.Type +var shapeMap = map[int]map[*types.Type]*types.Type{} diff --git a/src/cmd/compile/internal/typecheck/syms.go b/src/cmd/compile/internal/typecheck/syms.go index ed3aaecc5a..6c2e84680b 100644 --- a/src/cmd/compile/internal/typecheck/syms.go +++ b/src/cmd/compile/internal/typecheck/syms.go @@ -67,7 +67,6 @@ func Lookup(name string) *types.Sym { // but does not make them visible to user code. func InitRuntime() { base.Timer.Start("fe", "loadsys") - types.Block = 1 typs := runtimeTypes() for _, d := range &runtimeDecls { diff --git a/src/cmd/compile/internal/typecheck/typecheck.go b/src/cmd/compile/internal/typecheck/typecheck.go index 71a7841684..b5108eab84 100644 --- a/src/cmd/compile/internal/typecheck/typecheck.go +++ b/src/cmd/compile/internal/typecheck/typecheck.go @@ -45,17 +45,6 @@ func Callee(n ir.Node) ir.Node { return typecheck(n, ctxExpr|ctxCallee) } -func FuncBody(n *ir.Func) { - ir.CurFunc = n - errorsBefore := base.Errors() - Stmts(n.Body) - CheckUnused(n) - CheckReturn(n) - if ir.IsBlank(n.Nname) || base.Errors() > errorsBefore { - n.Body = nil // blank function or type errors; do not compile - } -} - var importlist []*ir.Func // AllImportedBodies reads in the bodies of all imported functions and typechecks @@ -127,8 +116,6 @@ const ( // marks variables that escape the local frame. // rewrites n.Op to be more specific in some cases. -var typecheckdefstack []*ir.Name - // Resolve resolves an ONONAME node to a definition, if any. If n is not an ONONAME node, // Resolve returns n unchanged. If n is an ONONAME node and not in the same package, // then n.Sym() is resolved using import data. Otherwise, Resolve returns @@ -153,13 +140,6 @@ func Resolve(n ir.Node) (res ir.Node) { return n } - if r.Op() == ir.OIOTA { - if x := getIotaValue(); x >= 0 { - return ir.NewInt(x) - } - return n - } - return r } @@ -413,37 +393,16 @@ func typecheck(n ir.Node, top int) (res ir.Node) { // this code a bit, especially the final case. switch { case top&(ctxStmt|ctxExpr) == ctxExpr && !isExpr && n.Op() != ir.OTYPE && !isMulti: - if !n.Diag() { - base.Errorf("%v used as value", n) - n.SetDiag(true) - } - if t != nil { - n.SetType(nil) - } + base.Fatalf("%v used as value", n) case top&ctxType == 0 && n.Op() == ir.OTYPE && t != nil: - if !n.Type().Broke() { - base.Errorf("type %v is not an expression", n.Type()) - n.SetDiag(true) - } + base.Fatalf("type %v is not an expression", n.Type()) case top&(ctxStmt|ctxExpr) == ctxStmt && !isStmt && t != nil: - if !n.Diag() { - base.Errorf("%v evaluated but not used", n) - n.SetDiag(true) - } - n.SetType(nil) + base.Fatalf("%v evaluated but not used", n) case top&(ctxType|ctxExpr) == ctxType && n.Op() != ir.OTYPE && n.Op() != ir.ONONAME && (t != nil || n.Op() == ir.ONAME): - base.Errorf("%v is not a type", n) - if t != nil { - if n.Op() == ir.ONAME { - t.SetBroke(true) - } else { - n.SetType(nil) - } - } - + base.Fatalf("%v is not a type", n) } base.Pos = lno @@ -465,10 +424,6 @@ func indexlit(n ir.Node) ir.Node { // typecheck1 should ONLY be called from typecheck. func typecheck1(n ir.Node, top int) ir.Node { - if n, ok := n.(*ir.Name); ok { - typecheckdef(n) - } - switch n.Op() { default: ir.Dump("typecheck", n) @@ -477,9 +432,7 @@ func typecheck1(n ir.Node, top int) ir.Node { case ir.OLITERAL: if n.Sym() == nil && n.Type() == nil { - if !n.Diag() { - base.Fatalf("literal missing type: %v", n) - } + base.Fatalf("literal missing type: %v", n) } return n @@ -488,14 +441,10 @@ func typecheck1(n ir.Node, top int) ir.Node { // names case ir.ONONAME: - if !n.Diag() { - // Note: adderrorname looks for this string and - // adds context about the outer expression - base.ErrorfAt(n.Pos(), "undefined: %v", n.Sym()) - n.SetDiag(true) - } - n.SetType(nil) - return n + // Note: adderrorname looks for this string and + // adds context about the outer expression + base.FatalfAt(n.Pos(), "undefined: %v", n.Sym()) + panic("unreachable") case ir.ONAME: n := n.(*ir.Name) @@ -828,9 +777,7 @@ func typecheck1(n ir.Node, top int) ir.Node { case ir.ODEFER, ir.OGO: n := n.(*ir.GoDeferStmt) n.Call = typecheck(n.Call, ctxStmt|ctxExpr) - if !n.Call.Diag() { - tcGoDefer(n) - } + tcGoDefer(n) return n case ir.OFOR, ir.OFORUNTIL: @@ -868,8 +815,7 @@ func typecheck1(n ir.Node, top int) ir.Node { case ir.OTYPESW: n := n.(*ir.TypeSwitchGuard) - base.Errorf("use of .(type) outside type switch") - n.SetDiag(true) + base.Fatalf("use of .(type) outside type switch") return n case ir.ODCLFUNC: @@ -1189,7 +1135,7 @@ func Lookdot(n *ir.SelectorExpr, t *types.Type, dostrcmp int) *types.Field { } if f1 != nil { - if dostrcmp > 1 || f1.Broke() { + if dostrcmp > 1 { // Already in the process of diagnosing an error. return f1 } @@ -1310,10 +1256,6 @@ func typecheckaste(op ir.Op, call ir.Node, isddd bool, tstruct *types.Type, nl i lno := base.Pos defer func() { base.Pos = lno }() - if tstruct.Broke() { - return - } - var n ir.Node if len(nl) == 1 { n = nl[0] @@ -1402,7 +1344,7 @@ invalidddd: return notenough: - if n == nil || (!n.Diag() && n.Type() != nil) { + if n == nil || n.Type() != nil { details := errorDetails(nl, tstruct, isddd) if call != nil { // call is the expression being called, not the overall call. @@ -1418,7 +1360,7 @@ notenough: base.Errorf("not enough arguments to %v%s", op, details) } if n != nil { - n.SetDiag(true) + base.Fatalf("invalid call") } } return @@ -1565,15 +1507,7 @@ func typecheckarraylit(elemType *types.Type, bound int64, elts []ir.Node, ctx st elt.Key = Expr(elt.Key) key = IndexConst(elt.Key) if key < 0 { - if !elt.Key.Diag() { - if key == -2 { - base.Errorf("index too large") - } else { - base.Errorf("index must be non-negative integer constant") - } - elt.Key.SetDiag(true) - } - key = -(1 << 30) // stay negative for a while + base.Fatalf("invalid index: %v", elt.Key) } kv = elt r = elt.Value @@ -1647,9 +1581,7 @@ func checkassign(stmt ir.Node, n ir.Node) { } defer n.SetType(nil) - if n.Diag() { - return - } + switch { case n.Op() == ir.ODOT && n.(*ir.SelectorExpr).X.Op() == ir.OINDEXMAP: base.Errorf("cannot assign to struct field %v in map", n) @@ -1693,204 +1625,6 @@ func stringtoruneslit(n *ir.ConvExpr) ir.Node { return Expr(nn) } -func typecheckdeftype(n *ir.Name) { - if base.EnableTrace && base.Flag.LowerT { - defer tracePrint("typecheckdeftype", n)(nil) - } - - t := types.NewNamed(n) - if n.Curfn != nil { - t.SetVargen() - } - - if n.Pragma()&ir.NotInHeap != 0 { - t.SetNotInHeap(true) - } - - n.SetType(t) - n.SetTypecheck(1) - n.SetWalkdef(1) - - types.DeferCheckSize() - errorsBefore := base.Errors() - n.Ntype = typecheckNtype(n.Ntype) - if underlying := n.Ntype.Type(); underlying != nil { - t.SetUnderlying(underlying) - } else { - n.SetDiag(true) - n.SetType(nil) - } - if t.Kind() == types.TFORW && base.Errors() > errorsBefore { - // Something went wrong during type-checking, - // but it was reported. Silence future errors. - t.SetBroke(true) - } - types.ResumeCheckSize() -} - -func typecheckdef(n *ir.Name) { - if base.EnableTrace && base.Flag.LowerT { - defer tracePrint("typecheckdef", n)(nil) - } - - if n.Walkdef() == 1 { - return - } - - if n.Type() != nil { // builtin - // Mark as Walkdef so that if n.SetType(nil) is called later, we - // won't try walking again. - if got := n.Walkdef(); got != 0 { - base.Fatalf("unexpected walkdef: %v", got) - } - n.SetWalkdef(1) - return - } - - lno := ir.SetPos(n) - typecheckdefstack = append(typecheckdefstack, n) - if n.Walkdef() == 2 { - base.FlushErrors() - fmt.Printf("typecheckdef loop:") - for i := len(typecheckdefstack) - 1; i >= 0; i-- { - n := typecheckdefstack[i] - fmt.Printf(" %v", n.Sym()) - } - fmt.Printf("\n") - base.Fatalf("typecheckdef loop") - } - - n.SetWalkdef(2) - - switch n.Op() { - default: - base.Fatalf("typecheckdef %v", n.Op()) - - case ir.OLITERAL: - if n.Ntype != nil { - n.Ntype = typecheckNtype(n.Ntype) - n.SetType(n.Ntype.Type()) - n.Ntype = nil - if n.Type() == nil { - n.SetDiag(true) - goto ret - } - } - - e := n.Defn - n.Defn = nil - if e == nil { - ir.Dump("typecheckdef nil defn", n) - base.ErrorfAt(n.Pos(), "xxx") - } - - e = Expr(e) - if e.Type() == nil { - goto ret - } - if !ir.IsConstNode(e) { - if !e.Diag() { - if e.Op() == ir.ONIL { - base.ErrorfAt(n.Pos(), "const initializer cannot be nil") - } else { - base.ErrorfAt(n.Pos(), "const initializer %v is not a constant", e) - } - e.SetDiag(true) - } - goto ret - } - - t := n.Type() - if t != nil { - if !ir.OKForConst[t.Kind()] { - base.ErrorfAt(n.Pos(), "invalid constant type %v", t) - goto ret - } - - if !e.Type().IsUntyped() && !types.Identical(t, e.Type()) { - base.ErrorfAt(n.Pos(), "cannot use %L as type %v in const initializer", e, t) - goto ret - } - - e = convlit(e, t) - } - - n.SetType(e.Type()) - if n.Type() != nil { - n.SetVal(e.Val()) - } - - case ir.ONAME: - if n.Ntype != nil { - n.Ntype = typecheckNtype(n.Ntype) - n.SetType(n.Ntype.Type()) - if n.Type() == nil { - n.SetDiag(true) - goto ret - } - } - - if n.Type() != nil { - break - } - if n.Defn == nil { - if n.BuiltinOp != 0 { // like OPRINTN - break - } - if base.Errors() > 0 { - // Can have undefined variables in x := foo - // that make x have an n.name.Defn == nil. - // If there are other errors anyway, don't - // bother adding to the noise. - break - } - - base.Fatalf("var without type, init: %v", n.Sym()) - } - - if n.Defn.Op() == ir.ONAME { - n.Defn = Expr(n.Defn) - n.SetType(n.Defn.Type()) - break - } - - n.Defn = Stmt(n.Defn) // fills in n.Type - - case ir.OTYPE: - if n.Alias() { - // Type alias declaration: Simply use the rhs type - no need - // to create a new type. - // If we have a syntax error, name.Ntype may be nil. - if n.Ntype != nil { - n.Ntype = typecheckNtype(n.Ntype) - n.SetType(n.Ntype.Type()) - if n.Type() == nil { - n.SetDiag(true) - goto ret - } - } - break - } - - // regular type declaration - typecheckdeftype(n) - } - -ret: - if n.Op() != ir.OLITERAL && n.Type() != nil && n.Type().IsUntyped() { - base.Fatalf("got %v for %v", n.Type(), n) - } - last := len(typecheckdefstack) - 1 - if typecheckdefstack[last] != n { - base.Fatalf("typecheckdefstack mismatch") - } - typecheckdefstack[last] = nil - typecheckdefstack = typecheckdefstack[:last] - - base.Pos = lno - n.SetWalkdef(1) -} - func checkmake(t *types.Type, arg string, np *ir.Node) bool { n := *np if !n.Type().IsInteger() && n.Type().Kind() != types.TIDEAL { @@ -2152,22 +1886,6 @@ func CheckReturn(fn *ir.Func) { } } -// getIotaValue returns the current value for "iota", -// or -1 if not within a ConstSpec. -func getIotaValue() int64 { - if i := len(typecheckdefstack); i > 0 { - if x := typecheckdefstack[i-1]; x.Op() == ir.OLITERAL { - return x.Iota() - } - } - - if ir.CurFunc != nil && ir.CurFunc.Iota >= 0 { - return ir.CurFunc.Iota - } - - return -1 -} - // curpkg returns the current package, based on Curfn. func curpkg() *types.Pkg { fn := ir.CurFunc diff --git a/src/cmd/compile/internal/typecheck/universe.go b/src/cmd/compile/internal/typecheck/universe.go index 0254d96e68..a49bf5793e 100644 --- a/src/cmd/compile/internal/typecheck/universe.go +++ b/src/cmd/compile/internal/typecheck/universe.go @@ -7,7 +7,6 @@ package typecheck import ( "go/constant" - "cmd/compile/internal/base" "cmd/compile/internal/ir" "cmd/compile/internal/types" "cmd/internal/src" @@ -92,14 +91,12 @@ func InitUniverse() { s = Lookup("_") types.BlankSym = s - s.Block = -100 s.Def = NewName(s) ir.AsNode(s.Def).SetType(types.Types[types.TBLANK]) ir.BlankNode = ir.AsNode(s.Def) ir.BlankNode.SetTypecheck(1) s = types.BuiltinPkg.Lookup("_") - s.Block = -100 s.Def = NewName(s) ir.AsNode(s.Def).SetType(types.Types[types.TBLANK]) @@ -108,9 +105,6 @@ func InitUniverse() { nnil.(*ir.NilExpr).SetSym(s) s.Def = nnil - s = types.BuiltinPkg.Lookup("iota") - s.Def = ir.NewIota(base.Pos, s) - // initialize okfor for et := types.Kind(0); et < types.NTYPE; et++ { if types.IsInt[et] || et == types.TIDEAL { @@ -226,6 +220,5 @@ func DeclareUniverse() { } s1.Def = s.Def - s1.Block = s.Block } } diff --git a/src/cmd/compile/internal/types/alg.go b/src/cmd/compile/internal/types/alg.go index f5675c66b4..c1f93fc1c3 100644 --- a/src/cmd/compile/internal/types/alg.go +++ b/src/cmd/compile/internal/types/alg.go @@ -40,9 +40,6 @@ const ( // If it returns ANOEQ, it also returns the component type of t that // makes it incomparable. func AlgType(t *Type) (AlgKind, *Type) { - if t.Broke() { - return AMEM, nil - } if t.Noalg() { return ANOEQ, t } diff --git a/src/cmd/compile/internal/types/goversion.go b/src/cmd/compile/internal/types/goversion.go index 1a324aa42f..ceb2ed366e 100644 --- a/src/cmd/compile/internal/types/goversion.go +++ b/src/cmd/compile/internal/types/goversion.go @@ -24,19 +24,9 @@ type lang struct { // any language version is supported. var langWant lang -// AllowsGoVersion reports whether a particular package -// is allowed to use Go version major.minor. -// We assume the imported packages have all been checked, -// so we only have to check the local package against the -lang flag. -func AllowsGoVersion(pkg *Pkg, major, minor int) 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 - } +// AllowsGoVersion reports whether local package is allowed +// to use Go version major.minor. +func AllowsGoVersion(major, minor int) bool { if langWant.major == 0 && langWant.minor == 0 { return true } diff --git a/src/cmd/compile/internal/types/identity.go b/src/cmd/compile/internal/types/identity.go index 60a0f2e7c5..17555d099b 100644 --- a/src/cmd/compile/internal/types/identity.go +++ b/src/cmd/compile/internal/types/identity.go @@ -39,7 +39,7 @@ func identical(t1, t2 *Type, flags int, assumedEqual map[typePair]struct{}) bool if t1 == t2 { return true } - if t1 == nil || t2 == nil || t1.kind != t2.kind || t1.Broke() || t2.Broke() { + if t1 == nil || t2 == nil || t1.kind != t2.kind { return false } if t1.sym != nil || t2.sym != nil { diff --git a/src/cmd/compile/internal/types/scope.go b/src/cmd/compile/internal/types/scope.go index d7c454f379..e577b7aa53 100644 --- a/src/cmd/compile/internal/types/scope.go +++ b/src/cmd/compile/internal/types/scope.go @@ -6,21 +6,15 @@ package types import ( "cmd/compile/internal/base" - "cmd/internal/src" ) // Declaration stack & operations -var blockgen int32 = 1 // max block number -var Block int32 = 1 // current block number - // A dsym stores a symbol's shadowed declaration so that it can be // restored once the block scope ends. type dsym struct { - sym *Sym // sym == nil indicates stack mark - def Object - block int32 - lastlineno src.XPos // last declaration for diagnostic + sym *Sym // sym == nil indicates stack mark + def Object } // dclstack maintains a stack of shadowed symbol declarations so that @@ -31,10 +25,8 @@ var dclstack []dsym // it can be shadowed by a new declaration within a nested block scope. func Pushdcl(s *Sym) { dclstack = append(dclstack, dsym{ - sym: s, - def: s.Def, - block: s.Block, - lastlineno: s.Lastlineno, + sym: s, + def: s.Def, }) } @@ -46,14 +38,11 @@ func Popdcl() { s := d.sym if s == nil { // pop stack mark - Block = d.block dclstack = dclstack[:i-1] return } s.Def = d.def - s.Block = d.block - s.Lastlineno = d.lastlineno // Clear dead pointer fields. d.sym = nil @@ -65,11 +54,8 @@ func Popdcl() { // Markdcl records the start of a new block scope for declarations. func Markdcl() { dclstack = append(dclstack, dsym{ - sym: nil, // stack mark - block: Block, + sym: nil, // stack mark }) - blockgen++ - Block = blockgen } func isDclstackValid() bool { diff --git a/src/cmd/compile/internal/types/size.go b/src/cmd/compile/internal/types/size.go index fb6accdc64..fc9907b85f 100644 --- a/src/cmd/compile/internal/types/size.go +++ b/src/cmd/compile/internal/types/size.go @@ -5,8 +5,6 @@ package types import ( - "bytes" - "fmt" "sort" "cmd/compile/internal/base" @@ -82,7 +80,7 @@ func expandiface(t *Type) { switch prev := seen[m.Sym]; { case prev == nil: seen[m.Sym] = m - case AllowsGoVersion(t.Pkg(), 1, 14) && !explicit && Identical(m.Type, prev.Type): + case !explicit && Identical(m.Type, prev.Type): return default: base.ErrorfAt(m.Pos, "duplicate method %s", m.Sym.Name) @@ -129,25 +127,14 @@ func expandiface(t *Type) { } // In 1.18, embedded types can be anything. In Go 1.17, we disallow - // embedding anything other than interfaces. + // embedding anything other than interfaces. This requirement was caught + // by types2 already, so allow non-interface here. if !m.Type.IsInterface() { - if AllowsGoVersion(t.Pkg(), 1, 18) { - continue - } - base.ErrorfAt(m.Pos, "interface contains embedded non-interface, non-union %v", m.Type) - m.SetBroke(true) - t.SetBroke(true) - // Add to fields so that error messages - // include the broken embedded type when - // printing t. - // TODO(mdempsky): Revisit this. - methods = append(methods, m) continue } // Embedded interface: duplicate all methods - // (including broken ones, if any) and add to t's - // method set. + // and add to t's method set. for _, t1 := range m.Type.AllMethods().Slice() { f := NewField(m.Pos, t1.Sym, t1.Type) addMethod(f, false) @@ -239,98 +226,6 @@ func calcStructOffset(errtype *Type, t *Type, o int64, flag int) int64 { return o } -// findTypeLoop searches for an invalid type declaration loop involving -// type t and reports whether one is found. If so, path contains the -// loop. -// -// path points to a slice used for tracking the sequence of types -// visited. Using a pointer to a slice allows the slice capacity to -// grow and limit reallocations. -func findTypeLoop(t *Type, path *[]*Type) bool { - // We implement a simple DFS loop-finding algorithm. This - // could be faster, but type cycles are rare. - - if t.Sym() != nil { - // Declared type. Check for loops and otherwise - // recurse on the type expression used in the type - // declaration. - - // Type imported from package, so it can't be part of - // a type loop (otherwise that package should have - // failed to compile). - if t.Sym().Pkg != LocalPkg { - return false - } - - for i, x := range *path { - if x == t { - *path = (*path)[i:] - return true - } - } - - *path = append(*path, t) - if findTypeLoop(t.Obj().(TypeObject).TypeDefn(), path) { - return true - } - *path = (*path)[:len(*path)-1] - } else { - // Anonymous type. Recurse on contained types. - - switch t.Kind() { - case TARRAY: - if findTypeLoop(t.Elem(), path) { - return true - } - case TSTRUCT: - for _, f := range t.Fields().Slice() { - if findTypeLoop(f.Type, path) { - return true - } - } - case TINTER: - for _, m := range t.Methods().Slice() { - if m.Type.IsInterface() { // embedded interface - if findTypeLoop(m.Type, path) { - return true - } - } - } - } - } - - return false -} - -func reportTypeLoop(t *Type) { - if t.Broke() { - return - } - - var l []*Type - if !findTypeLoop(t, &l) { - base.Fatalf("failed to find type loop for: %v", t) - } - - // Rotate loop so that the earliest type declaration is first. - i := 0 - for j, t := range l[1:] { - if typePos(t).Before(typePos(l[i])) { - i = j + 1 - } - } - l = append(l[i:], l[:i]...) - - var msg bytes.Buffer - fmt.Fprintf(&msg, "invalid recursive type %v\n", l[0]) - for _, t := range l { - fmt.Fprintf(&msg, "\t%v: %v refers to\n", base.FmtPos(typePos(t)), t) - t.SetBroke(true) - } - fmt.Fprintf(&msg, "\t%v: %v", base.FmtPos(typePos(l[0])), l[0]) - base.ErrorfAt(typePos(l[0]), msg.String()) -} - // CalcSize calculates and stores the size and alignment for t. // If CalcSizeDisabled is set, and the size/alignment // have not already been calculated, it calls Fatal. @@ -351,9 +246,9 @@ func CalcSize(t *Type) { } if t.width == -2 { - reportTypeLoop(t) t.width = 0 t.align = 1 + base.Fatalf("invalid recursive type %v", t) return } @@ -362,20 +257,9 @@ func CalcSize(t *Type) { } if CalcSizeDisabled { - if t.Broke() { - // break infinite recursion from Fatal call below - return - } - t.SetBroke(true) base.Fatalf("width not calculated: %v", t) } - // break infinite recursion if the broken recursive type - // is referenced again - if t.Broke() && t.width == 0 { - return - } - // defer CheckSize calls until after we're done DeferCheckSize() @@ -474,7 +358,7 @@ func CalcSize(t *Type) { CheckSize(t.Key()) case TFORW: // should have been filled in - reportTypeLoop(t) + base.Fatalf("invalid recursive type %v", t) w = 1 // anything will do case TANY: diff --git a/src/cmd/compile/internal/types/sizeof_test.go b/src/cmd/compile/internal/types/sizeof_test.go index d37c173058..0c46077dfa 100644 --- a/src/cmd/compile/internal/types/sizeof_test.go +++ b/src/cmd/compile/internal/types/sizeof_test.go @@ -20,7 +20,7 @@ func TestSizeof(t *testing.T) { _32bit uintptr // size on 32bit platforms _64bit uintptr // size on 64bit platforms }{ - {Sym{}, 44, 72}, + {Sym{}, 32, 64}, {Type{}, 64, 112}, {Map{}, 20, 40}, {Forward{}, 20, 32}, diff --git a/src/cmd/compile/internal/types/sym.go b/src/cmd/compile/internal/types/sym.go index fb642f52f8..927ebc453a 100644 --- a/src/cmd/compile/internal/types/sym.go +++ b/src/cmd/compile/internal/types/sym.go @@ -7,7 +7,6 @@ package types import ( "cmd/compile/internal/base" "cmd/internal/obj" - "cmd/internal/src" "unicode" "unicode/utf8" ) @@ -32,14 +31,15 @@ type Sym struct { Pkg *Pkg Name string // object name - // Def, Block, and Lastlineno are saved and restored by Pushdcl/Popdcl. - // The unique ONAME, OTYPE, OPACK, or OLITERAL node that this symbol is // bound to within the current scope. (Most parts of the compiler should // prefer passing the Node directly, rather than relying on this field.) - Def Object - Block int32 // blocknumber to catch redeclaration - Lastlineno src.XPos // last declaration for diagnostic + // + // Def is saved and restored by Pushdcl/Popdcl. + // + // Deprecated: New code should avoid depending on Sym.Def. Add + // mdempsky@ as a reviewer for any CLs involving Sym.Def. + Def Object flags bitset8 } diff --git a/src/cmd/compile/internal/types/type.go b/src/cmd/compile/internal/types/type.go index fe352e0b6e..c8d11b5bb9 100644 --- a/src/cmd/compile/internal/types/type.go +++ b/src/cmd/compile/internal/types/type.go @@ -202,17 +202,16 @@ type Type struct { // TODO(danscales): choose a better name. rparams *[]*Type - // For an instantiated generic type, the symbol for the base generic type. + // For an instantiated generic type, the base generic type. // This backpointer is useful, because the base type is the type that has // the method bodies. - origSym *Sym + origType *Type } func (*Type) CanBeAnSSAAux() {} const ( typeNotInHeap = 1 << iota // type cannot be heap allocated - typeBroke // broken type definition typeNoalg // suppress hash and eq algorithm generation typeDeferwidth // width computation has been deferred and type is on deferredTypeStack typeRecur @@ -222,7 +221,6 @@ const ( ) func (t *Type) NotInHeap() bool { return t.flags&typeNotInHeap != 0 } -func (t *Type) Broke() bool { return t.flags&typeBroke != 0 } func (t *Type) Noalg() bool { return t.flags&typeNoalg != 0 } func (t *Type) Deferwidth() bool { return t.flags&typeDeferwidth != 0 } func (t *Type) Recur() bool { return t.flags&typeRecur != 0 } @@ -231,7 +229,6 @@ func (t *Type) IsShape() bool { return t.flags&typeIsShape != 0 } func (t *Type) HasShape() bool { return t.flags&typeHasShape != 0 } func (t *Type) SetNotInHeap(b bool) { t.flags.set(typeNotInHeap, b) } -func (t *Type) SetBroke(b bool) { t.flags.set(typeBroke, b) } func (t *Type) SetNoalg(b bool) { t.flags.set(typeNoalg, b) } func (t *Type) SetDeferwidth(b bool) { t.flags.set(typeDeferwidth, b) } func (t *Type) SetRecur(b bool) { t.flags.set(typeRecur, b) } @@ -250,10 +247,10 @@ func (t *Type) Kind() Kind { return t.kind } func (t *Type) Sym() *Sym { return t.sym } func (t *Type) SetSym(sym *Sym) { t.sym = sym } -// OrigSym returns the name of the original generic type that t is an +// OrigType returns the original generic type that t is an // instantiation of, if any. -func (t *Type) OrigSym() *Sym { return t.origSym } -func (t *Type) SetOrigSym(sym *Sym) { t.origSym = sym } +func (t *Type) OrigType() *Type { return t.origType } +func (t *Type) SetOrigType(orig *Type) { t.origType = orig } // Underlying returns the underlying type of type t. func (t *Type) Underlying() *Type { return t.underlying } @@ -524,16 +521,13 @@ type Field struct { const ( fieldIsDDD = 1 << iota // field is ... argument - fieldBroke // broken field definition fieldNointerface ) func (f *Field) IsDDD() bool { return f.flags&fieldIsDDD != 0 } -func (f *Field) Broke() bool { return f.flags&fieldBroke != 0 } func (f *Field) Nointerface() bool { return f.flags&fieldNointerface != 0 } func (f *Field) SetIsDDD(b bool) { f.flags.set(fieldIsDDD, b) } -func (f *Field) SetBroke(b bool) { f.flags.set(fieldBroke, b) } func (f *Field) SetNointerface(b bool) { f.flags.set(fieldNointerface, b) } // End returns the offset of the first byte immediately after this field. @@ -798,7 +792,7 @@ func NewField(pos src.XPos, sym *Sym, typ *Type) *Field { Offset: BADWIDTH, } if typ == nil { - f.SetBroke(true) + base.Fatalf("typ is nil") } return f } @@ -1634,6 +1628,7 @@ func (t *Type) NumComponents(countBlank componentsIncludeBlankFields) int64 { // SoleComponent returns the only primitive component in t, // if there is exactly one. Otherwise, it returns nil. // Components are counted as in NumComponents, including blank fields. +// Keep in sync with cmd/compile/internal/walk/convert.go:soleComponent. func (t *Type) SoleComponent() *Type { switch t.kind { case TSTRUCT: @@ -1786,9 +1781,6 @@ func (t *Type) SetUnderlying(underlying *Type) { if underlying.NotInHeap() { t.SetNotInHeap(true) } - if underlying.Broke() { - t.SetBroke(true) - } if underlying.HasTParam() { t.SetHasTParam(true) } @@ -1859,9 +1851,6 @@ func NewInterface(pkg *Pkg, methods []*Field, implicit bool) *Type { break } } - if anyBroke(methods) { - t.SetBroke(true) - } t.extra.(*Interface).pkg = pkg t.extra.(*Interface).implicit = implicit return t @@ -1971,9 +1960,6 @@ func NewSignature(pkg *Pkg, recv *Field, tparams, params, results []*Field) *Typ funargs := func(fields []*Field, funarg Funarg) *Type { s := NewStruct(NoPkg, fields) s.StructType().Funarg = funarg - if s.Broke() { - t.SetBroke(true) - } return s } @@ -2003,9 +1989,6 @@ func NewSignature(pkg *Pkg, recv *Field, tparams, params, results []*Field) *Typ func NewStruct(pkg *Pkg, fields []*Field) *Type { t := newType(TSTRUCT) t.SetFields(fields) - if anyBroke(fields) { - t.SetBroke(true) - } t.extra.(*Struct).pkg = pkg if fieldsHasTParam(fields) { t.SetHasTParam(true) @@ -2016,15 +1999,6 @@ func NewStruct(pkg *Pkg, fields []*Field) *Type { return t } -func anyBroke(fields []*Field) bool { - for _, f := range fields { - if f.Broke() { - return true - } - } - return false -} - var ( IsInt [NTYPE]bool IsFloat [NTYPE]bool @@ -2083,10 +2057,6 @@ func IsReflexive(t *Type) bool { // Can this type be stored directly in an interface word? // Yes, if the representation is a single pointer. func IsDirectIface(t *Type) bool { - if t.Broke() { - return false - } - switch t.Kind() { case TPTR: // Pointers to notinheap types must be stored indirectly. See issue 42076. diff --git a/src/cmd/compile/internal/types2/api.go b/src/cmd/compile/internal/types2/api.go index 6230c58401..d864c96fb6 100644 --- a/src/cmd/compile/internal/types2/api.go +++ b/src/cmd/compile/internal/types2/api.go @@ -204,12 +204,12 @@ type Info struct { // qualified identifiers are collected in the Uses map. Types map[syntax.Expr]TypeAndValue - // Instances maps identifiers denoting parameterized types or functions to - // their type arguments and instantiated type. + // Instances maps identifiers denoting generic types or functions to their + // type arguments and instantiated type. // // For example, Instances will map the identifier for 'T' in the type // instantiation T[int, string] to the type arguments [int, string] and - // resulting instantiated *Named type. Given a parameterized function + // resulting instantiated *Named type. Given a generic function // func F[A any](A), Instances will map the identifier for 'F' in the call // expression F(int(1)) to the inferred type arguments [int], and resulting // instantiated *Signature. @@ -421,8 +421,11 @@ func (conf *Config) Check(path string, files []*syntax.File, info *Info) (*Packa } // AssertableTo reports whether a value of type V can be asserted to have type T. -// The behavior of AssertableTo is undefined if V is a generalized interface; i.e., -// an interface that may only be used as a type constraint in Go code. +// +// The behavior of AssertableTo is undefined in two cases: +// - if V is a generalized interface; i.e., an interface that may only be used +// as a type constraint in Go code +// - if T is an uninstantiated generic type func AssertableTo(V *Interface, T Type) bool { // Checker.newAssertableTo suppresses errors for invalid types, so we need special // handling here. @@ -432,20 +435,31 @@ func AssertableTo(V *Interface, T Type) bool { return (*Checker)(nil).newAssertableTo(V, T) == nil } -// AssignableTo reports whether a value of type V is assignable to a variable of type T. +// AssignableTo reports whether a value of type V is assignable to a variable +// of type T. +// +// The behavior of AssignableTo is undefined if V or T is an uninstantiated +// generic type. func AssignableTo(V, T Type) bool { x := operand{mode: value, typ: V} ok, _ := x.assignableTo(nil, T, nil) // check not needed for non-constant x return ok } -// ConvertibleTo reports whether a value of type V is convertible to a value of type T. +// ConvertibleTo reports whether a value of type V is convertible to a value of +// type T. +// +// The behavior of ConvertibleTo is undefined if V or T is an uninstantiated +// generic type. func ConvertibleTo(V, T Type) bool { x := operand{mode: value, typ: V} return x.convertibleTo(nil, T, nil) // check not needed for non-constant x } // Implements reports whether type V implements interface T. +// +// The behavior of Implements is undefined if V is an uninstantiated generic +// type. func Implements(V Type, T *Interface) bool { if T.Empty() { // All types (even Typ[Invalid]) implement the empty interface. diff --git a/src/cmd/compile/internal/types2/api_test.go b/src/cmd/compile/internal/types2/api_test.go index 5c38c59c80..d433ed1bdf 100644 --- a/src/cmd/compile/internal/types2/api_test.go +++ b/src/cmd/compile/internal/types2/api_test.go @@ -12,6 +12,7 @@ import ( "internal/testenv" "reflect" "regexp" + "sort" "strings" "testing" @@ -403,69 +404,61 @@ func TestTypesInfo(t *testing.T) { } func TestInstanceInfo(t *testing.T) { - var tests = []struct { - src string + const lib = `package lib + +func F[P any](P) {} + +type T[P any] []P +` + + type testInst struct { name string targs []string typ string + } + + var tests = []struct { + src string + instances []testInst // recorded instances in source order }{ {`package p0; func f[T any](T) {}; func _() { f(42) }`, - `f`, - []string{`int`}, - `func(int)`, + []testInst{{`f`, []string{`int`}, `func(int)`}}, }, {`package p1; func f[T any](T) T { panic(0) }; func _() { f('@') }`, - `f`, - []string{`rune`}, - `func(rune) rune`, + []testInst{{`f`, []string{`rune`}, `func(rune) rune`}}, }, {`package p2; func f[T any](...T) T { panic(0) }; func _() { f(0i) }`, - `f`, - []string{`complex128`}, - `func(...complex128) complex128`, + []testInst{{`f`, []string{`complex128`}, `func(...complex128) complex128`}}, }, {`package p3; func f[A, B, C any](A, *B, []C) {}; func _() { f(1.2, new(string), []byte{}) }`, - `f`, - []string{`float64`, `string`, `byte`}, - `func(float64, *string, []byte)`, + []testInst{{`f`, []string{`float64`, `string`, `byte`}, `func(float64, *string, []byte)`}}, }, {`package p4; func f[A, B any](A, *B, ...[]B) {}; func _() { f(1.2, new(byte)) }`, - `f`, - []string{`float64`, `byte`}, - `func(float64, *byte, ...[]byte)`, + []testInst{{`f`, []string{`float64`, `byte`}, `func(float64, *byte, ...[]byte)`}}, }, - // we don't know how to translate these but we can type-check them {`package q0; type T struct{}; func (T) m[P any](P) {}; func _(x T) { x.m(42) }`, - `m`, - []string{`int`}, - `func(int)`, + []testInst{{`m`, []string{`int`}, `func(int)`}}, }, {`package q1; type T struct{}; func (T) m[P any](P) P { panic(0) }; func _(x T) { x.m(42) }`, - `m`, - []string{`int`}, - `func(int) int`, + []testInst{{`m`, []string{`int`}, `func(int) int`}}, }, {`package q2; type T struct{}; func (T) m[P any](...P) P { panic(0) }; func _(x T) { x.m(42) }`, - `m`, - []string{`int`}, - `func(...int) int`, + []testInst{{`m`, []string{`int`}, `func(...int) int`}}, }, {`package q3; type T struct{}; func (T) m[A, B, C any](A, *B, []C) {}; func _(x T) { x.m(1.2, new(string), []byte{}) }`, - `m`, - []string{`float64`, `string`, `byte`}, - `func(float64, *string, []byte)`, + []testInst{{`m`, []string{`float64`, `string`, `byte`}, `func(float64, *string, []byte)`}}, }, {`package q4; type T struct{}; func (T) m[A, B any](A, *B, ...[]B) {}; func _(x T) { x.m(1.2, new(byte)) }`, - `m`, - []string{`float64`, `byte`}, - `func(float64, *byte, ...[]byte)`, + []testInst{{`m`, []string{`float64`, `byte`}, `func(float64, *byte, ...[]byte)`}}, }, - {`package r0; type T[P any] struct{}; func (_ T[P]) m[Q any](Q) {}; func _[P any](x T[P]) { x.m(42) }`, - `m`, - []string{`int`}, - `func(int)`, + {`package r0; type T[P1 any] struct{}; func (_ T[P2]) m[Q any](Q) {}; func _[P3 any](x T[P3]) { x.m(42) }`, + []testInst{ + {`T`, []string{`P2`}, `struct{}`}, + {`T`, []string{`P3`}, `struct{}`}, + {`m`, []string{`int`}, `func(int)`}, + }, }, // TODO(gri) record method type parameters in syntax.FuncType so we can check this // {`package r1; type T interface{ m[P any](P) }; func _(x T) { x.m(4.2) }`, @@ -475,98 +468,112 @@ func TestInstanceInfo(t *testing.T) { // }, {`package s1; func f[T any, P interface{*T}](x T) {}; func _(x string) { f(x) }`, - `f`, - []string{`string`, `*string`}, - `func(x string)`, + []testInst{{`f`, []string{`string`, `*string`}, `func(x string)`}}, }, {`package s2; func f[T any, P interface{*T}](x []T) {}; func _(x []int) { f(x) }`, - `f`, - []string{`int`, `*int`}, - `func(x []int)`, + []testInst{{`f`, []string{`int`, `*int`}, `func(x []int)`}}, }, {`package s3; type C[T any] interface{chan<- T}; func f[T any, P C[T]](x []T) {}; func _(x []int) { f(x) }`, - `f`, - []string{`int`, `chan<- int`}, - `func(x []int)`, + []testInst{ + {`C`, []string{`T`}, `interface{chan<- T}`}, + {`f`, []string{`int`, `chan<- int`}, `func(x []int)`}, + }, }, {`package s4; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]](x []T) {}; func _(x []int) { f(x) }`, - `f`, - []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, - `func(x []int)`, + []testInst{ + {`C`, []string{`T`}, `interface{chan<- T}`}, + {`C`, []string{`[]*P`}, `interface{chan<- []*P}`}, + {`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func(x []int)`}, + }, }, {`package t1; func f[T any, P interface{*T}]() T { panic(0) }; func _() { _ = f[string] }`, - `f`, - []string{`string`, `*string`}, - `func() string`, + []testInst{{`f`, []string{`string`, `*string`}, `func() string`}}, }, {`package t2; func f[T any, P interface{*T}]() T { panic(0) }; func _() { _ = (f[string]) }`, - `f`, - []string{`string`, `*string`}, - `func() string`, + []testInst{{`f`, []string{`string`, `*string`}, `func() string`}}, }, {`package t3; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = f[int] }`, - `f`, - []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, - `func() []int`, + []testInst{ + {`C`, []string{`T`}, `interface{chan<- T}`}, + {`C`, []string{`[]*P`}, `interface{chan<- []*P}`}, + {`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`}, + }, }, {`package t4; type C[T any] interface{chan<- T}; func f[T any, P C[T], Q C[[]*P]]() []T { return nil }; func _() { _ = (f[int]) }`, - `f`, - []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, - `func() []int`, + []testInst{ + {`C`, []string{`T`}, `interface{chan<- T}`}, + {`C`, []string{`[]*P`}, `interface{chan<- []*P}`}, + {`f`, []string{`int`, `chan<- int`, `chan<- []*chan<- int`}, `func() []int`}, + }, + }, + {`package i0; import "lib"; func _() { lib.F(42) }`, + []testInst{{`F`, []string{`int`}, `func(int)`}}, }, - {`package i0; import "lib"; func _() { lib.F(42) }`, - `F`, - []string{`int`}, - `func(int)`, + {`package duplfunc0; func f[T any](T) {}; func _() { f(42); f("foo"); f[int](3) }`, + []testInst{ + {`f`, []string{`int`}, `func(int)`}, + {`f`, []string{`string`}, `func(string)`}, + {`f`, []string{`int`}, `func(int)`}, + }, + }, + {`package duplfunc1; import "lib"; func _() { lib.F(42); lib.F("foo"); lib.F(3) }`, + []testInst{ + {`F`, []string{`int`}, `func(int)`}, + {`F`, []string{`string`}, `func(string)`}, + {`F`, []string{`int`}, `func(int)`}, + }, }, {`package type0; type T[P interface{~int}] struct{ x P }; var _ T[int]`, - `T`, - []string{`int`}, - `struct{x int}`, + []testInst{{`T`, []string{`int`}, `struct{x int}`}}, }, {`package type1; type T[P interface{~int}] struct{ x P }; var _ (T[int])`, - `T`, - []string{`int`}, - `struct{x int}`, + []testInst{{`T`, []string{`int`}, `struct{x int}`}}, }, {`package type2; type T[P interface{~int}] struct{ x P }; var _ T[(int)]`, - `T`, - []string{`int`}, - `struct{x int}`, + []testInst{{`T`, []string{`int`}, `struct{x int}`}}, }, {`package type3; type T[P1 interface{~[]P2}, P2 any] struct{ x P1; y P2 }; var _ T[[]int, int]`, - `T`, - []string{`[]int`, `int`}, - `struct{x []int; y int}`, + []testInst{{`T`, []string{`[]int`, `int`}, `struct{x []int; y int}`}}, }, {`package type4; import "lib"; var _ lib.T[int]`, - `T`, - []string{`int`}, - `[]int`, + []testInst{{`T`, []string{`int`}, `[]int`}}, + }, + + {`package dupltype0; type T[P interface{~int}] struct{ x P }; var x T[int]; var y T[int]`, + []testInst{ + {`T`, []string{`int`}, `struct{x int}`}, + {`T`, []string{`int`}, `struct{x int}`}, + }, + }, + {`package dupltype1; type T[P ~int] struct{ x P }; func (r *T[Q]) add(z T[Q]) { r.x += z.x }`, + []testInst{ + {`T`, []string{`Q`}, `struct{x Q}`}, + {`T`, []string{`Q`}, `struct{x Q}`}, + }, + }, + {`package dupltype1; import "lib"; var x lib.T[int]; var y lib.T[int]; var z lib.T[string]`, + []testInst{ + {`T`, []string{`int`}, `[]int`}, + {`T`, []string{`int`}, `[]int`}, + {`T`, []string{`string`}, `[]string`}, + }, }, } for _, test := range tests { - const lib = `package lib - -func F[P any](P) {} - -type T[P any] []P -` - imports := make(testImporter) conf := Config{Importer: imports} - instances := make(map[*syntax.Name]Instance) - uses := make(map[*syntax.Name]Object) + instMap := make(map[*syntax.Name]Instance) + useMap := make(map[*syntax.Name]Object) makePkg := func(src string) *Package { f, err := parseSrc("p.go", src) if err != nil { t.Fatal(err) } - pkg, err := conf.Check("", []*syntax.File{f}, &Info{Instances: instances, Uses: uses}) + pkg, err := conf.Check("", []*syntax.File{f}, &Info{Instances: instMap, Uses: useMap}) if err != nil { t.Fatal(err) } @@ -576,60 +583,72 @@ type T[P any] []P makePkg(lib) pkg := makePkg(test.src) - // look for instance information - var targs []Type - var typ Type - for ident, inst := range instances { - if syntax.String(ident) == test.name { - for i := 0; i < inst.TypeArgs.Len(); i++ { - targs = append(targs, inst.TypeArgs.At(i)) - } - typ = inst.Type + t.Run(pkg.Name(), func(t *testing.T) { + // Sort instances in source order for stability. + instances := sortedInstances(instMap) + if got, want := len(instances), len(test.instances); got != want { + t.Fatalf("got %d instances, want %d", got, want) + } - // Check that we can find the corresponding parameterized type. - ptype := uses[ident].Type() + // Pairwise compare with the expected instances. + for ii, inst := range instances { + var targs []Type + for i := 0; i < inst.Inst.TypeArgs.Len(); i++ { + targs = append(targs, inst.Inst.TypeArgs.At(i)) + } + typ := inst.Inst.Type + + testInst := test.instances[ii] + if got := inst.Name.Value; got != testInst.name { + t.Fatalf("got name %s, want %s", got, testInst.name) + } + + if len(targs) != len(testInst.targs) { + t.Fatalf("got %d type arguments; want %d", len(targs), len(testInst.targs)) + } + for i, targ := range targs { + if got := targ.String(); got != testInst.targs[i] { + t.Errorf("type argument %d: got %s; want %s", i, got, testInst.targs[i]) + } + } + if got := typ.Underlying().String(); got != testInst.typ { + t.Errorf("package %s: got %s; want %s", pkg.Name(), got, testInst.typ) + } + + // Verify the invariant that re-instantiating the corresponding generic + // type with TypeArgs results in an identical instance. + ptype := useMap[inst.Name].Type() lister, _ := ptype.(interface{ TypeParams() *TypeParamList }) if lister == nil || lister.TypeParams().Len() == 0 { - t.Errorf("package %s: info.Types[%v] = %v, want parameterized type", pkg.Name(), ident, ptype) - continue + t.Fatalf("info.Types[%v] = %v, want parameterized type", inst.Name, ptype) } - - // Verify the invariant that re-instantiating the generic type with - // TypeArgs results in an equivalent type. inst2, err := Instantiate(nil, ptype, targs, true) if err != nil { t.Errorf("Instantiate(%v, %v) failed: %v", ptype, targs, err) } - if !Identical(inst.Type, inst2) { - t.Errorf("%v and %v are not identical", inst.Type, inst2) + if !Identical(inst.Inst.Type, inst2) { + t.Errorf("%v and %v are not identical", inst.Inst.Type, inst2) } - break } - } - if targs == nil { - t.Errorf("package %s: no instance information found for %s", pkg.Name(), test.name) - continue - } - - // check that type arguments are correct - if len(targs) != len(test.targs) { - t.Errorf("package %s: got %d type arguments; want %d", pkg.Name(), len(targs), len(test.targs)) - continue - } - for i, targ := range targs { - if got := targ.String(); got != test.targs[i] { - t.Errorf("package %s, %d. type argument: got %s; want %s", pkg.Name(), i, got, test.targs[i]) - continue - } - } - - // check that the types match - if got := typ.Underlying().String(); got != test.typ { - t.Errorf("package %s: got %s; want %s", pkg.Name(), got, test.typ) - } + }) } } +type recordedInstance struct { + Name *syntax.Name + Inst Instance +} + +func sortedInstances(m map[*syntax.Name]Instance) (instances []recordedInstance) { + for id, inst := range m { + instances = append(instances, recordedInstance{id, inst}) + } + sort.Slice(instances, func(i, j int) bool { + return instances[i].Name.Pos().Cmp(instances[j].Name.Pos()) < 0 + }) + return instances +} + func TestDefsInfo(t *testing.T) { var tests = []struct { src string @@ -1409,15 +1428,23 @@ type C struct { c int } +type G[P any] struct { + p P +} + +func (G[P]) m(P) {} + +var Inst G[int] + func (C) g() func (*C) h() func main() { // qualified identifiers var _ lib.T - _ = lib.C - _ = lib.F - _ = lib.V + _ = lib.C + _ = lib.F + _ = lib.V _ = lib.T.M // fields @@ -1433,25 +1460,30 @@ func main() { _ = A{}.c _ = new(A).c + _ = Inst.p + _ = G[string]{}.p + // methods - _ = A{}.f - _ = new(A).f - _ = A{}.g - _ = new(A).g - _ = new(A).h + _ = A{}.f + _ = new(A).f + _ = A{}.g + _ = new(A).g + _ = new(A).h - _ = B{}.f - _ = new(B).f + _ = B{}.f + _ = new(B).f - _ = C{}.g - _ = new(C).g - _ = new(C).h + _ = C{}.g + _ = new(C).g + _ = new(C).h + _ = Inst.m // method expressions - _ = A.f - _ = (*A).f - _ = B.f - _ = (*B).f + _ = A.f + _ = (*A).f + _ = B.f + _ = (*B).f + _ = G[string].m }` wantOut := map[string][2]string{ @@ -1465,6 +1497,7 @@ func main() { "new(A).b": {"field (*main.A) b int", "->[0 0]"}, "A{}.c": {"field (main.A) c int", ".[1 0]"}, "new(A).c": {"field (*main.A) c int", "->[1 0]"}, + "Inst.p": {"field (main.G[int]) p int", ".[0]"}, "A{}.f": {"method (main.A) f(int)", "->[0 0]"}, "new(A).f": {"method (*main.A) f(int)", "->[0 0]"}, @@ -1476,11 +1509,14 @@ func main() { "C{}.g": {"method (main.C) g()", ".[0]"}, "new(C).g": {"method (*main.C) g()", "->[0]"}, "new(C).h": {"method (*main.C) h()", "->[1]"}, // TODO(gri) should this report .[1] ? + "Inst.m": {"method (main.G[int]) m(int)", ".[0]"}, - "A.f": {"method expr (main.A) f(main.A, int)", "->[0 0]"}, - "(*A).f": {"method expr (*main.A) f(*main.A, int)", "->[0 0]"}, - "B.f": {"method expr (main.B) f(main.B, int)", ".[0]"}, - "(*B).f": {"method expr (*main.B) f(*main.B, int)", "->[0]"}, + "A.f": {"method expr (main.A) f(main.A, int)", "->[0 0]"}, + "(*A).f": {"method expr (*main.A) f(*main.A, int)", "->[0 0]"}, + "B.f": {"method expr (main.B) f(main.B, int)", ".[0]"}, + "(*B).f": {"method expr (*main.B) f(*main.B, int)", "->[0]"}, + "G[string].m": {"method expr (main.G[string]) m(main.G[string], string)", ".[0]"}, + "G[string]{}.p": {"field (main.G[string]) p string", ".[0]"}, } makePkg("lib", libSrc) diff --git a/src/cmd/compile/internal/types2/assignments.go b/src/cmd/compile/internal/types2/assignments.go index d88b03748f..49f4e2d2ab 100644 --- a/src/cmd/compile/internal/types2/assignments.go +++ b/src/cmd/compile/internal/types2/assignments.go @@ -44,7 +44,7 @@ func (check *Checker) assignment(x *operand, T Type, context string) { x.mode = invalid return } - } else if T == nil || IsInterface(T) && !isTypeParam(T) { + } else if T == nil || isNonTypeParamInterface(T) { target = Default(x.typ) } newType, val, code := check.implicitTypeAndValue(x, target) diff --git a/src/cmd/compile/internal/types2/call.go b/src/cmd/compile/internal/types2/call.go index d12ee49adb..3ade147dfe 100644 --- a/src/cmd/compile/internal/types2/call.go +++ b/src/cmd/compile/internal/types2/call.go @@ -64,7 +64,7 @@ func (check *Checker) instantiateSignature(pos syntax.Pos, typ *Signature, targs assert(len(targs) == typ.TypeParams().Len()) if check.conf.Trace { - check.trace(pos, "-- instantiating %s with %s", typ, targs) + check.trace(pos, "-- instantiating signature %s with %s", typ, targs) check.indent++ defer func() { check.indent-- @@ -88,7 +88,7 @@ func (check *Checker) instantiateSignature(pos syntax.Pos, typ *Signature, targs } else { check.mono.recordInstance(check.pkg, pos, tparams, targs, xlist) } - }) + }).describef(pos, "verify instantiation") return inst } @@ -423,7 +423,7 @@ var cgoPrefixes = [...]string{ "_Cmacro_", // function to evaluate the expanded expression } -func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { +func (check *Checker) selector(x *operand, e *syntax.SelectorExpr, def *Named) { // these must be declared before the "goto Error" statements var ( obj Object @@ -526,6 +526,12 @@ func (check *Checker) selector(x *operand, e *syntax.SelectorExpr) { check.exprOrType(x, e.X, false) switch x.mode { + case typexpr: + // don't crash for "type T T.x" (was issue #51509) + if def != nil && x.typ == def { + check.cycleError([]Object{def.obj}) + goto Error + } case builtin: check.errorf(e.Pos(), "cannot select on %s", x) goto Error diff --git a/src/cmd/compile/internal/types2/check.go b/src/cmd/compile/internal/types2/check.go index 4ec6a7b4fd..5cf8454aa4 100644 --- a/src/cmd/compile/internal/types2/check.go +++ b/src/cmd/compile/internal/types2/check.go @@ -373,11 +373,17 @@ func (check *Checker) processDelayed(top int) { // this is a sufficiently bounded process. for i := top; i < len(check.delayed); i++ { a := &check.delayed[i] - if check.conf.Trace && a.desc != nil { - fmt.Println() - check.trace(a.desc.pos.Pos(), "-- "+a.desc.format, a.desc.args...) + if check.conf.Trace { + if a.desc != nil { + check.trace(a.desc.pos.Pos(), "-- "+a.desc.format, a.desc.args...) + } else { + check.trace(nopos, "-- delayed %p", a.f) + } } a.f() // may append to check.delayed + if check.conf.Trace { + fmt.Println() + } } assert(top <= len(check.delayed)) // stack must not have shrunk check.delayed = check.delayed[:top] diff --git a/src/cmd/compile/internal/types2/check_test.go b/src/cmd/compile/internal/types2/check_test.go index 7efa512164..cdf440f9be 100644 --- a/src/cmd/compile/internal/types2/check_test.go +++ b/src/cmd/compile/internal/types2/check_test.go @@ -23,9 +23,10 @@ package types2_test import ( + "bytes" "cmd/compile/internal/syntax" "flag" - "internal/buildcfg" + "fmt" "internal/testenv" "os" "path/filepath" @@ -80,26 +81,45 @@ func delta(x, y uint) uint { } } -// goVersionRx matches a Go version string using '_', e.g. "go1_12". -var goVersionRx = regexp.MustCompile(`^go[1-9][0-9]*_(0|[1-9][0-9]*)$`) +// Note: parseFlags is identical to the version in go/types which is +// why it has a src argument even though here it is always nil. -// asGoVersion returns a regular Go language version string -// if s is a Go version string using '_' rather than '.' to -// separate the major and minor version numbers (e.g. "go1_12"). -// Otherwise it returns the empty string. -func asGoVersion(s string) string { - if goVersionRx.MatchString(s) { - return strings.Replace(s, "_", ".", 1) +// parseFlags parses flags from the first line of the given source +// (from src if present, or by reading from the file) if the line +// starts with "//" (line comment) followed by "-" (possiby with +// spaces between). Otherwise the line is ignored. +func parseFlags(filename string, src []byte, flags *flag.FlagSet) error { + // If there is no src, read from the file. + const maxLen = 256 + if len(src) == 0 { + f, err := os.Open(filename) + if err != nil { + return err + } + + var buf [maxLen]byte + n, err := f.Read(buf[:]) + if err != nil { + return err + } + src = buf[:n] } - return "" -} -// excludedForUnifiedBuild lists files that cannot be tested -// when using the unified build's export data. -// TODO(gri) enable as soon as the unified build supports this. -var excludedForUnifiedBuild = map[string]bool{ - "issue47818.go2": true, - "issue49705.go2": true, + // we must have a line comment that starts with a "-" + const prefix = "//" + if !bytes.HasPrefix(src, []byte(prefix)) { + return nil // first line is not a line comment + } + src = src[len(prefix):] + if i := bytes.Index(src, []byte("-")); i < 0 || len(bytes.TrimSpace(src[:i])) != 0 { + return nil // comment doesn't start with a "-" + } + end := bytes.Index(src, []byte("\n")) + if end < 0 || end > maxLen { + return fmt.Errorf("flags comment line too long") + } + + return flags.Parse(strings.Fields(string(src[:end]))) } func testFiles(t *testing.T, filenames []string, colDelta uint, manual bool) { @@ -107,33 +127,21 @@ func testFiles(t *testing.T, filenames []string, colDelta uint, manual bool) { t.Fatal("no source files") } - if buildcfg.Experiment.Unified { - for _, f := range filenames { - if excludedForUnifiedBuild[filepath.Base(f)] { - t.Logf("%s cannot be tested with unified build - skipped", f) - return - } - } + var conf Config + flags := flag.NewFlagSet("", flag.PanicOnError) + flags.StringVar(&conf.GoVersion, "lang", "", "") + flags.BoolVar(&conf.FakeImportC, "fakeImportC", false, "") + if err := parseFlags(filenames[0], nil, flags); err != nil { + t.Fatal(err) } - var mode syntax.Mode - if strings.HasSuffix(filenames[0], ".go2") || manual { - mode |= syntax.AllowGenerics | syntax.AllowMethodTypeParams - } - // parse files and collect parser errors - files, errlist := parseFiles(t, filenames, mode) + files, errlist := parseFiles(t, filenames, syntax.AllowGenerics|syntax.AllowMethodTypeParams) pkgName := "" if len(files) > 0 { pkgName = files[0].PkgName.Value } - // if no Go version is given, consider the package name - goVersion := *goVersion - if goVersion == "" { - goVersion = asGoVersion(pkgName) - } - listErrors := manual && !*verifyErrors if listErrors && len(errlist) > 0 { t.Errorf("--- %s:", pkgName) @@ -143,12 +151,6 @@ func testFiles(t *testing.T, filenames []string, colDelta uint, manual bool) { } // typecheck and collect typechecker errors - var conf Config - conf.GoVersion = goVersion - // special case for importC.src - if len(filenames) == 1 && strings.HasSuffix(filenames[0], "importC.src") { - conf.FakeImportC = true - } conf.Trace = manual && testing.Verbose() conf.Importer = defaultImporter() conf.Error = func(err error) { @@ -263,7 +265,7 @@ func testFiles(t *testing.T, filenames []string, colDelta uint, manual bool) { // // go test -run Manual -- foo.go bar.go // -// If no source arguments are provided, the file testdata/manual.go2 +// If no source arguments are provided, the file testdata/manual.go // is used instead. // Provide the -verify flag to verify errors against ERROR comments // in the input files rather than having a list of errors reported. @@ -274,7 +276,7 @@ func TestManual(t *testing.T) { filenames := flag.Args() if len(filenames) == 0 { - filenames = []string{filepath.FromSlash("testdata/manual.go2")} + filenames = []string{filepath.FromSlash("testdata/manual.go")} } info, err := os.Stat(filenames[0]) @@ -295,13 +297,10 @@ func TestManual(t *testing.T) { // TODO(gri) go/types has extra TestLongConstants and TestIndexRepresentability tests -func TestCheck(t *testing.T) { DefPredeclaredTestFuncs(); testDirFiles(t, "testdata/check", 55, false) } // TODO(gri) narrow column tolerance -func TestSpec(t *testing.T) { DefPredeclaredTestFuncs(); testDirFiles(t, "testdata/spec", 0, false) } -func TestExamples(t *testing.T) { testDirFiles(t, "testdata/examples", 0, false) } -func TestFixedbugs(t *testing.T) { - DefPredeclaredTestFuncs() - testDirFiles(t, "testdata/fixedbugs", 0, false) -} +func TestCheck(t *testing.T) { testDirFiles(t, "testdata/check", 55, false) } // TODO(gri) narrow column tolerance +func TestSpec(t *testing.T) { testDirFiles(t, "testdata/spec", 0, false) } +func TestExamples(t *testing.T) { testDirFiles(t, "testdata/examples", 0, false) } +func TestFixedbugs(t *testing.T) { testDirFiles(t, "testdata/fixedbugs", 0, false) } func testDirFiles(t *testing.T, dir string, colDelta uint, manual bool) { testenv.MustHaveGoBuild(t) diff --git a/src/cmd/compile/internal/types2/conversions.go b/src/cmd/compile/internal/types2/conversions.go index 08b3cbff29..a86645a547 100644 --- a/src/cmd/compile/internal/types2/conversions.go +++ b/src/cmd/compile/internal/types2/conversions.go @@ -105,7 +105,7 @@ func (check *Checker) conversion(x *operand, T Type) { // (See also the TODO below.) if x.typ == Typ[UntypedNil] { // ok - } else if IsInterface(T) && !isTypeParam(T) || constArg && !isConstType(T) { + } else if isNonTypeParamInterface(T) || constArg && !isConstType(T) { final = Default(x.typ) } else if x.mode == constant_ && isInteger(x.typ) && allString(T) { final = x.typ diff --git a/src/cmd/compile/internal/types2/decl.go b/src/cmd/compile/internal/types2/decl.go index 579fa55e59..95143cbed5 100644 --- a/src/cmd/compile/internal/types2/decl.go +++ b/src/cmd/compile/internal/types2/decl.go @@ -502,7 +502,7 @@ func (check *Checker) typeDecl(obj *TypeName, tdecl *syntax.TypeDecl, def *Named } check.brokenAlias(obj) - rhs = check.varType(tdecl.Type) + rhs = check.typ(tdecl.Type) check.validAlias(obj, rhs) return } @@ -716,7 +716,7 @@ func (check *Checker) funcDecl(obj *Func, decl *declInfo) { if !check.conf.IgnoreFuncBodies && fdecl.Body != nil { check.later(func() { check.funcBody(decl, obj.name, sig, fdecl.Body, nil) - }) + }).describef(obj, "func %s", obj.name) } } diff --git a/src/cmd/compile/internal/types2/expr.go b/src/cmd/compile/internal/types2/expr.go index c587c40f80..23225c8d0d 100644 --- a/src/cmd/compile/internal/types2/expr.go +++ b/src/cmd/compile/internal/types2/expr.go @@ -1101,7 +1101,7 @@ func (check *Checker) binary(x *operand, e syntax.Expr, lhs, rhs syntax.Expr, op // TODO(gri) make canMix more efficient - called for each binary operation canMix := func(x, y *operand) bool { - if IsInterface(x.typ) && !isTypeParam(x.typ) || IsInterface(y.typ) && !isTypeParam(y.typ) { + if isNonTypeParamInterface(x.typ) || isNonTypeParamInterface(y.typ) { return true } if allBoolean(x.typ) != allBoolean(y.typ) { @@ -1214,7 +1214,7 @@ const ( // func (check *Checker) rawExpr(x *operand, e syntax.Expr, hint Type, allowGeneric bool) exprKind { if check.conf.Trace { - check.trace(e.Pos(), "expr %s", e) + check.trace(e.Pos(), "-- expr %s", e) check.indent++ defer func() { check.indent-- @@ -1328,7 +1328,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin // but before the enclosing scope contents changes (#22992). check.later(func() { check.funcBody(decl, "", sig, e.Body, iota) - }) + }).describef(e, "func literal") } x.mode = value x.typ = sig @@ -1429,7 +1429,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin } check.expr(x, e) if i >= len(fields) { - check.error(x, "too many values in struct literal") + check.errorf(x, "too many values in %s{…}", base) break // cannot continue } // i < len(fields) @@ -1442,7 +1442,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin check.assignment(x, etyp, "struct literal") } if len(e.ElemList) < len(fields) { - check.error(e.Rbrace, "too few values in struct literal") + check.errorf(e.Rbrace, "too few values in %s{…}", base) // ok to continue } } @@ -1491,6 +1491,10 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin check.error(e, "illegal cycle in type declaration") goto Error } + // If the map key type is an interface (but not a type parameter), + // the type of a constant key must be considered when checking for + // duplicates. + keyIsInterface := isNonTypeParamInterface(utyp.key) visited := make(map[interface{}][]Type, len(e.ElemList)) for _, e := range e.ElemList { kv, _ := e.(*syntax.KeyValueExpr) @@ -1505,9 +1509,8 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin } if x.mode == constant_ { duplicate := false - // if the key is of interface type, the type is also significant when checking for duplicates xkey := keyVal(x.val) - if IsInterface(utyp.key) { + if keyIsInterface { for _, vtyp := range visited[xkey] { if Identical(vtyp, x.typ) { duplicate = true @@ -1556,7 +1559,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin return kind case *syntax.SelectorExpr: - check.selector(x, e) + check.selector(x, e, nil) case *syntax.IndexExpr: if check.indexExpr(x, e) { @@ -1642,6 +1645,7 @@ func (check *Checker) exprInternal(x *operand, e syntax.Expr, hint Type) exprKin case invalid: goto Error case typexpr: + check.validVarType(e.X, x.typ) x.typ = &Pointer{base: x.typ} default: var base Type @@ -1713,6 +1717,10 @@ Error: } func keyVal(x constant.Value) interface{} { + // TODO(gri) This function must map 1, 1.0, and 1.0 + 0i to the same (integer) value. + // Same for 1.1 and 1.1 + 0i. + // Otherwise we won't get duplicate key errors for certain type parameter + // key types. See issue #51610. switch x.Kind() { case constant.Bool: return constant.BoolVal(x) diff --git a/src/cmd/compile/internal/types2/infer.go b/src/cmd/compile/internal/types2/infer.go index 29633028f3..78fc35b72a 100644 --- a/src/cmd/compile/internal/types2/infer.go +++ b/src/cmd/compile/internal/types2/infer.go @@ -355,7 +355,7 @@ func typeParamsString(list []*TypeParam) string { return b.String() } -// IsParameterized reports whether typ contains any of the type parameters of tparams. +// isParameterized reports whether typ contains any of the type parameters of tparams. func isParameterized(tparams []*TypeParam, typ Type) bool { w := tpWalker{ seen: make(map[Type]bool), @@ -739,8 +739,6 @@ func (w *cycleFinder) typ(typ Type) { // in signatures where they are handled explicitly. case *Signature: - // There are no "method types" so we should never see a recv. - assert(t.recv == nil) if t.params != nil { w.varList(t.params.vars) } diff --git a/src/cmd/compile/internal/types2/instantiate.go b/src/cmd/compile/internal/types2/instantiate.go index c2653a3834..a511538ccc 100644 --- a/src/cmd/compile/internal/types2/instantiate.go +++ b/src/cmd/compile/internal/types2/instantiate.go @@ -15,10 +15,10 @@ import ( // Instantiate instantiates the type orig with the given type arguments targs. // orig must be a *Named or a *Signature type. If there is no error, the -// resulting Type is a new, instantiated (not parameterized) type of the same -// kind (either a *Named or a *Signature). Methods attached to a *Named type -// are also instantiated, and associated with a new *Func that has the same -// position as the original method, but nil function scope. +// resulting Type is an instantiated type of the same kind (either a *Named or +// a *Signature). Methods attached to a *Named type are also instantiated, and +// associated with a new *Func that has the same position as the original +// method, but nil function scope. // // If ctxt is non-nil, it may be used to de-duplicate the instance against // previous instances with the same identity. As a special case, generic @@ -61,7 +61,7 @@ func Instantiate(ctxt *Context, orig Type, targs []Type, validate bool) (Type, e // instance creates a type or function instance using the given original type // typ and arguments targs. For Named types the resulting instance will be -// unexpanded. +// unexpanded. check may be nil. func (check *Checker) instance(pos syntax.Pos, orig Type, targs []Type, ctxt *Context) (res Type) { var h string if ctxt != nil { @@ -103,6 +103,7 @@ func (check *Checker) instance(pos syntax.Pos, orig Type, targs []Type, ctxt *Co // anymore; we need to set tparams to nil. sig.tparams = nil res = sig + default: // only types and functions can be generic panic(fmt.Sprintf("%v: cannot instantiate %v", pos, orig)) diff --git a/src/cmd/compile/internal/types2/interface.go b/src/cmd/compile/internal/types2/interface.go index 75597abaf9..b8bf88dc62 100644 --- a/src/cmd/compile/internal/types2/interface.go +++ b/src/cmd/compile/internal/types2/interface.go @@ -12,7 +12,6 @@ import "cmd/compile/internal/syntax" // An Interface represents an interface type. type Interface struct { check *Checker // for error reporting; nil once type set is computed - obj *TypeName // corresponding declared object; or nil (for better error messages) methods []*Func // ordered list of explicitly declared methods embeddeds []Type // ordered list of explicitly embedded elements embedPos *[]syntax.Pos // positions of embedded elements; or nil (for error messages) - use pointer to save space diff --git a/src/cmd/compile/internal/types2/lookup.go b/src/cmd/compile/internal/types2/lookup.go index 0a2d2a5790..0832877226 100644 --- a/src/cmd/compile/internal/types2/lookup.go +++ b/src/cmd/compile/internal/types2/lookup.go @@ -70,7 +70,8 @@ func LookupFieldOrMethod(T Type, addressable bool, pkg *Package, name string) (o // see if there is a matching field (but not a method, those need to be declared // explicitly in the constraint). If the constraint is a named pointer type (see // above), we are ok here because only fields are accepted as results. - if obj == nil && isTypeParam(T) { + const enableTParamFieldLookup = false // see issue #51576 + if enableTParamFieldLookup && obj == nil && isTypeParam(T) { if t := coreType(T); t != nil { obj, index, indirect = lookupFieldOrMethod(t, addressable, pkg, name, false) if _, ok := obj.(*Var); !ok { diff --git a/src/cmd/compile/internal/types2/main_test.go b/src/cmd/compile/internal/types2/main_test.go new file mode 100644 index 0000000000..42d26943c4 --- /dev/null +++ b/src/cmd/compile/internal/types2/main_test.go @@ -0,0 +1,17 @@ +// Copyright 2022 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 types2_test + +import ( + "go/build" + "internal/testenv" + "os" + "testing" +) + +func TestMain(m *testing.M) { + build.Default.GOROOT = testenv.GOROOT(nil) + os.Exit(m.Run()) +} diff --git a/src/cmd/compile/internal/types2/named.go b/src/cmd/compile/internal/types2/named.go index 5c6a1cf5d8..89d24d4e0b 100644 --- a/src/cmd/compile/internal/types2/named.go +++ b/src/cmd/compile/internal/types2/named.go @@ -78,6 +78,7 @@ func (check *Checker) newNamed(obj *TypeName, orig *Named, underlying Type, tpar } func (t *Named) cleanup() { + assert(t.orig.orig == t.orig) // Ensure that every defined type created in the course of type-checking has // either non-*Named underlying, or is unresolved. // @@ -98,10 +99,10 @@ func (t *Named) cleanup() { } // Obj returns the type name for the declaration defining the named type t. For -// instantiated types, this is the type name of the base type. +// instantiated types, this is same as the type name of the origin type. func (t *Named) Obj() *TypeName { return t.orig.obj } // for non-instances this is the same as t.obj -// Origin returns the parameterized type from which the named type t is +// Origin returns the generic type from which the named type t is // instantiated. If t is not an instantiated type, the result is t. func (t *Named) Origin() *Named { return t.orig } @@ -109,7 +110,7 @@ func (t *Named) Origin() *Named { return t.orig } // between parameterized instantiated and non-instantiated types. // TypeParams returns the type parameters of the named type t, or nil. -// The result is non-nil for an (originally) parameterized type even if it is instantiated. +// The result is non-nil for an (originally) generic type even if it is instantiated. func (t *Named) TypeParams() *TypeParamList { return t.resolve(nil).tparams } // SetTypeParams sets the type parameters of the named type t. @@ -122,7 +123,11 @@ func (t *Named) SetTypeParams(tparams []*TypeParam) { // TypeArgs returns the type arguments used to instantiate the named type t. func (t *Named) TypeArgs() *TypeList { return t.targs } -// NumMethods returns the number of explicit methods whose receiver is named type t. +// NumMethods returns the number of explicit methods defined for t. +// +// For an ordinary or instantiated type t, the receiver base type of these +// methods will be the named type t. For an uninstantiated generic type t, each +// method receiver will be instantiated with its receiver type parameters. func (t *Named) NumMethods() int { return t.resolve(nil).methods.Len() } // Method returns the i'th method of named type t for 0 <= i < t.NumMethods(). @@ -133,7 +138,7 @@ func (t *Named) Method(i int) *Func { }) } -// instiateMethod instantiates the i'th method for an instantiated receiver. +// instantiateMethod instantiates the i'th method for an instantiated receiver. func (t *Named) instantiateMethod(i int) *Func { assert(t.TypeArgs().Len() > 0) // t must be an instance @@ -350,11 +355,19 @@ func (check *Checker) bestContext(ctxt *Context) *Context { // expandNamed ensures that the underlying type of n is instantiated. // The underlying type will be Typ[Invalid] if there was an error. func expandNamed(ctxt *Context, n *Named, instPos syntax.Pos) (tparams *TypeParamList, underlying Type, methods *methodList) { + check := n.check + if check != nil && check.conf.Trace { + check.trace(instPos, "-- expandNamed %s", n) + check.indent++ + defer func() { + check.indent-- + check.trace(instPos, "=> %s (tparams = %s, under = %s)", n, tparams.list(), underlying) + }() + } + n.orig.resolve(ctxt) assert(n.orig.underlying != nil) - check := n.check - if _, unexpanded := n.orig.underlying.(*Named); unexpanded { // We should only get an unexpanded underlying here during type checking // (for example, in recursive type declarations). diff --git a/src/cmd/compile/internal/types2/predicates.go b/src/cmd/compile/internal/types2/predicates.go index ba259341f6..6bce26137e 100644 --- a/src/cmd/compile/internal/types2/predicates.go +++ b/src/cmd/compile/internal/types2/predicates.go @@ -85,6 +85,11 @@ func IsInterface(t Type) bool { return ok } +// isNonTypeParamInterface reports whether t is an interface type but not a type parameter. +func isNonTypeParamInterface(t Type) bool { + return !isTypeParam(t) && IsInterface(t) +} + // isTypeParam reports whether t is a type parameter. func isTypeParam(t Type) bool { _, ok := t.(*TypeParam) diff --git a/src/cmd/compile/internal/types2/resolver.go b/src/cmd/compile/internal/types2/resolver.go index 05755f8cfd..61963cb043 100644 --- a/src/cmd/compile/internal/types2/resolver.go +++ b/src/cmd/compile/internal/types2/resolver.go @@ -413,7 +413,7 @@ func (check *Checker) collectObjects() { case *syntax.TypeDecl: if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) { - check.softErrorf(s.TParamList[0], "type parameters require go1.18 or later") + check.versionErrorf(s.TParamList[0], "go1.18", "type parameter") } obj := NewTypeName(s.Name.Pos(), pkg, s.Name.Value, nil) check.declarePkgObj(s.Name, obj, &declInfo{file: fileScope, tdecl: s}) @@ -458,7 +458,7 @@ func (check *Checker) collectObjects() { check.recordDef(s.Name, obj) } if len(s.TParamList) != 0 && !check.allowVersion(pkg, 1, 18) && !hasTParamError { - check.softErrorf(s.TParamList[0], "type parameters require go1.18 or later") + check.versionErrorf(s.TParamList[0], "go1.18", "type parameter") } info := &declInfo{file: fileScope, fdecl: s} // Methods are not package-level objects but we still track them in the diff --git a/src/cmd/compile/internal/types2/sizeof_test.go b/src/cmd/compile/internal/types2/sizeof_test.go index 14020050a9..bd31a041b7 100644 --- a/src/cmd/compile/internal/types2/sizeof_test.go +++ b/src/cmd/compile/internal/types2/sizeof_test.go @@ -28,7 +28,7 @@ func TestSizeof(t *testing.T) { {Tuple{}, 12, 24}, {Signature{}, 28, 56}, {Union{}, 12, 24}, - {Interface{}, 44, 88}, + {Interface{}, 40, 80}, {Map{}, 16, 32}, {Chan{}, 12, 24}, {Named{}, 56, 104}, diff --git a/src/cmd/compile/internal/types2/stdlib_test.go b/src/cmd/compile/internal/types2/stdlib_test.go index 551611da55..fda78e20d1 100644 --- a/src/cmd/compile/internal/types2/stdlib_test.go +++ b/src/cmd/compile/internal/types2/stdlib_test.go @@ -15,7 +15,6 @@ import ( "internal/testenv" "os" "path/filepath" - "runtime" "strings" "testing" "time" @@ -29,7 +28,7 @@ func TestStdlib(t *testing.T) { testenv.MustHaveGoBuild(t) pkgCount := 0 - duration := walkPkgDirs(filepath.Join(runtime.GOROOT(), "src"), func(dir string, filenames []string) { + duration := walkPkgDirs(filepath.Join(testenv.GOROOT(t), "src"), func(dir string, filenames []string) { typecheck(t, dir, filenames) pkgCount++ }, t.Error) @@ -162,7 +161,7 @@ func TestStdTest(t *testing.T) { t.Skip("skipping in short mode") } - testTestDir(t, filepath.Join(runtime.GOROOT(), "test"), + testTestDir(t, filepath.Join(testenv.GOROOT(t), "test"), "cmplxdivide.go", // also needs file cmplxdivide1.go - ignore "directive.go", // tests compiler rejection of bad directive placement - ignore "directive2.go", // tests compiler rejection of bad directive placement - ignore @@ -180,7 +179,7 @@ func TestStdFixed(t *testing.T) { t.Skip("skipping in short mode") } - testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "fixedbugs"), + testTestDir(t, filepath.Join(testenv.GOROOT(t), "test", "fixedbugs"), "bug248.go", "bug302.go", "bug369.go", // complex test instructions - ignore "issue6889.go", // gc-specific test "issue11362.go", // canonical import path check @@ -204,7 +203,7 @@ func TestStdFixed(t *testing.T) { func TestStdKen(t *testing.T) { testenv.MustHaveGoBuild(t) - testTestDir(t, filepath.Join(runtime.GOROOT(), "test", "ken")) + testTestDir(t, filepath.Join(testenv.GOROOT(t), "test", "ken")) } // Package paths of excluded packages. @@ -311,16 +310,13 @@ func (w *walker) walk(dir string) { } // apply pkgh to the files in directory dir - // but ignore files directly under $GOROOT/src (might be temporary test files). - if dir != filepath.Join(runtime.GOROOT(), "src") { - files, err := pkgFilenames(dir) - if err != nil { - w.errh(err) - return - } - if files != nil { - w.pkgh(dir, files) - } + pkgFiles, err := pkgFilenames(dir) + if err != nil { + w.errh(err) + return + } + if pkgFiles != nil { + w.pkgh(dir, pkgFiles) } // traverse subdirectories, but don't walk into testdata diff --git a/src/cmd/compile/internal/types2/stmt.go b/src/cmd/compile/internal/types2/stmt.go index 4c8eac725f..2b6abbde7e 100644 --- a/src/cmd/compile/internal/types2/stmt.go +++ b/src/cmd/compile/internal/types2/stmt.go @@ -18,10 +18,7 @@ func (check *Checker) funcBody(decl *declInfo, name string, sig *Signature, body } if check.conf.Trace { - check.trace(body.Pos(), "--- %s: %s", name, sig) - defer func() { - check.trace(syntax.EndPos(body), "--- ") - }() + check.trace(body.Pos(), "-- %s: %s", name, sig) } // set function scope extent @@ -95,6 +92,7 @@ const ( // additional context information finalSwitchCase + inTypeSwitch ) func (check *Checker) simpleStmt(s syntax.Stmt) { @@ -370,7 +368,9 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { // process collected function literals before scope changes defer check.processDelayed(len(check.delayed)) - inner := ctxt &^ (fallthroughOk | finalSwitchCase) + // reset context for statements of inner blocks + inner := ctxt &^ (fallthroughOk | finalSwitchCase | inTypeSwitch) + switch s := s.(type) { case *syntax.EmptyStmt: // ignore @@ -523,9 +523,14 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { } case syntax.Fallthrough: if ctxt&fallthroughOk == 0 { - msg := "fallthrough statement out of place" - if ctxt&finalSwitchCase != 0 { + var msg string + switch { + case ctxt&finalSwitchCase != 0: msg = "cannot fallthrough final case in switch" + case ctxt&inTypeSwitch != 0: + msg = "cannot fallthrough in type switch" + default: + msg = "fallthrough statement out of place" } check.error(s, msg) } @@ -572,7 +577,7 @@ func (check *Checker) stmt(ctxt stmtContext, s syntax.Stmt) { check.simpleStmt(s.Init) if g, _ := s.Tag.(*syntax.TypeSwitchGuard); g != nil { - check.typeSwitchStmt(inner, s, g) + check.typeSwitchStmt(inner|inTypeSwitch, s, g) } else { check.switchStmt(inner, s) } diff --git a/src/cmd/compile/internal/types2/testdata/check/blank.src b/src/cmd/compile/internal/types2/testdata/check/blank.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/blank.src rename to src/cmd/compile/internal/types2/testdata/check/blank.go diff --git a/src/cmd/compile/internal/types2/testdata/check/builtins.src b/src/cmd/compile/internal/types2/testdata/check/builtins0.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/builtins.src rename to src/cmd/compile/internal/types2/testdata/check/builtins0.go diff --git a/src/cmd/compile/internal/types2/testdata/check/builtins.go2 b/src/cmd/compile/internal/types2/testdata/check/builtins1.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/builtins.go2 rename to src/cmd/compile/internal/types2/testdata/check/builtins1.go diff --git a/src/cmd/compile/internal/types2/testdata/check/chans.go2 b/src/cmd/compile/internal/types2/testdata/check/chans.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/chans.go2 rename to src/cmd/compile/internal/types2/testdata/check/chans.go diff --git a/src/cmd/compile/internal/types2/testdata/check/compliterals.go2 b/src/cmd/compile/internal/types2/testdata/check/compliterals.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/compliterals.go2 rename to src/cmd/compile/internal/types2/testdata/check/compliterals.go diff --git a/src/cmd/compile/internal/types2/testdata/check/const0.src b/src/cmd/compile/internal/types2/testdata/check/const0.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/const0.src rename to src/cmd/compile/internal/types2/testdata/check/const0.go diff --git a/src/cmd/compile/internal/types2/testdata/check/const1.src b/src/cmd/compile/internal/types2/testdata/check/const1.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/const1.src rename to src/cmd/compile/internal/types2/testdata/check/const1.go diff --git a/src/cmd/compile/internal/types2/testdata/check/constdecl.src b/src/cmd/compile/internal/types2/testdata/check/constdecl.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/constdecl.src rename to src/cmd/compile/internal/types2/testdata/check/constdecl.go diff --git a/src/cmd/compile/internal/types2/testdata/check/conversions.src b/src/cmd/compile/internal/types2/testdata/check/conversions0.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/conversions.src rename to src/cmd/compile/internal/types2/testdata/check/conversions0.go diff --git a/src/cmd/compile/internal/types2/testdata/check/conversions2.src b/src/cmd/compile/internal/types2/testdata/check/conversions1.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/conversions2.src rename to src/cmd/compile/internal/types2/testdata/check/conversions1.go diff --git a/src/cmd/compile/internal/types2/testdata/check/cycles.src b/src/cmd/compile/internal/types2/testdata/check/cycles0.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/cycles.src rename to src/cmd/compile/internal/types2/testdata/check/cycles0.go diff --git a/src/cmd/compile/internal/types2/testdata/check/cycles1.src b/src/cmd/compile/internal/types2/testdata/check/cycles1.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/cycles1.src rename to src/cmd/compile/internal/types2/testdata/check/cycles1.go diff --git a/src/cmd/compile/internal/types2/testdata/check/cycles2.src b/src/cmd/compile/internal/types2/testdata/check/cycles2.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/cycles2.src rename to src/cmd/compile/internal/types2/testdata/check/cycles2.go diff --git a/src/cmd/compile/internal/types2/testdata/check/cycles3.src b/src/cmd/compile/internal/types2/testdata/check/cycles3.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/cycles3.src rename to src/cmd/compile/internal/types2/testdata/check/cycles3.go diff --git a/src/cmd/compile/internal/types2/testdata/check/cycles4.src b/src/cmd/compile/internal/types2/testdata/check/cycles4.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/cycles4.src rename to src/cmd/compile/internal/types2/testdata/check/cycles4.go diff --git a/src/cmd/compile/internal/types2/testdata/check/cycles5.src b/src/cmd/compile/internal/types2/testdata/check/cycles5.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/cycles5.src rename to src/cmd/compile/internal/types2/testdata/check/cycles5.go diff --git a/src/cmd/compile/internal/types2/testdata/check/decls0.src b/src/cmd/compile/internal/types2/testdata/check/decls0.go similarity index 98% rename from src/cmd/compile/internal/types2/testdata/check/decls0.src rename to src/cmd/compile/internal/types2/testdata/check/decls0.go index 09e5d5c5ad..aa98480b99 100644 --- a/src/cmd/compile/internal/types2/testdata/check/decls0.src +++ b/src/cmd/compile/internal/types2/testdata/check/decls0.go @@ -1,10 +1,12 @@ +// -lang=go1.17 + // Copyright 2011 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. // type declarations -package go1_17 // don't permit non-interface elements in interfaces +package p // don't permit non-interface elements in interfaces import "unsafe" diff --git a/src/cmd/compile/internal/types2/testdata/check/decls1.src b/src/cmd/compile/internal/types2/testdata/check/decls1.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/decls1.src rename to src/cmd/compile/internal/types2/testdata/check/decls1.go diff --git a/src/cmd/compile/internal/types2/testdata/check/decls2/decls2a.src b/src/cmd/compile/internal/types2/testdata/check/decls2/decls2a.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/decls2/decls2a.src rename to src/cmd/compile/internal/types2/testdata/check/decls2/decls2a.go diff --git a/src/cmd/compile/internal/types2/testdata/check/decls2/decls2b.src b/src/cmd/compile/internal/types2/testdata/check/decls2/decls2b.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/decls2/decls2b.src rename to src/cmd/compile/internal/types2/testdata/check/decls2/decls2b.go diff --git a/src/cmd/compile/internal/types2/testdata/check/decls3.src b/src/cmd/compile/internal/types2/testdata/check/decls3.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/decls3.src rename to src/cmd/compile/internal/types2/testdata/check/decls3.go diff --git a/src/cmd/compile/internal/types2/testdata/check/decls4.src b/src/cmd/compile/internal/types2/testdata/check/decls4.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/decls4.src rename to src/cmd/compile/internal/types2/testdata/check/decls4.go diff --git a/src/cmd/compile/internal/types2/testdata/check/decls5.src b/src/cmd/compile/internal/types2/testdata/check/decls5.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/decls5.src rename to src/cmd/compile/internal/types2/testdata/check/decls5.go diff --git a/src/cmd/compile/internal/types2/testdata/check/errors.src b/src/cmd/compile/internal/types2/testdata/check/errors.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/errors.src rename to src/cmd/compile/internal/types2/testdata/check/errors.go diff --git a/src/cmd/compile/internal/types2/testdata/check/expr0.src b/src/cmd/compile/internal/types2/testdata/check/expr0.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/expr0.src rename to src/cmd/compile/internal/types2/testdata/check/expr0.go diff --git a/src/cmd/compile/internal/types2/testdata/check/expr1.src b/src/cmd/compile/internal/types2/testdata/check/expr1.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/expr1.src rename to src/cmd/compile/internal/types2/testdata/check/expr1.go diff --git a/src/cmd/compile/internal/types2/testdata/check/expr2.src b/src/cmd/compile/internal/types2/testdata/check/expr2.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/expr2.src rename to src/cmd/compile/internal/types2/testdata/check/expr2.go diff --git a/src/cmd/compile/internal/types2/testdata/check/expr3.src b/src/cmd/compile/internal/types2/testdata/check/expr3.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/expr3.src rename to src/cmd/compile/internal/types2/testdata/check/expr3.go diff --git a/src/go/types/testdata/check/funcinference.go2 b/src/cmd/compile/internal/types2/testdata/check/funcinference.go similarity index 97% rename from src/go/types/testdata/check/funcinference.go2 rename to src/cmd/compile/internal/types2/testdata/check/funcinference.go index 45d0781cd7..fedf1991dd 100644 --- a/src/go/types/testdata/check/funcinference.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/funcinference.go @@ -85,7 +85,7 @@ type Setter[B any] interface { func FromStrings[T interface{}, PT Setter[T]](s []string) []T { result := make([]T, len(s)) for i, v := range s { - // The type of &result[i] is *T which is in the type list + // The type of &result[i] is *T which is in the type set // of Setter, so we can convert it to PT. p := PT(&result[i]) // PT has a Set method. diff --git a/src/go/types/testdata/check/go1_12.src b/src/cmd/compile/internal/types2/testdata/check/go1_12.go similarity index 97% rename from src/go/types/testdata/check/go1_12.src rename to src/cmd/compile/internal/types2/testdata/check/go1_12.go index 1e529f18be..56c6d5a4c9 100644 --- a/src/go/types/testdata/check/go1_12.src +++ b/src/cmd/compile/internal/types2/testdata/check/go1_12.go @@ -1,10 +1,12 @@ +// -lang=go1.12 + // Copyright 2021 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. // Check Go language version-specific errors. -package go1_12 // go1.12 +package p // numeric literals const ( @@ -32,4 +34,3 @@ var ( _ = 1 << s // ERROR "invalid operation: signed shift count s \(variable of type int\) requires go1.13 or later" _ = 1 >> s // ERROR "signed shift count" ) - diff --git a/src/go/types/testdata/check/go1_13.src b/src/cmd/compile/internal/types2/testdata/check/go1_13.go similarity index 93% rename from src/go/types/testdata/check/go1_13.src rename to src/cmd/compile/internal/types2/testdata/check/go1_13.go index 6aa1364e8a..cc7861d616 100644 --- a/src/go/types/testdata/check/go1_13.src +++ b/src/cmd/compile/internal/types2/testdata/check/go1_13.go @@ -1,10 +1,12 @@ +// -lang=go1.13 + // Copyright 2021 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. // Check Go language version-specific errors. -package go1_13 // go1.13 +package p // interface embedding @@ -19,4 +21,3 @@ type _ interface { I I // ERROR "duplicate method m" } - diff --git a/src/cmd/compile/internal/types2/testdata/check/go1_16.src b/src/cmd/compile/internal/types2/testdata/check/go1_16.go similarity index 92% rename from src/cmd/compile/internal/types2/testdata/check/go1_16.src rename to src/cmd/compile/internal/types2/testdata/check/go1_16.go index fdf5c99d7e..81b529044c 100644 --- a/src/cmd/compile/internal/types2/testdata/check/go1_16.src +++ b/src/cmd/compile/internal/types2/testdata/check/go1_16.go @@ -1,10 +1,12 @@ +// -lang=go1.16 + // Copyright 2021 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. // Check Go language version-specific errors. -package go1_16 // go1.16 +package p type Slice []byte type Array [8]byte diff --git a/src/cmd/compile/internal/types2/testdata/check/go1_8.src b/src/cmd/compile/internal/types2/testdata/check/go1_8.go similarity index 92% rename from src/cmd/compile/internal/types2/testdata/check/go1_8.src rename to src/cmd/compile/internal/types2/testdata/check/go1_8.go index 0f3ba9443b..15462aba14 100644 --- a/src/cmd/compile/internal/types2/testdata/check/go1_8.src +++ b/src/cmd/compile/internal/types2/testdata/check/go1_8.go @@ -1,10 +1,12 @@ +// -lang=go1.8 + // Copyright 2021 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. // Check Go language version-specific errors. -package go1_8 // go1.8 +package p // type alias declarations type any /* ERROR type aliases requires go1.9 or later */ = interface{} diff --git a/src/cmd/compile/internal/types2/testdata/check/gotos.src b/src/cmd/compile/internal/types2/testdata/check/gotos.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/gotos.src rename to src/cmd/compile/internal/types2/testdata/check/gotos.go diff --git a/src/cmd/compile/internal/types2/testdata/check/importC.src b/src/cmd/compile/internal/types2/testdata/check/importC.go similarity index 98% rename from src/cmd/compile/internal/types2/testdata/check/importC.src rename to src/cmd/compile/internal/types2/testdata/check/importC.go index f55be2d5c5..807802199f 100644 --- a/src/cmd/compile/internal/types2/testdata/check/importC.src +++ b/src/cmd/compile/internal/types2/testdata/check/importC.go @@ -1,3 +1,5 @@ +// -fakeImportC + // Copyright 2015 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. diff --git a/src/cmd/compile/internal/types2/testdata/check/importdecl0/importdecl0a.src b/src/cmd/compile/internal/types2/testdata/check/importdecl0/importdecl0a.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/importdecl0/importdecl0a.src rename to src/cmd/compile/internal/types2/testdata/check/importdecl0/importdecl0a.go diff --git a/src/cmd/compile/internal/types2/testdata/check/importdecl0/importdecl0b.src b/src/cmd/compile/internal/types2/testdata/check/importdecl0/importdecl0b.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/importdecl0/importdecl0b.src rename to src/cmd/compile/internal/types2/testdata/check/importdecl0/importdecl0b.go diff --git a/src/cmd/compile/internal/types2/testdata/check/importdecl1/importdecl1a.src b/src/cmd/compile/internal/types2/testdata/check/importdecl1/importdecl1a.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/importdecl1/importdecl1a.src rename to src/cmd/compile/internal/types2/testdata/check/importdecl1/importdecl1a.go diff --git a/src/cmd/compile/internal/types2/testdata/check/importdecl1/importdecl1b.src b/src/cmd/compile/internal/types2/testdata/check/importdecl1/importdecl1b.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/importdecl1/importdecl1b.src rename to src/cmd/compile/internal/types2/testdata/check/importdecl1/importdecl1b.go diff --git a/src/cmd/compile/internal/types2/testdata/check/init0.src b/src/cmd/compile/internal/types2/testdata/check/init0.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/init0.src rename to src/cmd/compile/internal/types2/testdata/check/init0.go diff --git a/src/cmd/compile/internal/types2/testdata/check/init1.src b/src/cmd/compile/internal/types2/testdata/check/init1.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/init1.src rename to src/cmd/compile/internal/types2/testdata/check/init1.go diff --git a/src/cmd/compile/internal/types2/testdata/check/init2.src b/src/cmd/compile/internal/types2/testdata/check/init2.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/init2.src rename to src/cmd/compile/internal/types2/testdata/check/init2.go diff --git a/src/cmd/compile/internal/types2/testdata/check/issue25008/issue25008a.src b/src/cmd/compile/internal/types2/testdata/check/issue25008/issue25008a.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/issue25008/issue25008a.src rename to src/cmd/compile/internal/types2/testdata/check/issue25008/issue25008a.go diff --git a/src/cmd/compile/internal/types2/testdata/check/issue25008/issue25008b.src b/src/cmd/compile/internal/types2/testdata/check/issue25008/issue25008b.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/issue25008/issue25008b.src rename to src/cmd/compile/internal/types2/testdata/check/issue25008/issue25008b.go diff --git a/src/cmd/compile/internal/types2/testdata/check/issues.src b/src/cmd/compile/internal/types2/testdata/check/issues0.go similarity index 99% rename from src/cmd/compile/internal/types2/testdata/check/issues.src rename to src/cmd/compile/internal/types2/testdata/check/issues0.go index 42c5bc8f12..4ac3fc2f9d 100644 --- a/src/cmd/compile/internal/types2/testdata/check/issues.src +++ b/src/cmd/compile/internal/types2/testdata/check/issues0.go @@ -1,8 +1,10 @@ +// -lang=go1.17 + // Copyright 2014 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 go1_17 // don't permit non-interface elements in interfaces +package p // don't permit non-interface elements in interfaces import ( "fmt" diff --git a/src/cmd/compile/internal/types2/testdata/check/issues.go2 b/src/cmd/compile/internal/types2/testdata/check/issues1.go similarity index 84% rename from src/cmd/compile/internal/types2/testdata/check/issues.go2 rename to src/cmd/compile/internal/types2/testdata/check/issues1.go index 1763550c04..41a19ad637 100644 --- a/src/cmd/compile/internal/types2/testdata/check/issues.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/issues1.go @@ -51,9 +51,8 @@ func _() { } // When a type parameter is used as an argument to instantiate a parameterized -// type with a type list constraint, all of the type argument's types in its -// bound, but at least one (!), must be in the type list of the bound of the -// corresponding parameterized type's type parameter. +// type, the type argument's type set must be a subset of the instantiated type +// parameter's type set. type T1[P interface{~uint}] struct{} func _[P any]() { @@ -150,7 +149,7 @@ type inf2[T any] struct{ inf2 /* ERROR illegal cycle */ [T] } // The implementation of conversions T(x) between integers and floating-point // numbers checks that both T and x have either integer or floating-point // type. When the type of T or x is a type parameter, the respective simple -// predicate disjunction in the implementation was wrong because if a type list +// predicate disjunction in the implementation was wrong because if a type set // contains both an integer and a floating-point type, the type parameter is // neither an integer or a floating-point number. func convert[T1, T2 interface{~int | ~uint | ~float32}](v T1) T2 { @@ -183,14 +182,12 @@ func _[T interface{}, PT interface{~*T}] (x T) PT { return &x } -// Indexing of generic types containing type parameters in their type list: +// Indexing of type parameters containing type parameters in their constraint terms: func at[T interface{ ~[]E }, E interface{}](x T, i int) E { return x[i] } -// A generic type inside a function acts like a named type. Its underlying -// type is itself, its "operational type" is defined by the type list in -// the tybe bound, if any. +// Conversion of a local type to a type parameter. func _[T interface{~int}](x T) { type myint int var _ int = int(x) @@ -198,19 +195,19 @@ func _[T interface{~int}](x T) { var _ T = T(myint(42)) } -// Indexing a generic type with an array type bound checks length. +// Indexing a type parameter with an array type bound checks length. // (Example by mdempsky@.) func _[T interface { ~[10]int }](x T) { _ = x[9] // ok _ = x[20 /* ERROR out of bounds */ ] } -// Pointer indirection of a generic type. +// Pointer indirection of a type parameter. func _[T interface{ ~*int }](p T) int { return *p } -// Channel sends and receives on generic types. +// Channel sends and receives on type parameters. func _[T interface{ ~chan int }](ch T) int { ch <- 0 return <- ch @@ -229,11 +226,11 @@ func _[T interface{ func()|F1|F2 }](f T) { go f() } -// We must compare against the underlying type of type list entries -// when checking if a constraint is satisfied by a type. The under- -// lying type of each type list entry must be computed after the -// interface has been instantiated as its typelist may contain a -// type parameter that was substituted with a defined type. +// We must compare against the (possibly underlying) types of term list +// elements when checking if a constraint is satisfied by a type. +// The underlying type of each term must be computed after the +// interface has been instantiated as its constraint may contain +// a type parameter that was substituted with a defined type. // Test case from an (originally) failing example. type sliceOf[E any] interface{ ~[]E } diff --git a/src/cmd/compile/internal/types2/testdata/check/labels.src b/src/cmd/compile/internal/types2/testdata/check/labels.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/labels.src rename to src/cmd/compile/internal/types2/testdata/check/labels.go diff --git a/src/cmd/compile/internal/types2/testdata/check/linalg.go2 b/src/cmd/compile/internal/types2/testdata/check/linalg.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/linalg.go2 rename to src/cmd/compile/internal/types2/testdata/check/linalg.go diff --git a/src/cmd/compile/internal/types2/testdata/check/literals.src b/src/cmd/compile/internal/types2/testdata/check/literals.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/literals.src rename to src/cmd/compile/internal/types2/testdata/check/literals.go diff --git a/src/cmd/compile/internal/types2/testdata/check/main.src b/src/cmd/compile/internal/types2/testdata/check/main0.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/main.src rename to src/cmd/compile/internal/types2/testdata/check/main0.go diff --git a/src/cmd/compile/internal/types2/testdata/check/main.go2 b/src/cmd/compile/internal/types2/testdata/check/main1.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/main.go2 rename to src/cmd/compile/internal/types2/testdata/check/main1.go diff --git a/src/cmd/compile/internal/types2/testdata/check/map.go2 b/src/cmd/compile/internal/types2/testdata/check/map0.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/map.go2 rename to src/cmd/compile/internal/types2/testdata/check/map0.go diff --git a/src/cmd/compile/internal/types2/testdata/check/map2.go2 b/src/cmd/compile/internal/types2/testdata/check/map1.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/map2.go2 rename to src/cmd/compile/internal/types2/testdata/check/map1.go diff --git a/src/cmd/compile/internal/types2/testdata/check/methodsets.src b/src/cmd/compile/internal/types2/testdata/check/methodsets.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/methodsets.src rename to src/cmd/compile/internal/types2/testdata/check/methodsets.go diff --git a/src/cmd/compile/internal/types2/testdata/check/mtypeparams.go2 b/src/cmd/compile/internal/types2/testdata/check/mtypeparams.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/mtypeparams.go2 rename to src/cmd/compile/internal/types2/testdata/check/mtypeparams.go diff --git a/src/cmd/compile/internal/types2/testdata/check/shifts.src b/src/cmd/compile/internal/types2/testdata/check/shifts.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/shifts.src rename to src/cmd/compile/internal/types2/testdata/check/shifts.go diff --git a/src/cmd/compile/internal/types2/testdata/check/slices.go2 b/src/cmd/compile/internal/types2/testdata/check/slices.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/slices.go2 rename to src/cmd/compile/internal/types2/testdata/check/slices.go diff --git a/src/cmd/compile/internal/types2/testdata/check/stmt0.src b/src/cmd/compile/internal/types2/testdata/check/stmt0.go similarity index 99% rename from src/cmd/compile/internal/types2/testdata/check/stmt0.src rename to src/cmd/compile/internal/types2/testdata/check/stmt0.go index 90ef09511f..e5b6f5dff7 100644 --- a/src/cmd/compile/internal/types2/testdata/check/stmt0.src +++ b/src/cmd/compile/internal/types2/testdata/check/stmt0.go @@ -542,7 +542,7 @@ func switches1() { var y interface{} switch y.(type) { case int: - fallthrough /* ERROR "fallthrough statement out of place" */ ; ; ; + fallthrough /* ERROR "cannot fallthrough in type switch" */ ; ; ; default: } diff --git a/src/cmd/compile/internal/types2/testdata/check/stmt1.src b/src/cmd/compile/internal/types2/testdata/check/stmt1.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/stmt1.src rename to src/cmd/compile/internal/types2/testdata/check/stmt1.go diff --git a/src/go/types/testdata/check/typeinference.go2 b/src/cmd/compile/internal/types2/testdata/check/typeinference.go similarity index 55% rename from src/go/types/testdata/check/typeinference.go2 rename to src/cmd/compile/internal/types2/testdata/check/typeinference.go index 3d3380da9c..28f3e286b7 100644 --- a/src/go/types/testdata/check/typeinference.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeinference.go @@ -4,22 +4,24 @@ package typeInference +// As of issue #51527, type-type inference has been disabled. + // basic inference type Tb[P ~*Q, Q any] int func _() { - var x Tb[*int] + var x Tb /* ERROR got 1 arguments */ [*int] var y Tb[*int, int] - x = y + x = y /* ERROR cannot use y .* in assignment */ _ = x } // recursive inference type Tr[A any, B *C, C *D, D *A] int func _() { - var x Tr[string] + var x Tr /* ERROR got 1 arguments */ [string] var y Tr[string, ***string, **string, *string] var z Tr[int, ***int, **int, *int] - x = y + x = y /* ERROR cannot use y .* in assignment */ x = z // ERROR cannot use z .* as Tr _ = x } @@ -31,17 +33,17 @@ type To2[A any, B [][]A] int type To3[A any, B [3]*A] int type To4[A any, B any, C struct{a A; b B}] int func _() { - var _ To0[int] - var _ To1[int] - var _ To2[int] - var _ To3[int] - var _ To4[int, string] + var _ To0 /* ERROR got 1 arguments */ [int] + var _ To1 /* ERROR got 1 arguments */ [int] + var _ To2 /* ERROR got 1 arguments */ [int] + var _ To3 /* ERROR got 1 arguments */ [int] + var _ To4 /* ERROR got 2 arguments */ [int, string] } // failed inference type Tf0[A, B any] int type Tf1[A any, B ~struct{a A; c C}, C any] int func _() { - var _ Tf0 /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [int] - var _ Tf1 /* ERROR cannot infer B */ /* ERROR got 1 arguments but 3 type parameters */ [int] + var _ Tf0 /* ERROR got 1 arguments but 2 type parameters */ [int] + var _ Tf1 /* ERROR got 1 arguments but 3 type parameters */ [int] } diff --git a/src/cmd/compile/internal/types2/testdata/check/typeinst.go2 b/src/cmd/compile/internal/types2/testdata/check/typeinst0.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/typeinst.go2 rename to src/cmd/compile/internal/types2/testdata/check/typeinst0.go diff --git a/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 b/src/cmd/compile/internal/types2/testdata/check/typeinst1.go similarity index 95% rename from src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 rename to src/cmd/compile/internal/types2/testdata/check/typeinst1.go index 4aaefb3424..eb0708fea1 100644 --- a/src/cmd/compile/internal/types2/testdata/check/typeinst2.go2 +++ b/src/cmd/compile/internal/types2/testdata/check/typeinst1.go @@ -173,7 +173,9 @@ type _ interface { } // Interface term lists can contain any type, incl. *Named types. -// Verify that we use the underlying type to compute the operational type. +// Verify that we use the underlying type(s) of the type(s) in the +// term list when determining if an operation is permitted. + type MyInt int func add1[T interface{MyInt}](x T) T { return x + 1 @@ -271,10 +273,10 @@ func gg[T any]() {} func hh[T ~int]() {} func _[T none]() { - _ = ff[int /* ERROR cannot implement none \(empty type set\) */ ] - _ = ff[T] // pathological but ok because T's type set is empty, too - _ = gg[int] - _ = gg[T] + _ = ff[int /* ERROR cannot implement none \(empty type set\) */ ] + _ = ff[T] // pathological but ok because T's type set is empty, too + _ = gg[int] + _ = gg[T] _ = hh[int] _ = hh[T] } diff --git a/src/cmd/compile/internal/types2/testdata/check/typeinstcycles.go2 b/src/cmd/compile/internal/types2/testdata/check/typeinstcycles.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/typeinstcycles.go2 rename to src/cmd/compile/internal/types2/testdata/check/typeinstcycles.go diff --git a/src/cmd/compile/internal/types2/testdata/check/typeparams.go2 b/src/cmd/compile/internal/types2/testdata/check/typeparams.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/typeparams.go2 rename to src/cmd/compile/internal/types2/testdata/check/typeparams.go diff --git a/src/cmd/compile/internal/types2/testdata/check/unions.go2 b/src/cmd/compile/internal/types2/testdata/check/unions.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/unions.go2 rename to src/cmd/compile/internal/types2/testdata/check/unions.go diff --git a/src/cmd/compile/internal/types2/testdata/check/vardecl.src b/src/cmd/compile/internal/types2/testdata/check/vardecl.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/check/vardecl.src rename to src/cmd/compile/internal/types2/testdata/check/vardecl.go diff --git a/src/cmd/compile/internal/types2/testdata/examples/constraints.go2 b/src/cmd/compile/internal/types2/testdata/examples/constraints.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/examples/constraints.go2 rename to src/cmd/compile/internal/types2/testdata/examples/constraints.go diff --git a/src/cmd/compile/internal/types2/testdata/examples/functions.go2 b/src/cmd/compile/internal/types2/testdata/examples/functions.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/examples/functions.go2 rename to src/cmd/compile/internal/types2/testdata/examples/functions.go diff --git a/src/cmd/compile/internal/types2/testdata/examples/inference.go2 b/src/cmd/compile/internal/types2/testdata/examples/inference.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/examples/inference.go2 rename to src/cmd/compile/internal/types2/testdata/examples/inference.go diff --git a/src/cmd/compile/internal/types2/testdata/examples/methods.go2 b/src/cmd/compile/internal/types2/testdata/examples/methods.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/examples/methods.go2 rename to src/cmd/compile/internal/types2/testdata/examples/methods.go diff --git a/src/cmd/compile/internal/types2/testdata/examples/operations.go2 b/src/cmd/compile/internal/types2/testdata/examples/operations.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/examples/operations.go2 rename to src/cmd/compile/internal/types2/testdata/examples/operations.go diff --git a/src/cmd/compile/internal/types2/testdata/examples/types.go2 b/src/cmd/compile/internal/types2/testdata/examples/types.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/examples/types.go2 rename to src/cmd/compile/internal/types2/testdata/examples/types.go diff --git a/src/cmd/compile/internal/types2/testdata/examples/typesets.go2 b/src/cmd/compile/internal/types2/testdata/examples/typesets.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/examples/typesets.go2 rename to src/cmd/compile/internal/types2/testdata/examples/typesets.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue20583.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue20583.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue20583.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue20583.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue23203a.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue23203a.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue23203a.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue23203a.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue23203b.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue23203b.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue23203b.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue23203b.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue26390.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue26390.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue26390.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue26390.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue28251.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue28251.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue28251.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue28251.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue39634.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39664.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39664.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue39664.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue39664.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39680.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39680.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue39680.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue39680.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39693.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39693.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue39693.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue39693.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39699.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39699.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue39699.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue39699.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39711.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39711.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue39711.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue39711.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue39723.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39725.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39725.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue39725.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue39725.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39754.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39754.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue39754.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue39754.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39755.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39755.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue39755.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue39755.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39768.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39768.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue39768.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue39768.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39938.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39938.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue39938.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue39938.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue39948.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39976.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39976.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue39976.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue39976.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39982.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue39982.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue39982.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue39982.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40038.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40038.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue40038.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue40038.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40056.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40056.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue40056.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue40056.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40057.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40057.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue40057.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue40057.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40301.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40301.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue40301.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue40301.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40684.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40684.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue40684.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue40684.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40789.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue40789.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue40789.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue40789.go diff --git a/src/go/types/testdata/fixedbugs/issue41124.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go similarity index 86% rename from src/go/types/testdata/fixedbugs/issue41124.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go index 7f55ba85a6..4550dd732c 100644 --- a/src/go/types/testdata/fixedbugs/issue41124.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue41124.go @@ -47,7 +47,7 @@ type _ struct{ } type _ struct{ - I3 // ERROR interface is .* comparable + I3 // ERROR interface contains type constraints } // General composite types. @@ -59,19 +59,19 @@ type ( _ []I1 // ERROR interface is .* comparable _ []I2 // ERROR interface contains type constraints - _ *I3 // ERROR interface is .* comparable + _ *I3 // ERROR interface contains type constraints _ map[I1 /* ERROR interface is .* comparable */ ]I2 // ERROR interface contains type constraints - _ chan I3 // ERROR interface is .* comparable + _ chan I3 // ERROR interface contains type constraints _ func(I1 /* ERROR interface is .* comparable */ ) _ func() I2 // ERROR interface contains type constraints ) // Other cases. -var _ = [...]I3 /* ERROR interface is .* comparable */ {} +var _ = [...]I3 /* ERROR interface contains type constraints */ {} func _(x interface{}) { - _ = x.(I3 /* ERROR interface is .* comparable */ ) + _ = x.(I3 /* ERROR interface contains type constraints */ ) } type T1[_ any] struct{} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue42695.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue42695.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue42695.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue42695.go diff --git a/src/go/types/testdata/fixedbugs/issue42758.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue42758.go similarity index 89% rename from src/go/types/testdata/fixedbugs/issue42758.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue42758.go index dd66e9648b..6d75b106d4 100644 --- a/src/go/types/testdata/fixedbugs/issue42758.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue42758.go @@ -22,7 +22,7 @@ type constraint interface { func _[T constraint](x interface{}){ switch x.(type) { - case T: // ok to use a type parameter even if type list contains int + case T: // ok to use a type parameter even if type set contains int case int: } } diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue42987.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue42987.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue42987.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue42987.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43056.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43056.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue43056.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue43056.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43087.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43087.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue43087.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue43087.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43110.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43110.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue43110.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue43110.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43124.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43124.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue43124.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue43124.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43125.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43125.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue43125.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue43125.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43190.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43190.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue43190.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue43190.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43527.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43527.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue43527.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue43527.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43671.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue43671.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue43671.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue43671.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue44688.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue44688.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue44688.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue44688.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue44799.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue44799.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue44799.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue44799.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45548.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45548.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue45548.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue45548.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45550.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45550.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue45550.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue45550.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45635.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45635.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue45635.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue45635.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45639.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45639.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue45639.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue45639.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45920.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45920.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue45920.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue45920.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45985.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue45985.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue45985.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue45985.go diff --git a/src/go/types/testdata/fixedbugs/issue46090.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46090.go similarity index 90% rename from src/go/types/testdata/fixedbugs/issue46090.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue46090.go index 81b31974c8..0fb92a3657 100644 --- a/src/go/types/testdata/fixedbugs/issue46090.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46090.go @@ -1,9 +1,11 @@ +// -lang=go1.17 + // Copyright 2020 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. // The predeclared type comparable is not visible before Go 1.18. -package go1_17 +package p type _ comparable // ERROR undeclared diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46275.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46275.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue46275.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue46275.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46461.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46461.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue46461.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue46461.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46583.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue46583.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue46583.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue46583.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47031.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47031.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue47031.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue47031.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47115.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47115.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue47115.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue47115.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue47127.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47411.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47411.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue47411.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue47411.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47747.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47747.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue47747.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue47747.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47796.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47796.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue47796.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue47796.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47818.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47818.go similarity index 91% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue47818.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue47818.go index 546de1ce31..58a62092b7 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47818.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47818.go @@ -1,3 +1,5 @@ +// -lang=go1.17 + // Copyright 2021 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. @@ -6,15 +8,15 @@ // needs to report any operations that are not permitted // before Go 1.18. -package go1_17 +package p -type T[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ] struct{} +type T[P /* ERROR type parameter requires go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ] struct{} // for init (and main, but we're not in package main) we should only get one error func init[P /* ERROR func init must have no type parameters */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {} -func main[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {} +func main[P /* ERROR type parameter requires go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ]() {} -func f[P /* ERROR type parameters require go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ](x P) { +func f[P /* ERROR type parameter requires go1\.18 or later */ any /* ERROR undeclared name: any \(requires version go1\.18 or later\) */ ](x P) { var _ T[ /* ERROR type instantiation requires go1\.18 or later */ int] var _ (T[ /* ERROR type instantiation requires go1\.18 or later */ int]) _ = T[ /* ERROR type instantiation requires go1\.18 or later */ int]{} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47887.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47887.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue47887.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue47887.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue47968.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue47996.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48008.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48008.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48008.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48008.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48018.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48018.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48018.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48018.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48048.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48048.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48048.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48048.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48082.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48082.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48082.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48082.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48083.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48083.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48083.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48083.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48136.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48136.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48136.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48136.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48234.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48234.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48234.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48234.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48312.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48312.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48312.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48312.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48472.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48472.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48472.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48472.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48529.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48529.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48529.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48529.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48582.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48582.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48582.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48582.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48619.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48619.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48619.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48619.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48656.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48656.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48656.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48656.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48695.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48695.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48695.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48695.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48703.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48703.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48703.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48703.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48712.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48712.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48712.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48712.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48819.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48819.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48819.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48819.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48951.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48951.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48951.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48951.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48962.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48962.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48962.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48962.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48974.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue48974.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue48974.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue48974.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49043.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49043.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue49043.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49043.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49112.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49112.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue49112.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49112.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49179.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49179.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue49179.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49179.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49242.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49242.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue49242.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49242.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49247.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49247.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue49247.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49247.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49296.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49296.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue49296.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49296.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49439.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49439.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue49439.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49439.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49482.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49482.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue49482.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49482.go diff --git a/src/go/types/testdata/fixedbugs/issue49541.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49541.go similarity index 65% rename from src/go/types/testdata/fixedbugs/issue49541.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49541.go index b7bf12a186..c8499c1b61 100644 --- a/src/go/types/testdata/fixedbugs/issue49541.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49541.go @@ -10,9 +10,10 @@ type S[A, B any] struct { func (S[A, B]) m() {} -// TODO(gri) We should only report one error below. See issue #50588. +// TODO(gri): with type-type inference enabled we should only report one error +// below. See issue #50588. -func _[A any](s S /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [A]) { +func _[A any](s S /* ERROR got 1 arguments but 2 type parameters */ [A]) { // we should see no follow-on errors below s.f = 1 s.m() @@ -21,7 +22,7 @@ func _[A any](s S /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type // another test case from the issue func _() { - X(Interface[*F /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [string]](Impl{})) + X(Interface[*F /* ERROR got 1 arguments but 2 type parameters */ [string]](Impl{})) } func X[Q Qer](fs Interface[Q]) { diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49579.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49579.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue49579.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49579.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49592.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49592.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue49592.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49592.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49602.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49602.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue49602.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49602.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49705.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49705.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue49705.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49705.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49735.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49735.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue49735.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49735.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49739.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49739.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue49739.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49739.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49864.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue49864.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue49864.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue49864.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50259.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50259.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue50259.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50259.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50276.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50276.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue50276.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50276.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50281.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50281.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue50281.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50281.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50321.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50321.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue50321.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50321.go diff --git a/src/go/types/testdata/fixedbugs/issue50417.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50417.go similarity index 60% rename from src/go/types/testdata/fixedbugs/issue50417.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50417.go index 50487fa2ff..2caef1b986 100644 --- a/src/go/types/testdata/fixedbugs/issue50417.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50417.go @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Field accesses through type parameters are disabled +// until we have a more thorough understanding of the +// implications on the spec. See issue #51576. + package p type Sf struct { @@ -9,13 +13,13 @@ type Sf struct { } func f0[P Sf](p P) { - _ = p.f - p.f = 0 + _ = p.f // ERROR p\.f undefined + p.f /* ERROR p\.f undefined */ = 0 } func f0t[P ~struct{f int}](p P) { - _ = p.f - p.f = 0 + _ = p.f // ERROR p\.f undefined + p.f /* ERROR p\.f undefined */ = 0 } var _ = f0[Sf] @@ -25,8 +29,8 @@ var _ = f0[Sm /* ERROR does not implement */ ] var _ = f0t[Sm /* ERROR does not implement */ ] func f1[P interface{ Sf; m() }](p P) { - _ = p.f - p.f = 0 + _ = p.f // ERROR p\.f undefined + p.f /* ERROR p\.f undefined */ = 0 p.m() } @@ -44,8 +48,8 @@ type Sfm struct { func (Sfm) m() {} func f2[P interface{ Sfm; m() }](p P) { - _ = p.f - p.f = 0 + _ = p.f // ERROR p\.f undefined + p.f /* ERROR p\.f undefined */ = 0 p.m() } @@ -56,8 +60,8 @@ var _ = f2[Sfm] type PSfm *Sfm func f3[P interface{ PSfm }](p P) { - _ = p.f - p.f = 0 + _ = p.f // ERROR p\.f undefined + p.f /* ERROR p\.f undefined */ = 0 p.m /* ERROR type P has no field or method m */ () } diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50426.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50426.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue50426.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50426.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50450.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50450.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue50450.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50450.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50516.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50516.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue50516.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50516.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50646.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50646.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue50646.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50646.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50755.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50755.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue50755.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50755.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50779.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50779.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue50779.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50779.go diff --git a/src/go/types/testdata/fixedbugs/issue50782.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50782.go similarity index 72% rename from src/go/types/testdata/fixedbugs/issue50782.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50782.go index 8f41b84163..fd1ab11b8c 100644 --- a/src/go/types/testdata/fixedbugs/issue50782.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50782.go @@ -2,6 +2,10 @@ // Use of this source code is governed by a BSD-style // license that can be found in the LICENSE file. +// Field accesses through type parameters are disabled +// until we have a more thorough understanding of the +// implications on the spec. See issue #51576. + package p // The first example from the issue. @@ -18,9 +22,12 @@ type numericAbs[T Numeric] interface { // AbsDifference computes the absolute value of the difference of // a and b, where the absolute value is determined by the Abs method. func absDifference[T numericAbs[T /* ERROR T does not implement Numeric */]](a, b T) T { - // TODO: the error below should probably be positioned on the '-'. - d := a /* ERROR "invalid operation: operator - not defined" */ .Value - b.Value - return d.Abs() + // Field accesses are not permitted for now. Keep an error so + // we can find and fix this code once the situation changes. + return a.Value // ERROR a\.Value undefined + // TODO: The error below should probably be positioned on the '-'. + // d := a /* ERROR "invalid operation: operator - not defined" */ .Value - b.Value + // return d.Abs() } // The second example from the issue. diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50816.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50816.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue50816.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50816.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50833.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50833.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue50833.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50833.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50912.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50912.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue50912.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50912.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50929.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50929.go similarity index 77% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue50929.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue50929.go index 941dbaa3c1..3629ecf104 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50929.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue50929.go @@ -16,7 +16,7 @@ func G[A, B any](F[A, B]) { func _() { // TODO(gri) only report one error below (issue #50932) - var x F /* ERROR cannot infer B */ /* ERROR got 1 arguments but 2 type parameters */ [int] + var x F /* ERROR got 1 arguments but 2 type parameters */ [int] G(x /* ERROR does not match */) } @@ -46,9 +46,9 @@ func NSG[G any](c RSC[G]) { fmt.Println(c) } -func MMD[Rc RC /* ERROR cannot infer RG */ /* ERROR got 1 arguments */ [RG], RG any, G any]() M /* ERROR got 2 arguments */ /* ERROR Rc does not match */ [Rc, RG] { +func MMD[Rc RC /* ERROR got 1 arguments */ [RG], RG any, G any]() M /* ERROR got 2 arguments */ [Rc, RG] { - var nFn NFn /* ERROR got 2 arguments */ /* ERROR Rc does not match */ [Rc, RG] + var nFn NFn /* ERROR got 2 arguments */ [Rc, RG] var empty Rc switch any(empty).(type) { diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51048.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51048.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue51048.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue51048.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51158.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51158.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue51158.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue51158.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51229.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51229.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue51229.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue51229.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51232.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51232.go new file mode 100644 index 0000000000..3fa6a05732 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51232.go @@ -0,0 +1,30 @@ +// Copyright 2022 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 p + +type RC[RG any] interface { + ~[]RG +} + +type Fn[RCT RC[RG], RG any] func(RCT) + +type F[RCT RC[RG], RG any] interface { + Fn() Fn /* ERROR got 1 arguments */ [RCT] +} + +type concreteF[RCT RC[RG], RG any] struct { + makeFn func() Fn /* ERROR got 1 arguments */ [RCT] +} + +func (c *concreteF[RCT, RG]) Fn() Fn /* ERROR got 1 arguments */ [RCT] { + return c.makeFn() +} + +func NewConcrete[RCT RC[RG], RG any](Rc RCT) F /* ERROR got 1 arguments */ [RCT] { + // TODO(rfindley): eliminate the duplicate error below. + return & /* ERROR cannot use .* as F\[RCT\] */ concreteF /* ERROR got 1 arguments */ [RCT]{ + makeFn: nil, + } +} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51232.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51233.go similarity index 54% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue51232.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue51233.go index 6e575a376d..9c15028c91 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51232.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51233.go @@ -4,26 +4,24 @@ package p +// As of issue #51527, type-type inference has been disabled. + type RC[RG any] interface { ~[]RG } type Fn[RCT RC[RG], RG any] func(RCT) +type FFn[RCT RC[RG], RG any] func() Fn /* ERROR got 1 arguments */ [RCT] + type F[RCT RC[RG], RG any] interface { - Fn() Fn[RCT] + Fn() Fn /* ERROR got 1 arguments */ [RCT] } type concreteF[RCT RC[RG], RG any] struct { - makeFn func() Fn[RCT] + makeFn FFn /* ERROR got 1 arguments */ [RCT] } -func (c *concreteF[RCT, RG]) Fn() Fn[RCT] { +func (c *concreteF[RCT, RG]) Fn() Fn /* ERROR got 1 arguments */ [RCT] { return c.makeFn() } - -func NewConcrete[RCT RC[RG], RG any](Rc RCT) F[RCT] { - return &concreteF[RCT]{ - makeFn: nil, - } -} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51257.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51257.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue51257.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue51257.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51335.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51335.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue51335.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue51335.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go similarity index 81% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go index 40706ec493..84e551d9ad 100644 --- a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go2 +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51339.go @@ -10,7 +10,9 @@ package p type T[P any, B *P] struct{} func (T /* ERROR cannot use generic type */ ) m0() {} -func (T /* ERROR got 1 type parameter, but receiver base type declares 2 */ [_]) m1() {} + +// TODO(rfindley): eliminate the duplicate errors here. +func (T /* ERROR got 1 type parameter, but receiver base type declares 2 */ /* ERROR got 1 arguments but 2 type parameters */ [_]) m1() {} func (T[_, _]) m2() {} // TODO(gri) this error is unfortunate (issue #51343) func (T /* ERROR got 3 arguments but 2 type parameters */ [_, _, _]) m3() {} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51376.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51376.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue51376.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue51376.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51386.go2 b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51386.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue51386.go2 rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue51386.go diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51472.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51472.go new file mode 100644 index 0000000000..f19d906d97 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51472.go @@ -0,0 +1,54 @@ +// Copyright 2022 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 p + +func _[T comparable](x T) { + _ = x == x +} + +func _[T interface{interface{comparable}}](x T) { + _ = x == x +} + +func _[T interface{comparable; interface{comparable}}](x T) { + _ = x == x +} + +func _[T interface{comparable; ~int}](x T) { + _ = x == x +} + +func _[T interface{comparable; ~[]byte}](x T) { + _ = x /* ERROR cannot compare */ == x +} + +// TODO(gri) The error message here should be better. See issue #51525. +func _[T interface{comparable; ~int; ~string}](x T) { + _ = x /* ERROR cannot compare */ == x +} + +// TODO(gri) The error message here should be better. See issue #51525. +func _[T interface{~int; ~string}](x T) { + _ = x /* ERROR cannot compare */ == x +} + +func _[T interface{comparable; interface{~int}; interface{int|float64}}](x T) { + _ = x == x +} + +func _[T interface{interface{comparable; ~int}; interface{~float64; comparable; m()}}](x T) { + _ = x /* ERROR cannot compare */ == x +} + +// test case from issue + +func f[T interface{comparable; []byte|string}](x T) { + _ = x == x +} + +func _(s []byte) { + f( /* ERROR \[\]byte does not implement interface{comparable; \[\]byte\|string} */ s) + _ = f[[ /* ERROR does not implement */ ]byte] +} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51509.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51509.go new file mode 100644 index 0000000000..5ae47176d0 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51509.go @@ -0,0 +1,7 @@ +// Copyright 2022 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 p + +type T /* ERROR illegal cycle */ T.x diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51533.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51533.go new file mode 100644 index 0000000000..bf46f755f9 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51533.go @@ -0,0 +1,20 @@ +// Copyright 2022 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 p + +func _(x any) { + switch x { + case 0: + fallthrough // ERROR fallthrough statement out of place + _ = x + default: + } + + switch x.(type) { + case int: + fallthrough // ERROR cannot fallthrough in type switch + default: + } +} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51578.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51578.go new file mode 100644 index 0000000000..5c204bae20 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51578.go @@ -0,0 +1,17 @@ +// Copyright 2022 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 p + +var _ = (*interface /* ERROR interface contains type constraints */ {int})(nil) + +// abbreviated test case from issue + +type TypeSet interface{ int | string } + +func _() { + f((*TypeSet /* ERROR interface contains type constraints */)(nil)) +} + +func f(any) {} \ No newline at end of file diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51593.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51593.go new file mode 100644 index 0000000000..d323618ee8 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51593.go @@ -0,0 +1,13 @@ +// Copyright 2022 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 p + +func f[P interface{ m(R) }, R any]() {} + +type T = interface { m(int) } + +func _() { + _ = f[ /* ERROR cannot infer R */ T] // don't crash in type inference +} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51616.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51616.go new file mode 100644 index 0000000000..e0efc9e620 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51616.go @@ -0,0 +1,19 @@ +// Copyright 2022 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 p + +type ( + C[T any] interface{~int; M() T} + + _ C[bool] + _ comparable + _ interface {~[]byte | ~string} + + // Alias type declarations may refer to "constraint" types + // like ordinary type declarations. + _ = C[bool] + _ = comparable + _ = interface {~[]byte | ~string} +) diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51658.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51658.go new file mode 100644 index 0000000000..c437c92d29 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51658.go @@ -0,0 +1,39 @@ +// Copyright 2022 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 p + +type F { // ERROR syntax error + float64 +} // ERROR syntax error + +func _[T F | int](x T) { + _ = x == 0 // don't crash when recording type of 0 +} + +// test case from issue + +type FloatType { // ERROR syntax error + float32 | float64 +} // ERROR syntax error + +type IntegerType interface { + int8 | int16 | int32 | int64 | int | + uint8 | uint16 | uint32 | uint64 | uint +} + +type ComplexType interface { + complex64 | complex128 +} + +type Number interface { + FloatType | IntegerType | ComplexType +} + +func GetDefaultNumber[T Number](value, defaultValue T) T { + if value == 0 { + return defaultValue + } + return value +} diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51877.go b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51877.go new file mode 100644 index 0000000000..06f054b257 --- /dev/null +++ b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue51877.go @@ -0,0 +1,18 @@ +// Copyright 2013 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 p + +type S struct { + f1 int + f2 bool +} + +var ( + _ = S{0} /* ERROR too few values in S{…} */ + _ = struct{ f1, f2 int }{0} /* ERROR too few values in struct{f1 int; f2 int}{…} */ + + _ = S{0, true, "foo" /* ERROR too many values in S{…} */} + _ = struct{ f1, f2 int }{0, 1, 2 /* ERROR too many values in struct{f1 int; f2 int}{…} */} +) diff --git a/src/cmd/compile/internal/types2/testdata/fixedbugs/issue6977.src b/src/cmd/compile/internal/types2/testdata/fixedbugs/issue6977.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/fixedbugs/issue6977.src rename to src/cmd/compile/internal/types2/testdata/fixedbugs/issue6977.go diff --git a/src/cmd/compile/internal/types2/testdata/manual.go2 b/src/cmd/compile/internal/types2/testdata/manual.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/manual.go2 rename to src/cmd/compile/internal/types2/testdata/manual.go diff --git a/src/cmd/compile/internal/types2/testdata/spec/assignability.go2 b/src/cmd/compile/internal/types2/testdata/spec/assignability.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/spec/assignability.go2 rename to src/cmd/compile/internal/types2/testdata/spec/assignability.go diff --git a/src/cmd/compile/internal/types2/testdata/spec/comparisons.go2 b/src/cmd/compile/internal/types2/testdata/spec/comparisons.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/spec/comparisons.go2 rename to src/cmd/compile/internal/types2/testdata/spec/comparisons.go diff --git a/src/cmd/compile/internal/types2/testdata/spec/conversions.go2 b/src/cmd/compile/internal/types2/testdata/spec/conversions.go similarity index 100% rename from src/cmd/compile/internal/types2/testdata/spec/conversions.go2 rename to src/cmd/compile/internal/types2/testdata/spec/conversions.go diff --git a/src/cmd/compile/internal/types2/typeparam.go b/src/cmd/compile/internal/types2/typeparam.go index 9ed3369ff4..2e9a2adae6 100644 --- a/src/cmd/compile/internal/types2/typeparam.go +++ b/src/cmd/compile/internal/types2/typeparam.go @@ -31,7 +31,8 @@ func (t *TypeParam) Obj() *TypeName { return t.obj } // or Signature type by calling SetTypeParams. Setting a type parameter on more // than one type will result in a panic. // -// The constraint argument can be nil, and set later via SetConstraint. +// The constraint argument can be nil, and set later via SetConstraint. If the +// constraint is non-nil, it must be fully defined. func NewTypeParam(obj *TypeName, constraint Type) *TypeParam { return (*Checker)(nil).newTypeParam(obj, constraint) } @@ -71,8 +72,10 @@ func (t *TypeParam) Constraint() Type { // SetConstraint sets the type constraint for t. // -// SetConstraint should not be called concurrently, but once SetConstraint -// returns the receiver t is safe for concurrent use. +// It must be called by users of NewTypeParam after the bound's underlying is +// fully defined, and before using the type parameter in any way other than to +// form other types. Once SetConstraint returns the receiver, t is safe for +// concurrent use. func (t *TypeParam) SetConstraint(bound Type) { if bound == nil { panic("nil constraint") diff --git a/src/cmd/compile/internal/types2/typeset.go b/src/cmd/compile/internal/types2/typeset.go index 65ae04819e..328c5029e7 100644 --- a/src/cmd/compile/internal/types2/typeset.go +++ b/src/cmd/compile/internal/types2/typeset.go @@ -15,20 +15,25 @@ import ( // API // A _TypeSet represents the type set of an interface. +// Because of existing language restrictions, methods can be "factored out" +// from the terms. The actual type set is the intersection of the type set +// implied by the methods and the type set described by the terms and the +// comparable bit. To test whether a type is included in a type set +// ("implements" relation), the type must implement all methods _and_ be +// an element of the type set described by the terms and the comparable bit. +// If the term list describes the set of all types and comparable is true, +// only comparable types are meant; in all other cases comparable is false. type _TypeSet struct { - comparable bool // if set, the interface is or embeds comparable - // TODO(gri) consider using a set for the methods for faster lookup - methods []*Func // all methods of the interface; sorted by unique ID - terms termlist // type terms of the type set + methods []*Func // all methods of the interface; sorted by unique ID + terms termlist // type terms of the type set + comparable bool // invariant: !comparable || terms.isAll() } // IsEmpty reports whether type set s is the empty set. func (s *_TypeSet) IsEmpty() bool { return s.terms.isEmpty() } // IsAll reports whether type set s is the set of all types (corresponding to the empty interface). -func (s *_TypeSet) IsAll() bool { - return !s.comparable && len(s.methods) == 0 && s.terms.isAll() -} +func (s *_TypeSet) IsAll() bool { return s.IsMethodSet() && len(s.methods) == 0 } // IsMethodSet reports whether the interface t is fully described by its method set. func (s *_TypeSet) IsMethodSet() bool { return !s.comparable && s.terms.isAll() } @@ -43,13 +48,6 @@ func (s *_TypeSet) IsComparable(seen map[Type]bool) bool { }) } -// TODO(gri) IsTypeSet is not a great name for this predicate. Find a better one. - -// IsTypeSet reports whether the type set s is represented by a finite set of underlying types. -func (s *_TypeSet) IsTypeSet() bool { - return !s.comparable && len(s.methods) == 0 -} - // NumMethods returns the number of methods available. func (s *_TypeSet) NumMethods() int { return len(s.methods) } @@ -175,7 +173,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_ pos = ityp.methods[0].pos } - check.trace(pos, "type set for %s", ityp) + check.trace(pos, "-- type set for %s", ityp) check.indent++ defer func() { check.indent-- @@ -215,12 +213,12 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_ var todo []*Func var seen objset - var methods []*Func + var allMethods []*Func mpos := make(map[*Func]syntax.Pos) // method specification or method embedding position, for good error messages addMethod := func(pos syntax.Pos, m *Func, explicit bool) { switch other := seen.insert(m); { case other == nil: - methods = append(methods, m) + allMethods = append(allMethods, m) mpos[m] = pos case explicit: if check == nil { @@ -250,7 +248,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_ err.errorf(mpos[other.(*Func)], "other declaration of %s", m.name) check.report(&err) } - }) + }).describef(pos, "duplicate method check for %s", m.name) } } @@ -259,7 +257,8 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_ } // collect embedded elements - var allTerms = allTermlist + allTerms := allTermlist + allComparable := false for i, typ := range ityp.embeddeds { // The embedding position is nil for imported interfaces // and also for interface copies after substitution (but @@ -268,6 +267,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_ if ityp.embedPos != nil { pos = (*ityp.embedPos)[i] } + var comparable bool var terms termlist switch u := under(typ).(type) { case *Interface: @@ -279,9 +279,7 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_ check.versionErrorf(pos, "go1.18", "embedding constraint interface %s", typ) continue } - if tset.comparable { - ityp.tset.comparable = true - } + comparable = tset.comparable for _, m := range tset.methods { addMethod(pos, m, false) // use embedding position pos rather than m.pos } @@ -295,6 +293,8 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_ if tset == &invalidTypeSet { continue // ignore invalid unions } + assert(!tset.comparable) + assert(len(tset.methods) == 0) terms = tset.terms default: if u == Typ[Invalid] { @@ -306,11 +306,11 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_ } terms = termlist{{false, typ}} } - // The type set of an interface is the intersection - // of the type sets of all its elements. - // Intersection cannot produce longer termlists and - // thus cannot overflow. - allTerms = allTerms.intersect(terms) + + // The type set of an interface is the intersection of the type sets of all its elements. + // Due to language restrictions, only embedded interfaces can add methods, they are handled + // separately. Here we only need to intersect the term lists and comparable bits. + allTerms, allComparable = intersectTermLists(allTerms, allComparable, terms, comparable) } ityp.embedPos = nil // not needed anymore (errors have been reported) @@ -323,15 +323,46 @@ func computeInterfaceTypeSet(check *Checker, pos syntax.Pos, ityp *Interface) *_ } } - if methods != nil { - sortMethods(methods) - ityp.tset.methods = methods + ityp.tset.comparable = allComparable + if len(allMethods) != 0 { + sortMethods(allMethods) + ityp.tset.methods = allMethods } ityp.tset.terms = allTerms return ityp.tset } +// TODO(gri) The intersectTermLists function belongs to the termlist implementation. +// The comparable type set may also be best represented as a term (using +// a special type). + +// intersectTermLists computes the intersection of two term lists and respective comparable bits. +// xcomp, ycomp are valid only if xterms.isAll() and yterms.isAll() respectively. +func intersectTermLists(xterms termlist, xcomp bool, yterms termlist, ycomp bool) (termlist, bool) { + terms := xterms.intersect(yterms) + // If one of xterms or yterms is marked as comparable, + // the result must only include comparable types. + comp := xcomp || ycomp + if comp && !terms.isAll() { + // only keep comparable terms + i := 0 + for _, t := range terms { + assert(t.typ != nil) + if Comparable(t.typ) { + terms[i] = t + i++ + } + } + terms = terms[:i] + if !terms.isAll() { + comp = false + } + } + assert(!comp || terms.isAll()) // comparable invariant + return terms, comp +} + func sortMethods(list []*Func) { sort.Sort(byUniqueMethodName(list)) } @@ -375,7 +406,7 @@ func computeUnionTypeSet(check *Checker, unionSets map[*Union]*_TypeSet, pos syn // For now we don't permit type parameters as constraints. assert(!isTypeParam(t.typ)) terms = computeInterfaceTypeSet(check, pos, ui).terms - } else if t.typ == Typ[Invalid] { + } else if u == Typ[Invalid] { continue } else { if t.tilde && !Identical(t.typ, u) { diff --git a/src/cmd/compile/internal/types2/typeset_test.go b/src/cmd/compile/internal/types2/typeset_test.go index 7f7cc06db9..68e5d8ad62 100644 --- a/src/cmd/compile/internal/types2/typeset_test.go +++ b/src/cmd/compile/internal/types2/typeset_test.go @@ -25,9 +25,9 @@ func TestTypeSetString(t *testing.T) { "{int; string}": "∅", "{comparable}": "{comparable}", - "{comparable; int}": "{comparable; int}", - "{~int; comparable}": "{comparable; ~int}", - "{int|string; comparable}": "{comparable; int ∪ string}", + "{comparable; int}": "{int}", + "{~int; comparable}": "{~int}", + "{int|string; comparable}": "{int ∪ string}", "{comparable; int; string}": "∅", "{m()}": "{func (p.T).m()}", @@ -37,8 +37,8 @@ func TestTypeSetString(t *testing.T) { "{m1(); comparable; m2() int }": "{comparable; func (p.T).m1(); func (p.T).m2() int}", "{comparable; error}": "{comparable; func (error).Error() string}", - "{m(); comparable; int|float32|string}": "{comparable; func (p.T).m(); int ∪ float32 ∪ string}", - "{m1(); int; m2(); comparable }": "{comparable; func (p.T).m1(); func (p.T).m2(); int}", + "{m(); comparable; int|float32|string}": "{func (p.T).m(); int ∪ float32 ∪ string}", + "{m1(); int; m2(); comparable }": "{func (p.T).m1(); func (p.T).m2(); int}", "{E}; type E interface{}": "𝓤", "{E}; type E interface{int;string}": "∅", diff --git a/src/cmd/compile/internal/types2/typexpr.go b/src/cmd/compile/internal/types2/typexpr.go index 2847aa76c0..afbea06032 100644 --- a/src/cmd/compile/internal/types2/typexpr.go +++ b/src/cmd/compile/internal/types2/typexpr.go @@ -147,10 +147,16 @@ func (check *Checker) typ(e syntax.Expr) Type { // constraint interface. func (check *Checker) varType(e syntax.Expr) Type { typ := check.definedType(e, nil) + check.validVarType(e, typ) + return typ +} +// validVarType reports an error if typ is a constraint interface. +// The expression e is used for error reporting, if any. +func (check *Checker) validVarType(e syntax.Expr, typ Type) { // If we have a type parameter there's nothing to do. if isTypeParam(typ) { - return typ + return } // We don't want to call under() or complete interfaces while we are in @@ -168,9 +174,7 @@ func (check *Checker) varType(e syntax.Expr) Type { } } } - }) - - return typ + }).describef(e, "check var type %s", typ) } // definedType is like typ but also accepts a type name def. @@ -256,7 +260,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) { case *syntax.SelectorExpr: var x operand - check.selector(&x, e) + check.selector(&x, e, def) switch x.mode { case typexpr: @@ -344,9 +348,6 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) { case *syntax.InterfaceType: typ := check.newInterface() def.setUnderlying(typ) - if def != nil { - typ.obj = def.obj - } check.interfaceType(typ, e, def) return typ @@ -371,7 +372,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) { } check.errorf(e.Key, "invalid map key type %s%s", typ.key, why) } - }) + }).describef(e.Key, "check map key %s", typ.key) return typ @@ -408,7 +409,7 @@ func (check *Checker) typInternal(e0 syntax.Expr, def *Named) (T Type) { func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def *Named) (res Type) { if check.conf.Trace { - check.trace(x.Pos(), "-- instantiating %s with %s", x, xlist) + check.trace(x.Pos(), "-- instantiating type %s with %s", x, xlist) check.indent++ defer func() { check.indent-- @@ -430,10 +431,14 @@ func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def * // evaluate arguments targs := check.typeList(xlist) if targs == nil { - def.setUnderlying(Typ[Invalid]) // avoid later errors due to lazy instantiation + def.setUnderlying(Typ[Invalid]) // avoid errors later due to lazy instantiation return Typ[Invalid] } + // enableTypeTypeInference controls whether to infer missing type arguments + // using constraint type inference. See issue #51527. + const enableTypeTypeInference = false + // create the instance ctxt := check.bestContext(nil) h := ctxt.instanceHash(orig, targs) @@ -453,19 +458,18 @@ func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def * def.setUnderlying(inst) inst.resolver = func(ctxt *Context, n *Named) (*TypeParamList, Type, *methodList) { - tparams := orig.TypeParams().list() + tparams := n.orig.TypeParams().list() - inferred := targs - if len(targs) < len(tparams) { + targs := n.targs.list() + if enableTypeTypeInference && len(targs) < len(tparams) { // If inference fails, len(inferred) will be 0, and inst.underlying will // be set to Typ[Invalid] in expandNamed. - inferred = check.infer(x.Pos(), tparams, targs, nil, nil) + inferred := check.infer(x.Pos(), tparams, targs, nil, nil) if len(inferred) > len(targs) { - inst.targs = newTypeList(inferred) + n.targs = newTypeList(inferred) } } - check.recordInstance(x, inferred, inst) return expandNamed(ctxt, n, x.Pos()) } @@ -478,6 +482,7 @@ func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def * // Since check is non-nil, we can still mutate inst. Unpinning the resolver // frees some memory. inst.resolver = nil + check.recordInstance(x, inst.TypeArgs().list(), inst) if check.validateTArgLen(x.Pos(), inst.tparams.Len(), inst.targs.Len()) { if i, err := check.verify(x.Pos(), inst.tparams.list(), inst.targs.list()); err != nil { @@ -493,7 +498,7 @@ func (check *Checker) instantiatedType(x syntax.Expr, xlist []syntax.Expr, def * } check.validType(inst) - }) + }).describef(x, "resolve instance %s", inst) return inst } diff --git a/src/cmd/compile/internal/types2/unify.go b/src/cmd/compile/internal/types2/unify.go index 97d327cf8b..a7f68a05b1 100644 --- a/src/cmd/compile/internal/types2/unify.go +++ b/src/cmd/compile/internal/types2/unify.go @@ -39,9 +39,10 @@ const ( // due to implementation issues (e.g., see issues #48619, #48656). unificationDepthLimit = 50 - // Whether to panic when unificationDepthLimit is reached. Turn on when - // investigating infinite recursion. - panicAtUnificationDepthLimit = false + // Whether to panic when unificationDepthLimit is reached. + // If disabled, a recursion depth overflow results in a (quiet) + // unification failure. + panicAtUnificationDepthLimit = true // If enableCoreTypeUnification is set, unification will consider // the core types, if any, of non-local (unbound) type parameters. diff --git a/src/cmd/compile/internal/types2/union.go b/src/cmd/compile/internal/types2/union.go index 3c0df04ccd..132e73098a 100644 --- a/src/cmd/compile/internal/types2/union.go +++ b/src/cmd/compile/internal/types2/union.go @@ -100,25 +100,27 @@ func parseUnion(check *Checker, uexpr syntax.Expr) Type { if !Identical(u, t.typ) { check.errorf(tlist[i], "invalid use of ~ (underlying type of %s is %s)", t.typ, u) - continue // don't report another error for t + continue } } // Stand-alone embedded interfaces are ok and are handled by the single-type case // in the beginning. Embedded interfaces with tilde are excluded above. If we reach - // here, we must have at least two terms in the union. - if f != nil && !f.typeSet().IsTypeSet() { + // here, we must have at least two terms in the syntactic term list (but not necessarily + // in the term list of the union's type set). + if f != nil { + tset := f.typeSet() switch { - case f.typeSet().NumMethods() != 0: + case tset.NumMethods() != 0: check.errorf(tlist[i], "cannot use %s in union (%s contains methods)", t, t) + continue case t.typ == universeComparable.Type(): check.error(tlist[i], "cannot use comparable in union") - case f.typeSet().comparable: + continue + case tset.comparable: check.errorf(tlist[i], "cannot use %s in union (%s embeds comparable)", t, t) - default: - panic("not a type set but no methods and not comparable") + continue } - continue // don't report another error for t } // Report overlapping (non-disjoint) terms such as @@ -127,7 +129,7 @@ func parseUnion(check *Checker, uexpr syntax.Expr) Type { check.softErrorf(tlist[i], "overlapping terms %s and %s", t, terms[j]) } } - }) + }).describef(uexpr, "check term validity %s", uexpr) return u } diff --git a/src/cmd/compile/internal/types2/universe.go b/src/cmd/compile/internal/types2/universe.go index 6ee5dbdca3..1deff3961f 100644 --- a/src/cmd/compile/internal/types2/universe.go +++ b/src/cmd/compile/internal/types2/universe.go @@ -97,7 +97,7 @@ func defPredeclaredTypes() { err := NewFunc(nopos, nil, "Error", sig) // interface{ Error() string } - ityp := &Interface{obj: obj, methods: []*Func{err}, complete: true} + ityp := &Interface{methods: []*Func{err}, complete: true} computeInterfaceTypeSet(nil, nopos, ityp) // prevent races due to lazy computation of tset typ.SetUnderlying(ityp) @@ -111,7 +111,7 @@ func defPredeclaredTypes() { typ := NewNamed(obj, nil, nil) // interface{} // marked as comparable - ityp := &Interface{obj: obj, complete: true, tset: &_TypeSet{true, nil, allTermlist}} + ityp := &Interface{complete: true, tset: &_TypeSet{nil, allTermlist, true}} typ.SetUnderlying(ityp) def(obj) diff --git a/src/cmd/compile/internal/types2/validtype.go b/src/cmd/compile/internal/types2/validtype.go index f365ad1e27..c7d42551dd 100644 --- a/src/cmd/compile/internal/types2/validtype.go +++ b/src/cmd/compile/internal/types2/validtype.go @@ -63,7 +63,8 @@ func (check *Checker) validType0(typ Type, env *tparamEnv, path []Object) typeIn case *Named: // Don't report a 2nd error if we already know the type is invalid // (e.g., if a cycle was detected earlier, via under). - if t.underlying == Typ[Invalid] { + // Note: ensure that t.orig is fully resolved by calling Underlying(). + if t.Underlying() == Typ[Invalid] { check.infoMap[t] = invalid return invalid } diff --git a/src/cmd/compile/internal/walk/assign.go b/src/cmd/compile/internal/walk/assign.go index 9350c389c1..9b09e097fa 100644 --- a/src/cmd/compile/internal/walk/assign.go +++ b/src/cmd/compile/internal/walk/assign.go @@ -157,7 +157,7 @@ func walkAssignMapRead(init *ir.Nodes, n *ir.AssignListStmt) ir.Node { t := r.X.Type() fast := mapfast(t) - key := mapKeyArg(fast, r, r.Index) + key := mapKeyArg(fast, r, r.Index, false) // from: // a,b = m[i] diff --git a/src/cmd/compile/internal/walk/builtin.go b/src/cmd/compile/internal/walk/builtin.go index d0aaee03d5..b25627bd22 100644 --- a/src/cmd/compile/internal/walk/builtin.go +++ b/src/cmd/compile/internal/walk/builtin.go @@ -214,7 +214,7 @@ func walkDelete(init *ir.Nodes, n *ir.CallExpr) ir.Node { t := map_.Type() fast := mapfast(t) - key = mapKeyArg(fast, n, key) + key = mapKeyArg(fast, n, key, false) return mkcall1(mapfndel(mapdelete[fast], t), nil, init, reflectdata.TypePtr(t), map_, key) } diff --git a/src/cmd/compile/internal/walk/convert.go b/src/cmd/compile/internal/walk/convert.go index ffc5fd19e8..6edff4fbba 100644 --- a/src/cmd/compile/internal/walk/convert.go +++ b/src/cmd/compile/internal/walk/convert.go @@ -118,6 +118,12 @@ func dataWord(pos src.XPos, n ir.Node, init *ir.Nodes, escapes bool) ir.Node { return n } + isInteger := fromType.IsInteger() + isBool := fromType.IsBoolean() + if sc := fromType.SoleComponent(); sc != nil { + isInteger = sc.IsInteger() + isBool = sc.IsBoolean() + } // Try a bunch of cases to avoid an allocation. var value ir.Node switch { @@ -125,10 +131,11 @@ func dataWord(pos src.XPos, n ir.Node, init *ir.Nodes, escapes bool) ir.Node { // n is zero-sized. Use zerobase. cheapExpr(n, init) // Evaluate n for side-effects. See issue 19246. value = ir.NewLinksymExpr(base.Pos, ir.Syms.Zerobase, types.Types[types.TUINTPTR]) - case fromType.IsBoolean() || (fromType.Size() == 1 && fromType.IsInteger()): + case isBool || fromType.Size() == 1 && isInteger: // n is a bool/byte. Use staticuint64s[n * 8] on little-endian // and staticuint64s[n * 8 + 7] on big-endian. n = cheapExpr(n, init) + n = soleComponent(init, n) // byteindex widens n so that the multiplication doesn't overflow. index := ir.NewBinaryExpr(base.Pos, ir.OLSH, byteindex(n), ir.NewInt(3)) if ssagen.Arch.LinkArch.ByteOrder == binary.BigEndian { @@ -392,6 +399,29 @@ func rtconvfn(src, dst *types.Type) (param, result types.Kind) { return types.Txxx, types.Txxx } +func soleComponent(init *ir.Nodes, n ir.Node) ir.Node { + if n.Type().SoleComponent() == nil { + return n + } + // Keep in sync with cmd/compile/internal/types/type.go:Type.SoleComponent. + for { + switch { + case n.Type().IsStruct(): + if n.Type().Field(0).Sym.IsBlank() { + // Treat blank fields as the zero value as the Go language requires. + n = typecheck.Temp(n.Type().Field(0).Type) + appendWalkStmt(init, ir.NewAssignStmt(base.Pos, n, nil)) + return n + } + n = typecheck.Expr(ir.NewSelectorExpr(n.Pos(), ir.OXDOT, n, n.Type().Field(0).Sym)) + case n.Type().IsArray(): + n = typecheck.Expr(ir.NewIndexExpr(n.Pos(), n, ir.NewInt(0))) + default: + return n + } + } +} + // byteindex converts n, which is byte-sized, to an int used to index into an array. // We cannot use conv, because we allow converting bool to int here, // which is forbidden in user code. diff --git a/src/cmd/compile/internal/walk/expr.go b/src/cmd/compile/internal/walk/expr.go index e5bf6cf0b5..4c1e7adddd 100644 --- a/src/cmd/compile/internal/walk/expr.go +++ b/src/cmd/compile/internal/walk/expr.go @@ -723,21 +723,23 @@ func walkIndex(n *ir.IndexExpr, init *ir.Nodes) ir.Node { } // mapKeyArg returns an expression for key that is suitable to be passed -// as the key argument for mapaccess and mapdelete functions. +// as the key argument for runtime map* functions. // n is is the map indexing or delete Node (to provide Pos). -// Note: this is not used for mapassign, which does distinguish pointer vs. -// integer key. -func mapKeyArg(fast int, n, key ir.Node) ir.Node { - switch fast { - case mapslow: +func mapKeyArg(fast int, n, key ir.Node, assigned bool) ir.Node { + if fast == mapslow { // standard version takes key by reference. - // order.expr made sure key is addressable. + // orderState.expr made sure key is addressable. return typecheck.NodAddr(key) + } + if assigned { + // mapassign does distinguish pointer vs. integer key. + return key + } + // mapaccess and mapdelete don't distinguish pointer vs. integer key. + switch fast { case mapfast32ptr: - // mapaccess and mapdelete don't distinguish pointer vs. integer key. return ir.NewConvExpr(n.Pos(), ir.OCONVNOP, types.Types[types.TUINT32], key) case mapfast64ptr: - // mapaccess and mapdelete don't distinguish pointer vs. integer key. return ir.NewConvExpr(n.Pos(), ir.OCONVNOP, types.Types[types.TUINT64], key) default: // fast version takes key by value. @@ -746,34 +748,27 @@ func mapKeyArg(fast int, n, key ir.Node) ir.Node { } // walkIndexMap walks an OINDEXMAP node. +// It replaces m[k] with *map{access1,assign}(maptype, m, &k) func walkIndexMap(n *ir.IndexExpr, init *ir.Nodes) ir.Node { - // Replace m[k] with *map{access1,assign}(maptype, m, &k) n.X = walkExpr(n.X, init) n.Index = walkExpr(n.Index, init) map_ := n.X - key := n.Index t := map_.Type() - var call *ir.CallExpr - if n.Assigned { - // This m[k] expression is on the left-hand side of an assignment. - fast := mapfast(t) - if fast == mapslow { - // standard version takes key by reference. - // order.expr made sure key is addressable. - key = typecheck.NodAddr(key) - } - call = mkcall1(mapfn(mapassign[fast], t, false), nil, init, reflectdata.TypePtr(t), map_, key) - } else { - // m[k] is not the target of an assignment. - fast := mapfast(t) - key = mapKeyArg(fast, n, key) - if w := t.Elem().Size(); w <= zeroValSize { - call = mkcall1(mapfn(mapaccess1[fast], t, false), types.NewPtr(t.Elem()), init, reflectdata.TypePtr(t), map_, key) - } else { - z := reflectdata.ZeroAddr(w) - call = mkcall1(mapfn("mapaccess1_fat", t, true), types.NewPtr(t.Elem()), init, reflectdata.TypePtr(t), map_, key, z) - } + fast := mapfast(t) + key := mapKeyArg(fast, n, n.Index, n.Assigned) + args := []ir.Node{reflectdata.TypePtr(t), map_, key} + + var mapFn ir.Node + switch { + case n.Assigned: + mapFn = mapfn(mapassign[fast], t, false) + case t.Elem().Size() > zeroValSize: + args = append(args, reflectdata.ZeroAddr(t.Elem().Size())) + mapFn = mapfn("mapaccess1_fat", t, true) + default: + mapFn = mapfn(mapaccess1[fast], t, false) } + call := mkcall1(mapFn, nil, init, args...) call.SetType(types.NewPtr(t.Elem())) call.MarkNonNil() // mapaccess1* and mapassign always return non-nil pointers. star := ir.NewStarExpr(base.Pos, call) @@ -1012,9 +1007,6 @@ func usefield(n *ir.SelectorExpr) { if outer.Sym() == nil { base.Errorf("tracked field must be in named struct type") } - if !types.IsExported(field.Sym.Name) { - base.Errorf("tracked field must be exported (upper case)") - } sym := reflectdata.TrackSym(outer, field) if ir.CurFunc.FieldTrack == nil { diff --git a/src/cmd/dist/build.go b/src/cmd/dist/build.go index d37c3f83ef..4dfaf83ef7 100644 --- a/src/cmd/dist/build.go +++ b/src/cmd/dist/build.go @@ -976,12 +976,41 @@ func packagefile(pkg string) string { return pathf("%s/pkg/%s_%s/%s.a", goroot, goos, goarch, pkg) } +// unixOS is the set of GOOS values matched by the "unix" build tag. +// This is the same list as in go/build/syslist.go. +var unixOS = map[string]bool{ + "aix": true, + "android": true, + "darwin": true, + "dragonfly": true, + "freebsd": true, + "hurd": true, + "illumos": true, + "ios": true, + "linux": true, + "netbsd": true, + "openbsd": true, + "solaris": true, +} + // matchtag reports whether the tag matches this build. func matchtag(tag string) bool { - return tag == "gc" || tag == goos || tag == goarch || tag == "cmd_go_bootstrap" || tag == "go1.1" || - (goos == "android" && tag == "linux") || - (goos == "illumos" && tag == "solaris") || - (goos == "ios" && tag == "darwin") + switch tag { + case "gc", "cmd_go_bootstrap", "go1.1": + return true + case "linux": + return goos == "linux" || goos == "android" + case "solaris": + return goos == "solaris" || goos == "illumos" + case "darwin": + return goos == "darwin" || goos == "ios" + case goos, goarch: + return true + case "unix": + return unixOS[goos] + default: + return false + } } // shouldbuild reports whether we should build this file. @@ -1502,8 +1531,19 @@ func goInstall(goBinary string, args ...string) { goCmd(goBinary, "install", args...) } +func appendCompilerFlags(args []string) []string { + if gogcflags != "" { + args = append(args, "-gcflags=all="+gogcflags) + } + if goldflags != "" { + args = append(args, "-ldflags=all="+goldflags) + } + return args +} + func goCmd(goBinary string, cmd string, args ...string) { - goCmd := []string{goBinary, cmd, "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags} + goCmd := []string{goBinary, cmd} + goCmd = appendCompilerFlags(goCmd) if vflag > 0 { goCmd = append(goCmd, "-v") } @@ -1517,12 +1557,11 @@ func goCmd(goBinary string, cmd string, args ...string) { } func checkNotStale(goBinary string, targets ...string) { - out := run(workdir, CheckExit, - append([]string{ - goBinary, - "list", "-gcflags=all=" + gogcflags, "-ldflags=all=" + goldflags, - "-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}", - }, targets...)...) + goCmd := []string{goBinary, "list"} + goCmd = appendCompilerFlags(goCmd) + goCmd = append(goCmd, "-f={{if .Stale}}\tSTALE {{.ImportPath}}: {{.StaleReason}}{{end}}") + + out := run(workdir, CheckExit, append(goCmd, targets...)...) if strings.Contains(out, "\tSTALE ") { os.Setenv("GODEBUG", "gocachehash=1") for _, target := range []string{"runtime/internal/sys", "cmd/dist", "cmd/link"} { diff --git a/src/cmd/dist/test.go b/src/cmd/dist/test.go index ab30089881..a540a2abda 100644 --- a/src/cmd/dist/test.go +++ b/src/cmd/dist/test.go @@ -218,6 +218,15 @@ func (t *tester) run() { } } + if err := t.maybeLogMetadata(); err != nil { + t.failed = true + if t.keepGoing { + log.Printf("Failed logging metadata: %v", err) + } else { + fatalf("Failed logging metadata: %v", err) + } + } + for _, dt := range t.tests { if !t.shouldRunTest(dt.name) { t.partial = true @@ -268,6 +277,22 @@ func (t *tester) shouldRunTest(name string) bool { return false } +func (t *tester) maybeLogMetadata() error { + if t.compileOnly { + // We need to run a subprocess to log metadata. Don't do that + // on compile-only runs. + return nil + } + t.out("Test execution environment.") + // Helper binary to print system metadata (CPU model, etc). This is a + // separate binary from dist so it need not build with the bootstrap + // toolchain. + // + // TODO(prattmic): If we split dist bootstrap and dist test then this + // could be simplified to directly use internal/sysinfo here. + return t.dirCmd(filepath.Join(goroot, "src/cmd/internal/metadata"), "go", []string{"run", "."}).Run() +} + // short returns a -short flag value to use with 'go test' // or a test binary for tests intended to run in short mode. // It returns "true", unless the environment variable @@ -372,7 +397,9 @@ func (t *tester) registerStdTest(pkg string) { "-short=" + short(), t.tags(), t.timeout(timeoutSec), - "-gcflags=all=" + gcflags, + } + if gcflags != "" { + args = append(args, "-gcflags=all="+gcflags) } if t.race { args = append(args, "-race") diff --git a/src/cmd/doc/dirs.go b/src/cmd/doc/dirs.go index f27af1d27b..489f490889 100644 --- a/src/cmd/doc/dirs.go +++ b/src/cmd/doc/dirs.go @@ -41,12 +41,31 @@ var dirs Dirs // dirsInit starts the scanning of package directories in GOROOT and GOPATH. Any // extra paths passed to it are included in the channel. func dirsInit(extra ...Dir) { + if buildCtx.GOROOT == "" { + stdout, err := exec.Command("go", "env", "GOROOT").Output() + if err != nil { + if ee, ok := err.(*exec.ExitError); ok && len(ee.Stderr) > 0 { + log.Fatalf("failed to determine GOROOT: $GOROOT is not set and 'go env GOROOT' failed:\n%s", ee.Stderr) + } + log.Fatalf("failed to determine GOROOT: $GOROOT is not set and could not run 'go env GOROOT':\n\t%s", err) + } + buildCtx.GOROOT = string(bytes.TrimSpace(stdout)) + } + dirs.hist = make([]Dir, 0, 1000) dirs.hist = append(dirs.hist, extra...) dirs.scan = make(chan Dir) go dirs.walk(codeRoots()) } +// goCmd returns the "go" command path corresponding to buildCtx.GOROOT. +func goCmd() string { + if buildCtx.GOROOT == "" { + return "go" + } + return filepath.Join(buildCtx.GOROOT, "bin", "go") +} + // Reset puts the scan back at the beginning. func (d *Dirs) Reset() { d.offset = 0 @@ -170,11 +189,11 @@ func findCodeRoots() []Dir { if !testGOPATH { // Check for use of modules by 'go env GOMOD', // which reports a go.mod file path if modules are enabled. - stdout, _ := exec.Command("go", "env", "GOMOD").Output() + stdout, _ := exec.Command(goCmd(), "env", "GOMOD").Output() gomod := string(bytes.TrimSpace(stdout)) usingModules = len(gomod) > 0 - if usingModules { + if usingModules && buildCtx.GOROOT != "" { list = append(list, Dir{dir: filepath.Join(buildCtx.GOROOT, "src"), inModule: true}, Dir{importPath: "cmd", dir: filepath.Join(buildCtx.GOROOT, "src", "cmd"), inModule: true}) @@ -190,7 +209,9 @@ func findCodeRoots() []Dir { } if !usingModules { - list = append(list, Dir{dir: filepath.Join(buildCtx.GOROOT, "src")}) + if buildCtx.GOROOT != "" { + list = append(list, Dir{dir: filepath.Join(buildCtx.GOROOT, "src")}) + } for _, root := range splitGopath() { list = append(list, Dir{dir: filepath.Join(root, "src")}) } @@ -217,7 +238,7 @@ func findCodeRoots() []Dir { return list } - cmd := exec.Command("go", "list", "-m", "-f={{.Path}}\t{{.Dir}}", "all") + cmd := exec.Command(goCmd(), "list", "-m", "-f={{.Path}}\t{{.Dir}}", "all") cmd.Stderr = os.Stderr out, _ := cmd.Output() for _, line := range strings.Split(string(out), "\n") { @@ -246,7 +267,7 @@ func vendorEnabled() (*moduleJSON, bool, error) { return nil, false, err } - stdout, _ := exec.Command("go", "env", "GOFLAGS").Output() + stdout, _ := exec.Command(goCmd(), "env", "GOFLAGS").Output() goflags := string(bytes.TrimSpace(stdout)) matches := modFlagRegexp.FindStringSubmatch(goflags) var modFlag string @@ -280,7 +301,7 @@ func getMainModuleAnd114() (*moduleJSON, bool, error) { {{.GoVersion}} {{range context.ReleaseTags}}{{if eq . "go1.14"}}{{.}}{{end}}{{end}} ` - cmd := exec.Command("go", "list", "-m", "-f", format) + cmd := exec.Command(goCmd(), "list", "-m", "-f", format) cmd.Stderr = os.Stderr stdout, err := cmd.Output() if err != nil { diff --git a/src/cmd/doc/doc_test.go b/src/cmd/doc/doc_test.go index 0ff9edcde3..ead4f722f6 100644 --- a/src/cmd/doc/doc_test.go +++ b/src/cmd/doc/doc_test.go @@ -7,6 +7,8 @@ package main import ( "bytes" "flag" + "go/build" + "internal/testenv" "log" "os" "path/filepath" @@ -21,6 +23,12 @@ func TestMain(m *testing.M) { buildCtx.GOPATH = "" testGOPATH = true // force GOPATH mode; module test is in cmd/go/testdata/script/mod_doc.txt + // Set GOROOT in case runtime.GOROOT is wrong (for example, if the test was + // built with -trimpath). dirsInit would identify it using 'go env GOROOT', + // but we can't be sure that the 'go' in $PATH is the right one either. + buildCtx.GOROOT = testenv.GOROOT(nil) + build.Default.GOROOT = testenv.GOROOT(nil) + // Add $GOROOT/src/cmd/doc/testdata explicitly so we can access its contents in the test. // Normally testdata directories are ignored, but sending it to dirs.scan directly is // a hack that works around the check. diff --git a/src/cmd/doc/pkg.go b/src/cmd/doc/pkg.go index 0266600730..49b68873b6 100644 --- a/src/cmd/doc/pkg.go +++ b/src/cmd/doc/pkg.go @@ -89,9 +89,11 @@ func (pkg *Package) prettyPath() string { // Also convert everything to slash-separated paths for uniform handling. path = filepath.Clean(filepath.ToSlash(pkg.build.Dir)) // Can we find a decent prefix? - goroot := filepath.Join(buildCtx.GOROOT, "src") - if p, ok := trim(path, filepath.ToSlash(goroot)); ok { - return p + if buildCtx.GOROOT != "" { + goroot := filepath.Join(buildCtx.GOROOT, "src") + if p, ok := trim(path, filepath.ToSlash(goroot)); ok { + return p + } } for _, gopath := range splitGopath() { if p, ok := trim(path, filepath.ToSlash(gopath)); ok { diff --git a/src/cmd/fix/main.go b/src/cmd/fix/main.go index 3229b71ec4..4e5c08731b 100644 --- a/src/cmd/fix/main.go +++ b/src/cmd/fix/main.go @@ -13,6 +13,7 @@ import ( "go/parser" "go/scanner" "go/token" + "internal/diff" "io" "io/fs" "os" @@ -20,8 +21,6 @@ import ( "sort" "strconv" "strings" - - "cmd/internal/diff" ) var ( @@ -228,12 +227,7 @@ func processFile(filename string, useStdin bool) error { } if *doDiff { - data, err := diff.Diff("go-fix", src, newSrc) - if err != nil { - return fmt.Errorf("computing diff: %s", err) - } - fmt.Printf("diff %s fixed/%s\n", filename, filename) - os.Stdout.Write(data) + os.Stdout.Write(diff.Diff(filename, src, "fixed/"+filename, newSrc)) return nil } diff --git a/src/cmd/fix/main_test.go b/src/cmd/fix/main_test.go index 1baa95c545..755007bc0d 100644 --- a/src/cmd/fix/main_test.go +++ b/src/cmd/fix/main_test.go @@ -7,10 +7,9 @@ package main import ( "go/ast" "go/parser" + "internal/diff" "strings" "testing" - - "cmd/internal/diff" ) type testCase struct { @@ -52,7 +51,7 @@ func parseFixPrint(t *testing.T, fn func(*ast.File) bool, desc, in string, mustB if s := string(outb); in != s && mustBeGofmt { t.Errorf("not gofmt-formatted.\n--- %s\n%s\n--- %s | gofmt\n%s", desc, in, desc, s) - tdiff(t, in, s) + tdiff(t, "want", in, "have", s) return } @@ -109,7 +108,7 @@ func TestRewrite(t *testing.T) { if !strings.HasPrefix(tt.Name, "testdata/") { t.Errorf("--- have\n%s\n--- want\n%s", out, tt.Out) } - tdiff(t, out, tt.Out) + tdiff(t, "have", out, "want", tt.Out) return } @@ -132,17 +131,12 @@ func TestRewrite(t *testing.T) { if out2 != out { t.Errorf("changed output after second round of fixes.\n--- output after first round\n%s\n--- output after second round\n%s", out, out2) - tdiff(t, out, out2) + tdiff(t, "first", out, "second", out2) } }) } } -func tdiff(t *testing.T, a, b string) { - data, err := diff.Diff("go-fix-test", []byte(a), []byte(b)) - if err != nil { - t.Error(err) - return - } - t.Error(string(data)) +func tdiff(t *testing.T, aname, a, bname, b string) { + t.Errorf("%s", diff.Diff(aname, []byte(a), bname, []byte(b))) } diff --git a/src/cmd/go.mod b/src/cmd/go.mod index 48fc888f94..33ba0a6ae8 100644 --- a/src/cmd/go.mod +++ b/src/cmd/go.mod @@ -1,19 +1,19 @@ module cmd -go 1.18 +go 1.19 require ( - github.com/google/pprof v0.0.0-20211104044539-f987b9c94b31 + github.com/google/pprof v0.0.0-20220314021825-5bba342933ea golang.org/x/arch v0.0.0-20210923205945-b76863e36670 - golang.org/x/mod v0.6.0-dev.0.20211102181907-3a5865c02020 + golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 golang.org/x/sync v0.0.0-20210220032951-036812b2e83c + golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 - golang.org/x/tools v0.1.9-0.20220124164225-97de9ec46646 + golang.org/x/tools v0.1.11-0.20220321170318-c717623e3197 ) require ( github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d // indirect - golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 // indirect - golang.org/x/sys v0.0.0-20211205182925-97ca703d548d // indirect + golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd // indirect golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 // indirect ) diff --git a/src/cmd/go.sum b/src/cmd/go.sum index 4a5479f881..5f625110c2 100644 --- a/src/cmd/go.sum +++ b/src/cmd/go.sum @@ -1,24 +1,24 @@ github.com/chzyer/logex v1.1.10/go.mod h1:+Ywpsq7O8HXn0nuIou7OrIPyXbp3wmkHB+jjWRnGsAI= github.com/chzyer/readline v0.0.0-20180603132655-2972be24d48e/go.mod h1:nSuG5e5PlCu98SY8svDHJxuZscDgtXS6KTTbou5AhLI= github.com/chzyer/test v0.0.0-20180213035817-a1ea475d72b1/go.mod h1:Q3SI9o4m/ZMnBNeIyt5eFwwo7qiLfzFZmjNmxjkiQlU= -github.com/google/pprof v0.0.0-20211104044539-f987b9c94b31 h1:YvpxjnjGhf/vDEeYOysNbsrtB///PKS8lqkFNSDm1p8= -github.com/google/pprof v0.0.0-20211104044539-f987b9c94b31/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= +github.com/google/pprof v0.0.0-20220314021825-5bba342933ea h1:yVDp4C9ff/qoEAhHNf5cqk/YTxTGECSzGYzahdhEKBI= +github.com/google/pprof v0.0.0-20220314021825-5bba342933ea/go.mod h1:KgnwoLYCZ8IQu3XUZ8Nc/bM9CCZFOyjUNOSygVozoDg= github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d h1:uGg2frlt3IcT7kbV6LEp5ONv4vmoO2FW4qSO+my/aoM= github.com/ianlancetaylor/demangle v0.0.0-20210905161508-09a460cdf81d/go.mod h1:aYm2/VgdVmcIU8iMfdMvDMsRAQjcfZSKFby6HOFvi/w= golang.org/x/arch v0.0.0-20210923205945-b76863e36670 h1:18EFjUmQOcUvxNYSkA6jO9VAiXCnxFY6NyDX0bHDmkU= golang.org/x/arch v0.0.0-20210923205945-b76863e36670/go.mod h1:5om86z9Hs0C8fWVUuoMHwpExlXzs5Tkyp9hOrfG7pp8= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3 h1:0es+/5331RGQPcXlMfP+WrnIIS6dNnNRe0WB02W0F4M= -golang.org/x/crypto v0.0.0-20211215153901-e495a2d5b3d3/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= -golang.org/x/mod v0.6.0-dev.0.20211102181907-3a5865c02020 h1:HjtpZuJcnSa+yHlL4Y5aypjDvbHkJne5FS8JRmKI2+I= -golang.org/x/mod v0.6.0-dev.0.20211102181907-3a5865c02020/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd h1:XcWmESyNjXJMLahc3mqVQJcgSTDxFxhETVlfk9uGc38= +golang.org/x/crypto v0.0.0-20220315160706-3147a52a75dd/go.mod h1:IxCIyHEi3zRg3s0A5j5BB6A9Jmi73HwBIUl50j+osU4= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3 h1:kQgndtyPBW/JIYERgdxfwMYh3AVStj88WQTlNDi2a+o= +golang.org/x/mod v0.6.0-dev.0.20220106191415-9b9b3d81d5e3/go.mod h1:3p9vT2HGsQu2K1YbXdKPJLVgG5VJdoTa1poYQBtP1AY= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c h1:5KslGYwFpkhGh+Q16bwMP3cOontH8FOep7tGV86Y7SQ= golang.org/x/sync v0.0.0-20210220032951-036812b2e83c/go.mod h1:RxMgew5VJxzue5/jJTE5uejpjVlOe/izrB70Jof72aM= golang.org/x/sys v0.0.0-20211007075335-d3039528d8ac/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d h1:FjkYO/PPp4Wi0EAUOVLxePm7qVW4r4ctbWpURyuOD0E= -golang.org/x/sys v0.0.0-20211205182925-97ca703d548d/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= +golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf h1:Fm4IcnUL803i92qDlmB0obyHmosDrxZWxJL3gIeNqOw= +golang.org/x/sys v0.0.0-20220317061510-51cd9980dadf/go.mod h1:oPkhp1MJrh7nUepCBck5+mAzfO9JrbApNNgaTdGDITg= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211 h1:JGgROgKl9N8DuW20oFS5gxc+lE67/N3FcwmBPMe7ArY= golang.org/x/term v0.0.0-20210927222741-03fcf44c2211/go.mod h1:jbD1KX2456YbFQfuXm/mYQcufACuNUgVhRMnK/tPxf8= -golang.org/x/tools v0.1.9-0.20220124164225-97de9ec46646 h1:f8aekWvlQQ8ZhD8SL7lOu18dtWslZYl029PN2F0VnS4= -golang.org/x/tools v0.1.9-0.20220124164225-97de9ec46646/go.mod h1:nABZi5QlRsZVlzPpHl034qft6wpY4eDcsTt5AaioBiU= +golang.org/x/tools v0.1.11-0.20220321170318-c717623e3197 h1:WMZWqasfF4Mn7qLi4QW7JmUmwV6ucBntOppK8p6dYKQ= +golang.org/x/tools v0.1.11-0.20220321170318-c717623e3197/go.mod h1:Uh6Zz+xoGYZom868N8YTex3t7RhtHDBrE8Gzo9bV56E= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1 h1:go1bK/D/BFZV2I8cIQd1NKEZ+0owSTG1fDTci4IqFcE= golang.org/x/xerrors v0.0.0-20200804184101-5ec99f83aff1/go.mod h1:I/5z698sn9Ka8TeJc9MKroUUfqBBauWjQqLJ2OPfmY0= diff --git a/src/cmd/go/alldocs.go b/src/cmd/go/alldocs.go index 825de1e64a..f9d78b59e3 100644 --- a/src/cmd/go/alldocs.go +++ b/src/cmd/go/alldocs.go @@ -1599,6 +1599,10 @@ // cross-compiled programs when a simulator or other execution method is // available. // +// By default, 'go run' compiles the binary without generating the information +// used by debuggers, to reduce build time. To include debugger information in +// the binary, use 'go build'. +// // The exit status of Run is not the exit status of the compiled binary. // // For more about build flags, see 'go help build'. @@ -1840,6 +1844,7 @@ // GOOS environment variable. // - the target architecture, as spelled by runtime.GOARCH, set with the // GOARCH environment variable. +// - "unix", if GOOS is a Unix or Unix-like system. // - the compiler being used, either "gc" or "gccgo" // - "cgo", if the cgo command is supported (see CGO_ENABLED in // 'go help environment'). diff --git a/src/cmd/go/export_test.go b/src/cmd/go/export_test.go new file mode 100644 index 0000000000..155ab8c1bb --- /dev/null +++ b/src/cmd/go/export_test.go @@ -0,0 +1,7 @@ +// Copyright 2015 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 main + +func Main() { main() } diff --git a/src/cmd/go/go_test.go b/src/cmd/go/go_test.go index 11ba733b38..84fef6db77 100644 --- a/src/cmd/go/go_test.go +++ b/src/cmd/go/go_test.go @@ -14,7 +14,6 @@ import ( "fmt" "go/format" "internal/godebug" - "internal/race" "internal/testenv" "io" "io/fs" @@ -32,7 +31,11 @@ import ( "cmd/go/internal/cache" "cmd/go/internal/cfg" "cmd/go/internal/robustio" + "cmd/go/internal/search" + "cmd/go/internal/work" "cmd/internal/sys" + + cmdgo "cmd/go" ) func init() { @@ -84,6 +87,43 @@ var testBin string // The TestMain function creates a go command for testing purposes and // deletes it after the tests have been run. func TestMain(m *testing.M) { + // When CMDGO_TEST_RUN_MAIN is set, we're reusing the test binary as cmd/go. + // Enable the special behavior needed in cmd/go/internal/work, + // run the main func exported via export_test.go, and exit. + // We set CMDGO_TEST_RUN_MAIN via os.Setenv and testScript.setup. + if os.Getenv("CMDGO_TEST_RUN_MAIN") != "" { + if v := os.Getenv("TESTGO_VERSION"); v != "" { + work.RuntimeVersion = v + } + + if testGOROOT := os.Getenv("TESTGO_GOROOT"); testGOROOT != "" { + // Disallow installs to the GOROOT from which testgo was built. + // Installs to other GOROOTs — such as one set explicitly within a test — are ok. + work.AllowInstall = func(a *work.Action) error { + if cfg.BuildN { + return nil + } + + rel := search.InDir(a.Target, testGOROOT) + if rel == "" { + return nil + } + + callerPos := "" + if _, file, line, ok := runtime.Caller(1); ok { + if shortFile := search.InDir(file, filepath.Join(testGOROOT, "src")); shortFile != "" { + file = shortFile + } + callerPos = fmt.Sprintf("%s:%d: ", file, line) + } + return fmt.Errorf("%stestgo must not write to GOROOT (installing to %s)", callerPos, filepath.Join("GOROOT", rel)) + } + } + cmdgo.Main() + os.Exit(0) + } + os.Setenv("CMDGO_TEST_RUN_MAIN", "true") + // $GO_GCFLAGS a compiler debug flag known to cmd/dist, make.bash, etc. // It is not a standard go command flag; use os.Getenv, not cfg.Getenv. if os.Getenv("GO_GCFLAGS") != "" { @@ -127,10 +167,6 @@ func TestMain(m *testing.M) { log.Fatal(err) } testGo = filepath.Join(testBin, "go"+exeSuffix) - args := []string{"build", "-tags", "testgo", "-o", testGo} - if race.Enabled { - args = append(args, "-race") - } gotool, err := testenv.GoTool() if err != nil { fmt.Fprintln(os.Stderr, "locating go tool: ", err) @@ -173,12 +209,32 @@ func TestMain(m *testing.M) { return } - buildCmd := exec.Command(gotool, args...) - buildCmd.Env = append(os.Environ(), "GOFLAGS=-mod=vendor") - out, err := buildCmd.CombinedOutput() + // Duplicate the test executable into the path at testGo, for $PATH. + // If the OS supports symlinks, use them instead of copying bytes. + testExe, err := os.Executable() if err != nil { - fmt.Fprintf(os.Stderr, "building testgo failed: %v\n%s", err, out) - os.Exit(2) + log.Fatal(err) + } + if err := os.Symlink(testExe, testGo); err != nil { + // Otherwise, copy the bytes. + src, err := os.Open(testExe) + if err != nil { + log.Fatal(err) + } + defer src.Close() + + dst, err := os.OpenFile(testGo, os.O_WRONLY|os.O_CREATE|os.O_EXCL, 0o777) + if err != nil { + log.Fatal(err) + } + + _, err = io.Copy(dst, src) + if closeErr := dst.Close(); err == nil { + err = closeErr + } + if err != nil { + log.Fatal(err) + } } cmd := exec.Command(testGo, "env", "CGO_ENABLED") @@ -193,7 +249,7 @@ func TestMain(m *testing.M) { } } - out, err = exec.Command(gotool, "env", "GOCACHE").CombinedOutput() + out, err := exec.Command(gotool, "env", "GOCACHE").CombinedOutput() if err != nil { fmt.Fprintf(os.Stderr, "could not find testing GOCACHE: %v\n%s", err, out) os.Exit(2) @@ -1575,7 +1631,7 @@ func TestListTemplateContextFunction(t *testing.T) { }{ {"GOARCH", runtime.GOARCH}, {"GOOS", runtime.GOOS}, - {"GOROOT", filepath.Clean(runtime.GOROOT())}, + {"GOROOT", testGOROOT}, {"GOPATH", os.Getenv("GOPATH")}, {"CgoEnabled", ""}, {"UseAllFiles", ""}, diff --git a/src/cmd/go/help_test.go b/src/cmd/go/help_test.go index abfc3db993..3e1d817ca5 100644 --- a/src/cmd/go/help_test.go +++ b/src/cmd/go/help_test.go @@ -6,6 +6,8 @@ package main_test import ( "bytes" + "go/format" + diffpkg "internal/diff" "os" "testing" @@ -23,11 +25,17 @@ func TestDocsUpToDate(t *testing.T) { buf := new(bytes.Buffer) // Match the command in mkalldocs.sh that generates alldocs.go. help.Help(buf, []string{"documentation"}) - data, err := os.ReadFile("alldocs.go") + internal := buf.Bytes() + internal, err := format.Source(internal) + if err != nil { + t.Fatalf("gofmt docs: %v", err) + } + alldocs, err := os.ReadFile("alldocs.go") if err != nil { t.Fatalf("error reading alldocs.go: %v", err) } - if !bytes.Equal(data, buf.Bytes()) { - t.Errorf("alldocs.go is not up to date; run mkalldocs.sh to regenerate it") + if !bytes.Equal(internal, alldocs) { + t.Errorf("alldocs.go is not up to date; run mkalldocs.sh to regenerate it\n%s", + diffpkg.Diff("go help documentation | gofmt", internal, "alldocs.go", alldocs)) } } diff --git a/src/cmd/go/internal/cfg/cfg.go b/src/cmd/go/internal/cfg/cfg.go index deab3dddd0..a11a1a7655 100644 --- a/src/cmd/go/internal/cfg/cfg.go +++ b/src/cmd/go/internal/cfg/cfg.go @@ -22,6 +22,26 @@ import ( "cmd/go/internal/fsys" ) +// Global build parameters (used during package load) +var ( + Goos = envOr("GOOS", build.Default.GOOS) + Goarch = envOr("GOARCH", build.Default.GOARCH) + + ExeSuffix = exeSuffix() + + // ModulesEnabled specifies whether the go command is running + // in module-aware mode (as opposed to GOPATH mode). + // It is equal to modload.Enabled, but not all packages can import modload. + ModulesEnabled bool +) + +func exeSuffix() string { + if Goos == "windows" { + return ".exe" + } + return "" +} + // These are general "build flags" used by build and other commands. var ( BuildA bool // -a flag @@ -60,8 +80,6 @@ var ( // GoPathError is set when GOPATH is not set. it contains an // explanation why GOPATH is unset. GoPathError string - - GOEXPERIMENT = envOr("GOEXPERIMENT", buildcfg.DefaultGOEXPERIMENT) ) func defaultContext() build.Context { @@ -69,30 +87,15 @@ func defaultContext() build.Context { ctxt.JoinPath = filepath.Join // back door to say "do not use go command" - ctxt.GOROOT = findGOROOT() - if runtime.Compiler != "gccgo" { - // Note that we must use runtime.GOOS and runtime.GOARCH here, - // as the tool directory does not move based on environment - // variables. This matches the initialization of ToolDir in - // go/build, except for using ctxt.GOROOT rather than - // runtime.GOROOT. - build.ToolDir = filepath.Join(ctxt.GOROOT, "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH) - } - - ctxt.GOPATH = envOr("GOPATH", gopath(ctxt)) - // Override defaults computed in go/build with defaults // from go environment configuration file, if known. - ctxt.GOOS = envOr("GOOS", ctxt.GOOS) - ctxt.GOARCH = envOr("GOARCH", ctxt.GOARCH) + ctxt.GOPATH = envOr("GOPATH", gopath(ctxt)) + ctxt.GOOS = Goos + ctxt.GOARCH = Goarch - // The experiments flags are based on GOARCH, so they may - // need to change. TODO: This should be cleaned up. - buildcfg.UpdateExperiments(ctxt.GOOS, ctxt.GOARCH, GOEXPERIMENT) + // ToolTags are based on GOEXPERIMENT, which we will parse and + // initialize later. ctxt.ToolTags = nil - for _, exp := range buildcfg.EnabledExperiments() { - ctxt.ToolTags = append(ctxt.ToolTags, "goexperiment."+exp) - } // The go/build rule for whether cgo is enabled is: // 1. If $CGO_ENABLED is set, respect it. @@ -133,10 +136,63 @@ func defaultContext() build.Context { } func init() { + SetGOROOT(findGOROOT()) BuildToolchainCompiler = func() string { return "missing-compiler" } BuildToolchainLinker = func() string { return "missing-linker" } } +func SetGOROOT(goroot string) { + BuildContext.GOROOT = goroot + + GOROOT = goroot + if goroot == "" { + GOROOTbin = "" + GOROOTpkg = "" + GOROOTsrc = "" + } else { + GOROOTbin = filepath.Join(goroot, "bin") + GOROOTpkg = filepath.Join(goroot, "pkg") + GOROOTsrc = filepath.Join(goroot, "src") + } + GOROOT_FINAL = findGOROOT_FINAL(goroot) + + if runtime.Compiler != "gccgo" && goroot != "" { + // Note that we must use runtime.GOOS and runtime.GOARCH here, + // as the tool directory does not move based on environment + // variables. This matches the initialization of ToolDir in + // go/build, except for using BuildContext.GOROOT rather than + // runtime.GOROOT. + build.ToolDir = filepath.Join(goroot, "pkg/tool/"+runtime.GOOS+"_"+runtime.GOARCH) + } +} + +// Experiment configuration. +var ( + // RawGOEXPERIMENT is the GOEXPERIMENT value set by the user. + RawGOEXPERIMENT = envOr("GOEXPERIMENT", buildcfg.DefaultGOEXPERIMENT) + // CleanGOEXPERIMENT is the minimal GOEXPERIMENT value needed to reproduce the + // experiments enabled by RawGOEXPERIMENT. + CleanGOEXPERIMENT = RawGOEXPERIMENT + + Experiment *buildcfg.ExperimentFlags + ExperimentErr error +) + +func init() { + Experiment, ExperimentErr = buildcfg.ParseGOEXPERIMENT(Goos, Goarch, RawGOEXPERIMENT) + if ExperimentErr != nil { + return + } + + // GOEXPERIMENT is valid, so convert it to canonical form. + CleanGOEXPERIMENT = Experiment.String() + + // Add build tags based on the experiments in effect. + for _, exp := range Experiment.Enabled() { + BuildContext.ToolTags = append(BuildContext.ToolTags, "goexperiment."+exp) + } +} + // An EnvVar is an environment variable Name=Value. type EnvVar struct { Name string @@ -151,26 +207,6 @@ var OrigEnv []string // not CmdEnv. var CmdEnv []EnvVar -// Global build parameters (used during package load) -var ( - Goarch = BuildContext.GOARCH - Goos = BuildContext.GOOS - - ExeSuffix = exeSuffix() - - // ModulesEnabled specifies whether the go command is running - // in module-aware mode (as opposed to GOPATH mode). - // It is equal to modload.Enabled, but not all packages can import modload. - ModulesEnabled bool -) - -func exeSuffix() string { - if Goos == "windows" { - return ".exe" - } - return "" -} - var envCache struct { once sync.Once m map[string]string @@ -259,12 +295,12 @@ func CanGetenv(key string) bool { } var ( - GOROOT = BuildContext.GOROOT + GOROOT string + GOROOTbin string + GOROOTpkg string + GOROOTsrc string + GOROOT_FINAL string GOBIN = Getenv("GOBIN") - GOROOTbin = filepath.Join(GOROOT, "bin") - GOROOTpkg = filepath.Join(GOROOT, "pkg") - GOROOTsrc = filepath.Join(GOROOT, "src") - GOROOT_FINAL = findGOROOT_FINAL() GOMODCACHE = envOr("GOMODCACHE", gopathDir("pkg/mod")) // Used in envcmd.MkEnv and build ID computations. @@ -334,7 +370,10 @@ func findGOROOT() string { if env := Getenv("GOROOT"); env != "" { return filepath.Clean(env) } - def := filepath.Clean(runtime.GOROOT()) + def := "" + if r := runtime.GOROOT(); r != "" { + def = filepath.Clean(r) + } if runtime.Compiler == "gccgo" { // gccgo has no real GOROOT, and it certainly doesn't // depend on the executable's location. @@ -366,10 +405,10 @@ func findGOROOT() string { return def } -func findGOROOT_FINAL() string { +func findGOROOT_FINAL(goroot string) string { // $GOROOT_FINAL is only for use during make.bash // so it is not settable using go/env, so we use os.Getenv here. - def := GOROOT + def := goroot if env := os.Getenv("GOROOT_FINAL"); env != "" { def = filepath.Clean(env) } diff --git a/src/cmd/go/internal/envcmd/env.go b/src/cmd/go/internal/envcmd/env.go index c1adf8cef4..fcabc8d1c7 100644 --- a/src/cmd/go/internal/envcmd/env.go +++ b/src/cmd/go/internal/envcmd/env.go @@ -74,7 +74,14 @@ func MkEnv() []cfg.EnvVar { {Name: "GOCACHE", Value: cache.DefaultDir()}, {Name: "GOENV", Value: envFile}, {Name: "GOEXE", Value: cfg.ExeSuffix}, - {Name: "GOEXPERIMENT", Value: buildcfg.GOEXPERIMENT()}, + + // List the raw value of GOEXPERIMENT, not the cleaned one. + // The set of default experiments may change from one release + // to the next, so a GOEXPERIMENT setting that is redundant + // with the current toolchain might actually be relevant with + // a different version (for example, when bisecting a regression). + {Name: "GOEXPERIMENT", Value: cfg.RawGOEXPERIMENT}, + {Name: "GOFLAGS", Value: cfg.Getenv("GOFLAGS")}, {Name: "GOHOSTARCH", Value: runtime.GOARCH}, {Name: "GOHOSTOS", Value: runtime.GOOS}, @@ -222,6 +229,9 @@ func runEnv(ctx context.Context, cmd *base.Command, args []string) { } buildcfg.Check() + if cfg.ExperimentErr != nil { + base.Fatalf("go: %v", cfg.ExperimentErr) + } env := cfg.CmdEnv env = append(env, ExtraEnvVars()...) @@ -374,9 +384,9 @@ func checkBuildConfig(add map[string]string, del map[string]bool) error { } } - goexperiment, okGOEXPERIMENT := get("GOEXPERIMENT", buildcfg.GOEXPERIMENT(), "") + goexperiment, okGOEXPERIMENT := get("GOEXPERIMENT", cfg.RawGOEXPERIMENT, buildcfg.DefaultGOEXPERIMENT) if okGOEXPERIMENT { - if _, _, err := buildcfg.ParseGOEXPERIMENT(goos, goarch, goexperiment); err != nil { + if _, err := buildcfg.ParseGOEXPERIMENT(goos, goarch, goexperiment); err != nil { return err } } diff --git a/src/cmd/go/internal/fsys/fsys_test.go b/src/cmd/go/internal/fsys/fsys_test.go index c080c14987..8cfe1d89e6 100644 --- a/src/cmd/go/internal/fsys/fsys_test.go +++ b/src/cmd/go/internal/fsys/fsys_test.go @@ -5,14 +5,13 @@ import ( "errors" "fmt" "internal/testenv" + "internal/txtar" "io" "io/fs" "os" "path/filepath" "reflect" "testing" - - "golang.org/x/tools/txtar" ) // initOverlay resets the overlay state to reflect the config. diff --git a/src/cmd/go/internal/help/helpdoc.go b/src/cmd/go/internal/help/helpdoc.go index 28ddaac8f1..36bc4f28b7 100644 --- a/src/cmd/go/internal/help/helpdoc.go +++ b/src/cmd/go/internal/help/helpdoc.go @@ -843,6 +843,7 @@ During a particular build, the following words are satisfied: GOOS environment variable. - the target architecture, as spelled by runtime.GOARCH, set with the GOARCH environment variable. + - "unix", if GOOS is a Unix or Unix-like system. - the compiler being used, either "gc" or "gccgo" - "cgo", if the cgo command is supported (see CGO_ENABLED in 'go help environment'). diff --git a/src/cmd/go/internal/imports/scan_test.go b/src/cmd/go/internal/imports/scan_test.go index 7e69c56513..56efa9023f 100644 --- a/src/cmd/go/internal/imports/scan_test.go +++ b/src/cmd/go/internal/imports/scan_test.go @@ -10,7 +10,6 @@ import ( "os" "path" "path/filepath" - "runtime" "strings" "testing" ) @@ -18,7 +17,7 @@ import ( func TestScan(t *testing.T) { testenv.MustHaveGoBuild(t) - imports, testImports, err := ScanDir(filepath.Join(runtime.GOROOT(), "src/encoding/json"), Tags()) + imports, testImports, err := ScanDir(filepath.Join(testenv.GOROOT(t), "src/encoding/json"), Tags()) if err != nil { t.Fatal(err) } diff --git a/src/cmd/go/internal/list/list.go b/src/cmd/go/internal/list/list.go index 9cebb934bf..5fc33989cd 100644 --- a/src/cmd/go/internal/list/list.go +++ b/src/cmd/go/internal/list/list.go @@ -567,6 +567,7 @@ func runList(ctx context.Context, cmd *base.Command, args []string) { pkgOpts := load.PackageOpts{ IgnoreImports: *listFind, ModResolveTests: *listTest, + LoadVCS: cfg.BuildBuildvcs, } pkgs := load.PackagesAndErrors(ctx, pkgOpts, args) if !*listE { diff --git a/src/cmd/go/internal/load/pkg.go b/src/cmd/go/internal/load/pkg.go index 1a510b86c7..a1cfcad826 100644 --- a/src/cmd/go/internal/load/pkg.go +++ b/src/cmd/go/internal/load/pkg.go @@ -193,6 +193,18 @@ func (p *Package) Desc() string { return p.ImportPath } +// IsTestOnly reports whether p is a test-only package. +// +// A “test-only” package is one that: +// - is a test-only variant of an ordinary package, or +// - is a synthesized "main" package for a test binary, or +// - contains only _test.go files. +func (p *Package) IsTestOnly() bool { + return p.ForTest != "" || + p.Internal.TestmainGo != nil || + len(p.TestGoFiles)+len(p.XTestGoFiles) > 0 && len(p.GoFiles)+len(p.CgoFiles) == 0 +} + type PackageInternal struct { // Unexported fields are not part of the public API. Build *build.Package @@ -1932,8 +1944,12 @@ func (p *Package) load(ctx context.Context, opts PackageOpts, path string, stk * } p.Internal.Imports = imports p.collectDeps() - if p.Error == nil && p.Name == "main" && len(p.DepsErrors) == 0 { - p.setBuildInfo() + if p.Error == nil && p.Name == "main" && !p.Internal.ForceLibrary && len(p.DepsErrors) == 0 { + // TODO(bcmills): loading VCS metadata can be fairly slow. + // Consider starting this as a background goroutine and retrieving the result + // asynchronously when we're actually ready to build the package, or when we + // actually need to evaluate whether the package's metadata is stale. + p.setBuildInfo(opts.LoadVCS) } // unsafe is a fake package. @@ -2222,12 +2238,7 @@ var vcsStatusCache par.Cache // // Note that the GoVersion field is not set here to avoid encoding it twice. // It is stored separately in the binary, mostly for historical reasons. -func (p *Package) setBuildInfo() { - // TODO: build and vcs information is not embedded for executables in GOROOT. - // cmd/dist uses -gcflags=all= -ldflags=all= by default, which means these - // executables always appear stale unless the user sets the same flags. - // Perhaps it's safe to omit those flags when GO_GCFLAGS and GO_LDFLAGS - // are not set? +func (p *Package) setBuildInfo(includeVCS bool) { setPkgErrorf := func(format string, args ...any) { if p.Error == nil { p.Error = &PackageError{Err: fmt.Errorf(format, args...)} @@ -2303,57 +2314,58 @@ func (p *Package) setBuildInfo() { // Add command-line flags relevant to the build. // This is informational, not an exhaustive list. // Please keep the list sorted. - if !p.Standard { - if cfg.BuildASan { - appendSetting("-asan", "true") - } - if BuildAsmflags.present { - appendSetting("-asmflags", BuildAsmflags.String()) - } - appendSetting("-compiler", cfg.BuildContext.Compiler) - if BuildGccgoflags.present && cfg.BuildContext.Compiler == "gccgo" { - appendSetting("-gccgoflags", BuildGccgoflags.String()) - } - if BuildGcflags.present && cfg.BuildContext.Compiler == "gc" { - appendSetting("-gcflags", BuildGcflags.String()) - } - if BuildLdflags.present { - appendSetting("-ldflags", BuildLdflags.String()) - } - if cfg.BuildMSan { - appendSetting("-msan", "true") - } - if cfg.BuildRace { - appendSetting("-race", "true") - } - if tags := cfg.BuildContext.BuildTags; len(tags) > 0 { - appendSetting("-tags", strings.Join(tags, ",")) - } - cgo := "0" - if cfg.BuildContext.CgoEnabled { - cgo = "1" - } - appendSetting("CGO_ENABLED", cgo) - if cfg.BuildContext.CgoEnabled { - for _, name := range []string{"CGO_CFLAGS", "CGO_CPPFLAGS", "CGO_CXXFLAGS", "CGO_LDFLAGS"} { - appendSetting(name, cfg.Getenv(name)) - } - } - appendSetting("GOARCH", cfg.BuildContext.GOARCH) - if cfg.GOEXPERIMENT != "" { - appendSetting("GOEXPERIMENT", cfg.GOEXPERIMENT) - } - appendSetting("GOOS", cfg.BuildContext.GOOS) - if key, val := cfg.GetArchEnv(); key != "" && val != "" { - appendSetting(key, val) + if cfg.BuildASan { + appendSetting("-asan", "true") + } + if BuildAsmflags.present { + appendSetting("-asmflags", BuildAsmflags.String()) + } + appendSetting("-compiler", cfg.BuildContext.Compiler) + if gccgoflags := BuildGccgoflags.String(); gccgoflags != "" && cfg.BuildContext.Compiler == "gccgo" { + appendSetting("-gccgoflags", gccgoflags) + } + if gcflags := BuildGcflags.String(); gcflags != "" && cfg.BuildContext.Compiler == "gc" { + appendSetting("-gcflags", gcflags) + } + if ldflags := BuildLdflags.String(); ldflags != "" { + appendSetting("-ldflags", ldflags) + } + if cfg.BuildMSan { + appendSetting("-msan", "true") + } + if cfg.BuildRace { + appendSetting("-race", "true") + } + if tags := cfg.BuildContext.BuildTags; len(tags) > 0 { + appendSetting("-tags", strings.Join(tags, ",")) + } + if cfg.BuildTrimpath { + appendSetting("-trimpath", "true") + } + cgo := "0" + if cfg.BuildContext.CgoEnabled { + cgo = "1" + } + appendSetting("CGO_ENABLED", cgo) + if cfg.BuildContext.CgoEnabled { + for _, name := range []string{"CGO_CFLAGS", "CGO_CPPFLAGS", "CGO_CXXFLAGS", "CGO_LDFLAGS"} { + appendSetting(name, cfg.Getenv(name)) } } + appendSetting("GOARCH", cfg.BuildContext.GOARCH) + if cfg.RawGOEXPERIMENT != "" { + appendSetting("GOEXPERIMENT", cfg.RawGOEXPERIMENT) + } + appendSetting("GOOS", cfg.BuildContext.GOOS) + if key, val := cfg.GetArchEnv(); key != "" && val != "" { + appendSetting(key, val) + } // Add VCS status if all conditions are true: // // - -buildvcs is enabled. - // - p is contained within a main module (there may be multiple main modules - // in a workspace, but local replacements don't count). + // - p is a non-test contained within a main module (there may be multiple + // main modules in a workspace, but local replacements don't count). // - Both the current directory and p's module's root directory are contained // in the same local repository. // - We know the VCS commands needed to get the status. @@ -2365,7 +2377,7 @@ func (p *Package) setBuildInfo() { var vcsCmd *vcs.Cmd var err error const allowNesting = true - if cfg.BuildBuildvcs && p.Module != nil && p.Module.Version == "" && !p.Standard { + if includeVCS && p.Module != nil && p.Module.Version == "" && !p.Standard && !p.IsTestOnly() { repoDir, vcsCmd, err = vcs.FromDir(base.Cwd(), "", allowNesting) if err != nil && !errors.Is(err, os.ErrNotExist) { setVCSError(err) @@ -2654,6 +2666,9 @@ type PackageOpts struct { // are not be matched, and their dependencies may not be loaded. A warning // may be printed for non-literal arguments that match no main packages. MainOnly bool + + // LoadVCS controls whether we also load version-control metadata for main packages. + LoadVCS bool } // PackagesAndErrors returns the packages named by the command line arguments @@ -3007,7 +3022,7 @@ func PackagesAndErrorsOutsideModule(ctx context.Context, opts PackageOpts, args patterns := make([]string, len(args)) for i, arg := range args { if !strings.HasSuffix(arg, "@"+version) { - return nil, fmt.Errorf("%s: all arguments must have the same version (@%s)", arg, version) + return nil, fmt.Errorf("%s: all arguments must refer to packages in the same module at the same version (@%s)", arg, version) } p := arg[:len(arg)-len(version)-1] switch { diff --git a/src/cmd/go/internal/load/test.go b/src/cmd/go/internal/load/test.go index 6122428c9c..39f1131a43 100644 --- a/src/cmd/go/internal/load/test.go +++ b/src/cmd/go/internal/load/test.go @@ -368,9 +368,9 @@ func TestPackagesAndErrors(ctx context.Context, opts PackageOpts, p *Package, co if err != nil && pmain.Error == nil { pmain.Error = &PackageError{Err: err} } - if data != nil { - pmain.Internal.TestmainGo = &data - } + // Set TestmainGo even if it is empty: the presence of a TestmainGo + // indicates that this package is, in fact, a test main. + pmain.Internal.TestmainGo = &data return pmain, ptest, pxtest } diff --git a/src/cmd/go/internal/modfetch/codehost/codehost.go b/src/cmd/go/internal/modfetch/codehost/codehost.go index 4a0e2241e5..d8d4392baa 100644 --- a/src/cmd/go/internal/modfetch/codehost/codehost.go +++ b/src/cmd/go/internal/modfetch/codehost/codehost.go @@ -83,13 +83,6 @@ type RevInfo struct { Tags []string // known tags for commit } -// A FileRev describes the result of reading a file at a given revision. -type FileRev struct { - Rev string // requested revision - Data []byte // file data - Err error // error if any; os.IsNotExist(Err)==true if rev exists but file does not exist in that rev -} - // UnknownRevisionError is an error equivalent to fs.ErrNotExist, but for a // revision rather than a file. type UnknownRevisionError struct { diff --git a/src/cmd/go/internal/run/run.go b/src/cmd/go/internal/run/run.go index 312b49ef5d..35c5783373 100644 --- a/src/cmd/go/internal/run/run.go +++ b/src/cmd/go/internal/run/run.go @@ -52,6 +52,10 @@ for example 'go_js_wasm_exec a.out arguments...'. This allows execution of cross-compiled programs when a simulator or other execution method is available. +By default, 'go run' compiles the binary without generating the information +used by debuggers, to reduce build time. To include debugger information in +the binary, use 'go build'. + The exit status of Run is not the exit status of the compiled binary. For more about build flags, see 'go help build'. diff --git a/src/cmd/go/internal/test/flagdefs_test.go b/src/cmd/go/internal/test/flagdefs_test.go index 40dc558e90..f74f3c18f7 100644 --- a/src/cmd/go/internal/test/flagdefs_test.go +++ b/src/cmd/go/internal/test/flagdefs_test.go @@ -5,13 +5,19 @@ package test import ( + "cmd/go/internal/cfg" "cmd/go/internal/test/internal/genflags" "flag" + "internal/testenv" "reflect" "strings" "testing" ) +func TestMain(m *testing.M) { + cfg.SetGOROOT(testenv.GOROOT(nil)) +} + func TestPassFlagToTestIncludesAllTestFlags(t *testing.T) { flag.VisitAll(func(f *flag.Flag) { if !strings.HasPrefix(f.Name, "test.") { diff --git a/src/cmd/go/internal/vcs/vcs.go b/src/cmd/go/internal/vcs/vcs.go index fd521b2eb1..2acabf7aaf 100644 --- a/src/cmd/go/internal/vcs/vcs.go +++ b/src/cmd/go/internal/vcs/vcs.go @@ -312,7 +312,7 @@ func gitStatus(vcsGit *Cmd, rootDir string) (Status, error) { // uncommitted files and skip tagging revision / committime. var rev string var commitTime time.Time - out, err = vcsGit.runOutputVerboseOnly(rootDir, "show -s --no-show-signature --format=%H:%ct") + out, err = vcsGit.runOutputVerboseOnly(rootDir, "-c log.showsignature=false show -s --format=%H:%ct") if err != nil && !uncommitted { return Status{}, err } else if err == nil { diff --git a/src/cmd/go/internal/work/build.go b/src/cmd/go/internal/work/build.go index 0b5848a77d..42f052d341 100644 --- a/src/cmd/go/internal/work/build.go +++ b/src/cmd/go/internal/work/build.go @@ -371,7 +371,7 @@ func oneMainPkg(pkgs []*load.Package) []*load.Package { var pkgsFilter = func(pkgs []*load.Package) []*load.Package { return pkgs } -var runtimeVersion = runtime.Version() +var RuntimeVersion = runtime.Version() func runBuild(ctx context.Context, cmd *base.Command, args []string) { modload.InitWorkfile() @@ -379,7 +379,7 @@ func runBuild(ctx context.Context, cmd *base.Command, args []string) { var b Builder b.Init() - pkgs := load.PackagesAndErrors(ctx, load.PackageOpts{}, args) + pkgs := load.PackagesAndErrors(ctx, load.PackageOpts{LoadVCS: cfg.BuildBuildvcs}, args) load.CheckPackageErrors(pkgs) explicitO := len(cfg.BuildO) > 0 @@ -603,7 +603,7 @@ func runInstall(ctx context.Context, cmd *base.Command, args []string) { modload.InitWorkfile() BuildInit() - pkgs := load.PackagesAndErrors(ctx, load.PackageOpts{}, args) + pkgs := load.PackagesAndErrors(ctx, load.PackageOpts{LoadVCS: cfg.BuildBuildvcs}, args) if cfg.ModulesEnabled && !modload.HasModRoot() { haveErrors := false allMissingErrors := true diff --git a/src/cmd/go/internal/work/exec.go b/src/cmd/go/internal/work/exec.go index ac80f503cd..6d6837aa8a 100644 --- a/src/cmd/go/internal/work/exec.go +++ b/src/cmd/go/internal/work/exec.go @@ -12,7 +12,6 @@ import ( "encoding/json" "errors" "fmt" - "internal/buildcfg" exec "internal/execabs" "internal/lazyregexp" "io" @@ -320,8 +319,8 @@ func (b *Builder) buildActionID(a *Action) cache.ActionID { key, val := cfg.GetArchEnv() fmt.Fprintf(h, "%s=%s\n", key, val) - if goexperiment := buildcfg.GOEXPERIMENT(); goexperiment != "" { - fmt.Fprintf(h, "GOEXPERIMENT=%q\n", goexperiment) + if cfg.CleanGOEXPERIMENT != "" { + fmt.Fprintf(h, "GOEXPERIMENT=%q\n", cfg.CleanGOEXPERIMENT) } // TODO(rsc): Convince compiler team not to add more magic environment variables, @@ -560,7 +559,7 @@ func (b *Builder) build(ctx context.Context, a *Action) (err error) { return nil } - if err := allowInstall(a); err != nil { + if err := AllowInstall(a); err != nil { return err } @@ -1301,8 +1300,8 @@ func (b *Builder) printLinkerConfig(h io.Writer, p *load.Package) { key, val := cfg.GetArchEnv() fmt.Fprintf(h, "%s=%s\n", key, val) - if goexperiment := buildcfg.GOEXPERIMENT(); goexperiment != "" { - fmt.Fprintf(h, "GOEXPERIMENT=%q\n", goexperiment) + if cfg.CleanGOEXPERIMENT != "" { + fmt.Fprintf(h, "GOEXPERIMENT=%q\n", cfg.CleanGOEXPERIMENT) } // The linker writes source file paths that say GOROOT_FINAL, but @@ -1346,7 +1345,7 @@ func (b *Builder) link(ctx context.Context, a *Action) (err error) { return err } - if err := allowInstall(a); err != nil { + if err := AllowInstall(a); err != nil { return err } @@ -1527,7 +1526,7 @@ func (b *Builder) getPkgConfigFlags(p *load.Package) (cflags, ldflags []string, } func (b *Builder) installShlibname(ctx context.Context, a *Action) error { - if err := allowInstall(a); err != nil { + if err := AllowInstall(a); err != nil { return err } @@ -1581,7 +1580,7 @@ func (b *Builder) linkShared(ctx context.Context, a *Action) (err error) { } defer b.flushOutput(a) - if err := allowInstall(a); err != nil { + if err := AllowInstall(a); err != nil { return err } @@ -1652,7 +1651,7 @@ func BuildInstallFunc(b *Builder, ctx context.Context, a *Action) (err error) { if !a.buggyInstall && !b.IsCmdList { if cfg.BuildN { b.Showcmd("", "touch %s", a.Target) - } else if err := allowInstall(a); err == nil { + } else if err := AllowInstall(a); err == nil { now := time.Now() os.Chtimes(a.Target, now, now) } @@ -1666,7 +1665,7 @@ func BuildInstallFunc(b *Builder, ctx context.Context, a *Action) (err error) { a.built = a1.built return nil } - if err := allowInstall(a); err != nil { + if err := AllowInstall(a); err != nil { return err } @@ -1698,12 +1697,12 @@ func BuildInstallFunc(b *Builder, ctx context.Context, a *Action) (err error) { return b.moveOrCopyFile(a.Target, a1.built, perm, false) } -// allowInstall returns a non-nil error if this invocation of the go command is +// AllowInstall returns a non-nil error if this invocation of the go command is // allowed to install a.Target. // -// (The build of cmd/go running under its own test is forbidden from installing -// to its original GOROOT.) -var allowInstall = func(*Action) error { return nil } +// The build of cmd/go running under its own test is forbidden from installing +// to its original GOROOT. The var is exported so it can be set by TestMain. +var AllowInstall = func(*Action) error { return nil } // cleanup removes a's object dir to keep the amount of // on-disk garbage down in a large build. On an operating system @@ -1868,7 +1867,7 @@ func (b *Builder) installHeader(ctx context.Context, a *Action) error { return nil } - if err := allowInstall(a); err != nil { + if err := AllowInstall(a); err != nil { return err } diff --git a/src/cmd/go/internal/work/gc.go b/src/cmd/go/internal/work/gc.go index 40175324d2..fdde3b289f 100644 --- a/src/cmd/go/internal/work/gc.go +++ b/src/cmd/go/internal/work/gc.go @@ -8,7 +8,6 @@ import ( "bufio" "bytes" "fmt" - "internal/buildcfg" "io" "log" "os" @@ -28,7 +27,7 @@ import ( ) // The 'path' used for GOROOT_FINAL when -trimpath is specified -const trimPathGoRootFinal = "go" +const trimPathGoRootFinal string = "$GOROOT" var runtimePackages = map[string]struct{}{ "internal/abi": struct{}{}, @@ -137,8 +136,8 @@ func (gcToolchain) gc(b *Builder, a *Action, archive string, importcfg, embedcfg if p.Internal.OmitDebug || cfg.Goos == "plan9" || cfg.Goarch == "wasm" { defaultGcFlags = append(defaultGcFlags, "-dwarf=false") } - if strings.HasPrefix(runtimeVersion, "go1") && !strings.Contains(os.Args[0], "go_bootstrap") { - defaultGcFlags = append(defaultGcFlags, "-goversion", runtimeVersion) + if strings.HasPrefix(RuntimeVersion, "go1") && !strings.Contains(os.Args[0], "go_bootstrap") { + defaultGcFlags = append(defaultGcFlags, "-goversion", RuntimeVersion) } if symabis != "" { defaultGcFlags = append(defaultGcFlags, "-symabis", symabis) @@ -245,7 +244,7 @@ CheckFlags: } // TODO: Test and delete these conditions. - if buildcfg.Experiment.FieldTrack || buildcfg.Experiment.PreemptibleLoops { + if cfg.ExperimentErr != nil || cfg.Experiment.FieldTrack || cfg.Experiment.PreemptibleLoops { canDashC = false } diff --git a/src/cmd/go/internal/work/testgo.go b/src/cmd/go/internal/work/testgo.go deleted file mode 100644 index a09b65a23c..0000000000 --- a/src/cmd/go/internal/work/testgo.go +++ /dev/null @@ -1,48 +0,0 @@ -// Copyright 2017 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. - -// This file contains extra hooks for testing the go command. - -//go:build testgo - -package work - -import ( - "cmd/go/internal/cfg" - "cmd/go/internal/search" - "fmt" - "os" - "path/filepath" - "runtime" -) - -func init() { - if v := os.Getenv("TESTGO_VERSION"); v != "" { - runtimeVersion = v - } - - if testGOROOT := os.Getenv("TESTGO_GOROOT"); testGOROOT != "" { - // Disallow installs to the GOROOT from which testgo was built. - // Installs to other GOROOTs — such as one set explicitly within a test — are ok. - allowInstall = func(a *Action) error { - if cfg.BuildN { - return nil - } - - rel := search.InDir(a.Target, testGOROOT) - if rel == "" { - return nil - } - - callerPos := "" - if _, file, line, ok := runtime.Caller(1); ok { - if shortFile := search.InDir(file, filepath.Join(testGOROOT, "src")); shortFile != "" { - file = shortFile - } - callerPos = fmt.Sprintf("%s:%d: ", file, line) - } - return fmt.Errorf("%stestgo must not write to GOROOT (installing to %s)", callerPos, filepath.Join("GOROOT", rel)) - } - } -} diff --git a/src/cmd/go/main.go b/src/cmd/go/main.go index c0a1d3ccfc..ee705e87e0 100644 --- a/src/cmd/go/main.go +++ b/src/cmd/go/main.go @@ -142,6 +142,10 @@ func main() { } } + if cfg.GOROOT == "" { + fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: 'go' binary is trimmed and GOROOT is not set\n") + os.Exit(2) + } if fi, err := os.Stat(cfg.GOROOT); err != nil || !fi.IsDir() { fmt.Fprintf(os.Stderr, "go: cannot find GOROOT directory: %v\n", cfg.GOROOT) os.Exit(2) @@ -190,6 +194,9 @@ func invoke(cmd *base.Command, args []string) { // 'go env' handles checking the build config if cmd != envcmd.CmdEnv { buildcfg.Check() + if cfg.ExperimentErr != nil { + base.Fatalf("go: %v", cfg.ExperimentErr) + } } // Set environment (GOOS, GOARCH, etc) explicitly. diff --git a/src/cmd/go/proxy_test.go b/src/cmd/go/proxy_test.go index 517a885542..fc256968b7 100644 --- a/src/cmd/go/proxy_test.go +++ b/src/cmd/go/proxy_test.go @@ -11,6 +11,7 @@ import ( "errors" "flag" "fmt" + "internal/txtar" "io" "io/fs" "log" @@ -30,7 +31,6 @@ import ( "golang.org/x/mod/semver" "golang.org/x/mod/sumdb" "golang.org/x/mod/sumdb/dirhash" - "golang.org/x/tools/txtar" ) var ( diff --git a/src/cmd/go/script_test.go b/src/cmd/go/script_test.go index 55a88e0e0b..bffbe32220 100644 --- a/src/cmd/go/script_test.go +++ b/src/cmd/go/script_test.go @@ -15,12 +15,14 @@ import ( "fmt" "go/build" "internal/testenv" + "internal/txtar" "io/fs" "os" "os/exec" "path/filepath" "regexp" "runtime" + "runtime/debug" "strconv" "strings" "sync" @@ -33,8 +35,6 @@ import ( "cmd/go/internal/robustio" "cmd/go/internal/work" "cmd/internal/sys" - - "golang.org/x/tools/txtar" ) var testSum = flag.String("testsum", "", `may be tidy, listm, or listall. If set, TestScript generates a go.sum file at the beginning of each test and updates test files if they pass.`) @@ -188,6 +188,7 @@ func (ts *testScript) setup() { "goversion=" + goVersion(ts), ":=" + string(os.PathListSeparator), "/=" + string(os.PathSeparator), + "CMDGO_TEST_RUN_MAIN=true", } if !testenv.HasExternalNetwork() { ts.env = append(ts.env, "TESTGONETWORK=panic", "TESTGOVCS=panic") @@ -373,6 +374,17 @@ Script: ok = testenv.HasSymlink() case "case-sensitive": ok = isCaseSensitive(ts.t) + case "trimpath": + if info, _ := debug.ReadBuildInfo(); info == nil { + ts.fatalf("missing build info") + } else { + for _, s := range info.Settings { + if s.Key == "-trimpath" && s.Value == "true" { + ok = true + break + } + } + } default: if strings.HasPrefix(cond.tag, "exec:") { prog := cond.tag[len("exec:"):] diff --git a/src/cmd/go/testdata/addmod.go b/src/cmd/go/testdata/addmod.go index eac2a7ad44..41997a52ff 100644 --- a/src/cmd/go/testdata/addmod.go +++ b/src/cmd/go/testdata/addmod.go @@ -24,13 +24,12 @@ import ( "flag" "fmt" exec "internal/execabs" + "internal/txtar" "io/fs" "log" "os" "path/filepath" "strings" - - "golang.org/x/tools/txtar" ) func usage() { diff --git a/src/cmd/go/testdata/savedir.go b/src/cmd/go/testdata/savedir.go index 53c78cfb00..eaafc5e493 100644 --- a/src/cmd/go/testdata/savedir.go +++ b/src/cmd/go/testdata/savedir.go @@ -18,14 +18,13 @@ package main import ( "flag" "fmt" + "internal/txtar" "io/fs" "log" "os" "path/filepath" "strings" "unicode/utf8" - - "golang.org/x/tools/txtar" ) func usage() { diff --git a/src/cmd/go/testdata/script/README b/src/cmd/go/testdata/script/README index b2a7fd1915..17b582d662 100644 --- a/src/cmd/go/testdata/script/README +++ b/src/cmd/go/testdata/script/README @@ -7,7 +7,7 @@ In general script files should have short names: a few words, not whole sentence The first word should be the general category of behavior being tested, often the name of a go subcommand (list, build, test, ...) or concept (vendor, pattern). -Each script is a text archive (go doc cmd/go/internal/txtar). +Each script is a text archive (go doc internal/txtar). The script begins with an actual command script to run followed by the content of zero or more supporting files to create in the script's temporary file system before it starts executing. diff --git a/src/cmd/go/testdata/script/build_trimpath_goroot.txt b/src/cmd/go/testdata/script/build_trimpath_goroot.txt new file mode 100644 index 0000000000..7b870ab739 --- /dev/null +++ b/src/cmd/go/testdata/script/build_trimpath_goroot.txt @@ -0,0 +1,68 @@ +# Regression test for https://go.dev/issue/51461 and https://go.dev/issue/51483. +# +# When built with -trimpath, runtime.GOROOT() returned the bogus string "go" +# if GOROOT was not set explicitly in the environment. +# It should instead return the empty string, since we know that we don't +# have a valid path to return. +# +# TODO(#51483): when runtime.GOROOT() returns the empty string, +# go/build should default to 'go env GOROOT' instead. + +env GOROOT= +env GOROOT_FINAL= + +[trimpath] ! go env GOROOT +[trimpath] stderr '^go: cannot find GOROOT directory: ''go'' binary is trimmed and GOROOT is not set$' +[trimpath] stop + + +[short] skip + +go run . +stdout '^GOROOT '$TESTGO_GOROOT'$' +stdout '^runtime '$TESTGO_GOROOT${/}src${/}runtime'$' + +go test -v . +stdout '^GOROOT '$TESTGO_GOROOT'$' +stdout '^runtime '$TESTGO_GOROOT${/}src${/}runtime'$' + +! go run -trimpath . +stdout '^GOROOT $' +stderr 'cannot find package "runtime" in any of:\n\t\(\$GOROOT not set\)\n\t'$WORK${/}gopath${/}src${/}runtime' \(from \$GOPATH\)\nexit status 1\n\z' + +! go test -trimpath -v . +stdout '^GOROOT $' +stdout 'cannot find package "runtime" in any of:\n\t\(\$GOROOT not set\)\n\t'$WORK${/}gopath${/}src${/}runtime' \(from \$GOPATH\)$' + +-- go.mod -- +module example + +go 1.19 +-- main.go -- +package main + +import ( + "fmt" + "go/build" + "os" + "runtime" +) + +func main() { + fmt.Println("GOROOT", runtime.GOROOT()) + + p, err := build.Default.Import("runtime", "", build.FindOnly) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + fmt.Println("runtime", p.Dir) +} +-- main_test.go -- +package main + +import "testing" + +func TestMain(*testing.M) { + main() +} diff --git a/src/cmd/go/testdata/script/fmt_load_errors.txt b/src/cmd/go/testdata/script/fmt_load_errors.txt index 84bf41cfba..e3a9034ede 100644 --- a/src/cmd/go/testdata/script/fmt_load_errors.txt +++ b/src/cmd/go/testdata/script/fmt_load_errors.txt @@ -7,16 +7,19 @@ stdout 'exclude[/\\]x\.go' stdout 'exclude[/\\]x_linux\.go' # Test edge cases with gofmt. -# Note that this execs GOROOT/bin/gofmt. -! exec gofmt does-not-exist +! exec $GOROOT/bin/gofmt does-not-exist -exec gofmt gofmt-dir/no-extension +exec $GOROOT/bin/gofmt gofmt-dir/no-extension stdout 'package x' -exec gofmt gofmt-dir +exec $GOROOT/bin/gofmt gofmt-dir ! stdout 'package x' +! exec $GOROOT/bin/gofmt empty.go nopackage.go +stderr -count=1 'empty\.go:1:1: expected .package., found .EOF.' +stderr -count=1 'nopackage\.go:1:1: expected .package., found not' + -- exclude/empty/x.txt -- -- exclude/ignore/_x.go -- package x @@ -30,3 +33,6 @@ package x package x -- gofmt-dir/no-extension -- package x +-- empty.go -- +-- nopackage.go -- +not the proper start to a Go file diff --git a/src/cmd/go/testdata/script/list_swigcxx.txt b/src/cmd/go/testdata/script/list_swigcxx.txt index d4227a80e8..4220487a28 100644 --- a/src/cmd/go/testdata/script/list_swigcxx.txt +++ b/src/cmd/go/testdata/script/list_swigcxx.txt @@ -6,7 +6,7 @@ # CompiledGoFiles should contain 4 files: # a.go -# a.swigcxx.go +# _cgo_import.go [gc only] # _cgo_gotypes.go # a.cgo1.go # @@ -16,7 +16,8 @@ go list -f '{{.CompiledGoFiles}}' -compiled=true example/swig stdout a\.go -stdout -count=3 $GOCACHE +[gc] stdout -count=3 $GOCACHE +[gccgo] stdout -count=2 $GOCACHE -- go.mod -- module example diff --git a/src/cmd/go/testdata/script/mod_doc_path.txt b/src/cmd/go/testdata/script/mod_doc_path.txt new file mode 100644 index 0000000000..57470a95c4 --- /dev/null +++ b/src/cmd/go/testdata/script/mod_doc_path.txt @@ -0,0 +1,30 @@ +# cmd/doc should use GOROOT to locate the 'go' command, +# not use whatever is in $PATH. + +# Remove 'go' from $PATH. (It can still be located via $GOROOT/bin/go, and the +# test script's built-in 'go' command still knows where to find it.) +env PATH='' +[plan9] env path='' + +go doc p.X + +-- go.mod -- +module example + +go 1.19 + +require example.com/p v0.1.0 + +replace example.com/p => ./pfork +-- example.go -- +package example + +import _ "example.com/p" +-- pfork/go.mod -- +module example.com/p + +go 1.19 +-- pfork/p.go -- +package p + +const X = 42 diff --git a/src/cmd/go/testdata/script/mod_install_pkg_version.txt b/src/cmd/go/testdata/script/mod_install_pkg_version.txt index 14153b8e9e..e3f59fc152 100644 --- a/src/cmd/go/testdata/script/mod_install_pkg_version.txt +++ b/src/cmd/go/testdata/script/mod_install_pkg_version.txt @@ -106,7 +106,7 @@ stdout '^example.com/cmd v1.0.0$' env GO111MODULE=auto ! go install example.com/cmd/a@v1.0.0 example.com/cmd/b@latest -stderr '^go: example.com/cmd/b@latest: all arguments must have the same version \(@v1.0.0\)$' +stderr '^go: example.com/cmd/b@latest: all arguments must refer to packages in the same module at the same version \(@v1.0.0\)$' # 'go install pkg@version' should report an error if the arguments are in diff --git a/src/cmd/go/testdata/script/test_buildvcs.txt b/src/cmd/go/testdata/script/test_buildvcs.txt new file mode 100644 index 0000000000..a0689195e8 --- /dev/null +++ b/src/cmd/go/testdata/script/test_buildvcs.txt @@ -0,0 +1,92 @@ +# https://go.dev/issue/51723: 'go test' should not stamp VCS metadata +# in the build settings. (It isn't worth the latency hit, given that +# test binaries are almost never distributed to users.) + +[short] skip +[!exec:git] skip + +exec git init + +# The test binaries should not have VCS settings stamped. +# (The test itself verifies that.) +go test . ./testonly + + +# Remove 'git' from $PATH. The test should still build. +# This ensures that we aren't loading VCS metadata that +# we subsequently throw away. +env PATH='' +env path='' + +# Compiling the test should not require the VCS tool. +go test -c -o $devnull . + + +# When listing a main package, in general we need its VCS metadata to determine +# the .Stale and .StaleReason fields. +! go list . +stderr '^go: missing Git command\. See https://golang\.org/s/gogetcmd\nerror obtaining VCS status: .*\n\tUse -buildvcs=false to disable VCS stamping.' + +# Adding the -test flag should be strictly additive — it should not suppress the error. +! go list -test . +stderr '^go: missing Git command\. See https://golang\.org/s/gogetcmd\nerror obtaining VCS status: .*\n\tUse -buildvcs=false to disable VCS stamping.' + +# Adding the suggested flag should suppress the error. +go list -test -buildvcs=false . +! stderr . + + +# Since the ./testonly package can't produce an actual binary, we shouldn't +# invoke a VCS tool to compute a build stamp when listing it. +go list ./testonly +! stderr . +go list -test ./testonly +! stderr . + + +-- go.mod -- +module example + +go 1.18 +-- example.go -- +package main +-- example_test.go -- +package main + +import ( + "runtime/debug" + "strings" + "testing" +) + +func TestDetail(t *testing.T) { + bi, ok := debug.ReadBuildInfo() + if !ok { + t.Fatal("BuildInfo not present") + } + for _, s := range bi.Settings { + if strings.HasPrefix(s.Key, "vcs.") { + t.Fatalf("unexpected VCS setting: %s=%s", s.Key, s.Value) + } + } +} +-- testonly/main_test.go -- +package main + +import ( + "runtime/debug" + "strings" + "testing" +) + +func TestDetail(t *testing.T) { + bi, ok := debug.ReadBuildInfo() + if !ok { + t.Fatal("BuildInfo not present") + } + for _, s := range bi.Settings { + if strings.HasPrefix(s.Key, "vcs.") { + t.Fatalf("unexpected VCS setting: %s=%s", s.Key, s.Value) + } + } +} diff --git a/src/cmd/go/testdata/script/test_fuzz_minimize_dirty_cov.txt b/src/cmd/go/testdata/script/test_fuzz_minimize_dirty_cov.txt new file mode 100644 index 0000000000..571bf752d0 --- /dev/null +++ b/src/cmd/go/testdata/script/test_fuzz_minimize_dirty_cov.txt @@ -0,0 +1,84 @@ +# Test that minimization doesn't use dirty coverage snapshots when it +# is unable to actually minimize the input. We do this by checking that +# a expected value appears in the cache. If a dirty coverage map is used +# (i.e. the coverage map generated during the last minimization step, +# rather than the map provided with the initial input) then this value +# is unlikely to appear in the cache, since the map generated during +# the last minimization step should not increase the coverage. + +[short] skip +[!fuzz-instrumented] skip + +env GOCACHE=$WORK/gocache +go test -fuzz=FuzzCovMin -fuzztime=25s -test.fuzzcachedir=$GOCACHE/fuzz +go run check_file/main.go $GOCACHE/fuzz/FuzzCovMin abcd + +-- go.mod -- +module test + +-- covmin_test.go -- +package covmin + +import "testing" + +func FuzzCovMin(f *testing.F) { + f.Fuzz(func(t *testing.T, data []byte) { + if len(data) >= 4 && data[0] == 'a' && data[1] == 'b' && data[2] == 'c' && data[3] == 'd' { + return + } + }) +} + +-- check_file/main.go -- +package main + +import ( + "bytes" + "fmt" + "os" + "path/filepath" + "regexp" + "strconv" +) + +func checkFile(name, expected string) (bool, error) { + data, err := os.ReadFile(name) + if err != nil { + return false, err + } + for _, line := range bytes.Split(data, []byte("\n")) { + m := valRe.FindSubmatch(line) + if m == nil { + continue + } + fmt.Println(strconv.Unquote(string(m[1]))) + if s, err := strconv.Unquote(string(m[1])); err != nil { + return false, err + } else if s == expected { + return true, nil + } + } + return false, nil +} + +var valRe = regexp.MustCompile(`^\[\]byte\(([^)]+)\)$`) + +func main() { + dir, expected := os.Args[1], os.Args[2] + ents, err := os.ReadDir(dir) + if err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } + for _, ent := range ents { + name := filepath.Join(dir, ent.Name()) + if good, err := checkFile(name, expected); err != nil { + fmt.Fprintln(os.Stderr, err) + os.Exit(1) + } else if good { + os.Exit(0) + } + } + fmt.Fprintln(os.Stderr, "input over minimized") + os.Exit(1) +} diff --git a/src/cmd/go/testdata/script/test_fuzz_minimize_interesting.txt b/src/cmd/go/testdata/script/test_fuzz_minimize_interesting.txt index 5d0de17f6b..a09e85b972 100644 --- a/src/cmd/go/testdata/script/test_fuzz_minimize_interesting.txt +++ b/src/cmd/go/testdata/script/test_fuzz_minimize_interesting.txt @@ -127,19 +127,8 @@ func FuzzMinCache(f *testing.F) { if bytes.Equal(buf, seed) { return } - if n := sum(buf); n < 0 { - t.Error("sum cannot be negative") - } }) } - -func sum(buf []byte) int { - n := 0 - for _, b := range buf { - n += int(b) - } - return n -} -- check_testdata/check_testdata.go -- //go:build ignore // +build ignore diff --git a/src/cmd/go/testdata/script/version_build_settings.txt b/src/cmd/go/testdata/script/version_build_settings.txt index dc9e67681e..90c7253764 100644 --- a/src/cmd/go/testdata/script/version_build_settings.txt +++ b/src/cmd/go/testdata/script/version_build_settings.txt @@ -23,6 +23,10 @@ go build -ldflags=example.com/m=-w go version -m m$GOEXE stdout '^\tbuild\t-ldflags=example\.com/m=-w$' +go build -trimpath +go version -m m$GOEXE +stdout '\tbuild\t-trimpath=true$' + # gccgoflags are not added when gc is used, and vice versa. # TODO: test gccgo. go build -gccgoflags=all=UNUSED diff --git a/src/cmd/go/testdata/script/version_buildvcs_git.txt b/src/cmd/go/testdata/script/version_buildvcs_git.txt index 86d1de06df..44706870e2 100644 --- a/src/cmd/go/testdata/script/version_buildvcs_git.txt +++ b/src/cmd/go/testdata/script/version_buildvcs_git.txt @@ -111,7 +111,7 @@ rm $GOBIN/d$GOEXE go list -x ./... stdout -count=3 '^example.com' stderr -count=1 '^git status' -stderr -count=1 '^git show' +stderr -count=1 '^git -c log.showsignature=false show' -- $WORK/fakebin/git -- #!/bin/sh diff --git a/src/cmd/gofmt/gofmt.go b/src/cmd/gofmt/gofmt.go index 4280ed4459..5fa883fb56 100644 --- a/src/cmd/gofmt/gofmt.go +++ b/src/cmd/gofmt/gofmt.go @@ -14,6 +14,7 @@ import ( "go/printer" "go/scanner" "go/token" + "internal/diff" "io" "io/fs" "os" @@ -22,8 +23,6 @@ import ( "runtime/pprof" "strings" - "cmd/internal/diff" - "golang.org/x/sync/semaphore" ) @@ -287,12 +286,9 @@ func processFile(filename string, info fs.FileInfo, in io.Reader, r *reporter) e } } if *doDiff { - data, err := diffWithReplaceTempFile(src, res, filename) - if err != nil { - return fmt.Errorf("computing diff: %s", err) - } - fmt.Fprintf(r, "diff -u %s %s\n", filepath.ToSlash(filename+".orig"), filepath.ToSlash(filename)) - r.Write(data) + newName := filepath.ToSlash(filename) + oldName := newName + ".orig" + r.Write(diff.Diff(oldName, src, newName, res)) } } @@ -351,7 +347,12 @@ func readFile(filename string, info fs.FileInfo, in io.Reader) ([]byte, error) { // stop to avoid corrupting it.) src := make([]byte, size+1) n, err := io.ReadFull(in, src) - if err != nil && err != io.ErrUnexpectedEOF { + switch err { + case nil, io.EOF, io.ErrUnexpectedEOF: + // io.ReadFull returns io.EOF (for an empty file) or io.ErrUnexpectedEOF + // (for a non-empty file) if the file was changed unexpectedly. Continue + // with comparing file sizes in those cases. + default: return nil, err } if n < size { @@ -464,43 +465,6 @@ func fileWeight(path string, info fs.FileInfo) int64 { return info.Size() } -func diffWithReplaceTempFile(b1, b2 []byte, filename string) ([]byte, error) { - data, err := diff.Diff("gofmt", b1, b2) - if len(data) > 0 { - return replaceTempFilename(data, filename) - } - return data, err -} - -// replaceTempFilename replaces temporary filenames in diff with actual one. -// -// --- /tmp/gofmt316145376 2017-02-03 19:13:00.280468375 -0500 -// +++ /tmp/gofmt617882815 2017-02-03 19:13:00.280468375 -0500 -// ... -// -> -// --- path/to/file.go.orig 2017-02-03 19:13:00.280468375 -0500 -// +++ path/to/file.go 2017-02-03 19:13:00.280468375 -0500 -// ... -func replaceTempFilename(diff []byte, filename string) ([]byte, error) { - bs := bytes.SplitN(diff, []byte{'\n'}, 3) - if len(bs) < 3 { - return nil, fmt.Errorf("got unexpected diff for %s", filename) - } - // Preserve timestamps. - var t0, t1 []byte - if i := bytes.LastIndexByte(bs[0], '\t'); i != -1 { - t0 = bs[0][i:] - } - if i := bytes.LastIndexByte(bs[1], '\t'); i != -1 { - t1 = bs[1][i:] - } - // Always print filepath with slash separator. - f := filepath.ToSlash(filename) - bs[0] = []byte(fmt.Sprintf("--- %s%s", f+".orig", t0)) - bs[1] = []byte(fmt.Sprintf("+++ %s%s", f, t1)) - return bytes.Join(bs, []byte{'\n'}), nil -} - const chmodSupported = runtime.GOOS != "windows" // backupFile writes data to a new file named filename with permissions perm, diff --git a/src/cmd/gofmt/gofmt_test.go b/src/cmd/gofmt/gofmt_test.go index 676c5b43ed..641e0ea415 100644 --- a/src/cmd/gofmt/gofmt_test.go +++ b/src/cmd/gofmt/gofmt_test.go @@ -7,10 +7,9 @@ package main import ( "bytes" "flag" + "internal/diff" "os" - "os/exec" "path/filepath" - "runtime" "strings" "testing" "text/scanner" @@ -119,11 +118,8 @@ func runTest(t *testing.T, in, out string) { t.Errorf("WARNING: -update did not rewrite input file %s", in) } - t.Errorf("(gofmt %s) != %s (see %s.gofmt)", in, out, in) - d, err := diffWithReplaceTempFile(expected, got, in) - if err == nil { - t.Errorf("%s", d) - } + t.Errorf("(gofmt %s) != %s (see %s.gofmt)\n%s", in, out, in, + diff.Diff("expected", expected, "got", got)) if err := os.WriteFile(in+".gofmt", got, 0666); err != nil { t.Error(err) } @@ -194,69 +190,3 @@ func TestBackupFile(t *testing.T) { } t.Logf("Created: %s", name) } - -func TestDiff(t *testing.T) { - if _, err := exec.LookPath("diff"); err != nil { - t.Skipf("skip test on %s: diff command is required", runtime.GOOS) - } - in := []byte("first\nsecond\n") - out := []byte("first\nthird\n") - filename := "difftest.txt" - b, err := diffWithReplaceTempFile(in, out, filename) - if err != nil { - t.Fatal(err) - } - - if runtime.GOOS == "windows" { - b = bytes.ReplaceAll(b, []byte{'\r', '\n'}, []byte{'\n'}) - } - - bs := bytes.SplitN(b, []byte{'\n'}, 3) - line0, line1 := bs[0], bs[1] - - if prefix := "--- difftest.txt.orig"; !bytes.HasPrefix(line0, []byte(prefix)) { - t.Errorf("diff: first line should start with `%s`\ngot: %s", prefix, line0) - } - - if prefix := "+++ difftest.txt"; !bytes.HasPrefix(line1, []byte(prefix)) { - t.Errorf("diff: second line should start with `%s`\ngot: %s", prefix, line1) - } - - want := `@@ -1,2 +1,2 @@ - first --second -+third -` - - if got := string(bs[2]); got != want { - t.Errorf("diff: got:\n%s\nwant:\n%s", got, want) - } -} - -func TestReplaceTempFilename(t *testing.T) { - diff := []byte(`--- /tmp/tmpfile1 2017-02-08 00:53:26.175105619 +0900 -+++ /tmp/tmpfile2 2017-02-08 00:53:38.415151275 +0900 -@@ -1,2 +1,2 @@ - first --second -+third -`) - want := []byte(`--- path/to/file.go.orig 2017-02-08 00:53:26.175105619 +0900 -+++ path/to/file.go 2017-02-08 00:53:38.415151275 +0900 -@@ -1,2 +1,2 @@ - first --second -+third -`) - // Check path in diff output is always slash regardless of the - // os.PathSeparator (`/` or `\`). - sep := string(os.PathSeparator) - filename := strings.Join([]string{"path", "to", "file.go"}, sep) - got, err := replaceTempFilename(diff, filename) - if err != nil { - t.Fatal(err) - } - if !bytes.Equal(got, want) { - t.Errorf("os.PathSeparator='%s': replacedDiff:\ngot:\n%s\nwant:\n%s", sep, got, want) - } -} diff --git a/src/cmd/gofmt/long_test.go b/src/cmd/gofmt/long_test.go index 4a821705f1..2ee5174b96 100644 --- a/src/cmd/gofmt/long_test.go +++ b/src/cmd/gofmt/long_test.go @@ -15,6 +15,7 @@ import ( "go/ast" "go/printer" "go/token" + "internal/testenv" "io" "io/fs" "os" @@ -113,7 +114,8 @@ func genFilenames(t *testing.T, filenames chan<- string) { t.Error(err) return nil } - if isGoFile(d) { + // don't descend into testdata directories + if isGoFile(d) && !strings.Contains(filepath.ToSlash(filename), "/testdata/") { filenames <- filename nfiles++ } @@ -130,7 +132,11 @@ func genFilenames(t *testing.T, filenames chan<- string) { } // otherwise, test all Go files under *root - filepath.WalkDir(*root, handleFile) + goroot := *root + if goroot == "" { + goroot = testenv.GOROOT(t) + } + filepath.WalkDir(goroot, handleFile) } func TestAll(t *testing.T) { diff --git a/src/cmd/gofmt/testdata/crlf.golden b/src/cmd/gofmt/testdata/crlf.golden index 193dbacc72..65de9cf199 100644 --- a/src/cmd/gofmt/testdata/crlf.golden +++ b/src/cmd/gofmt/testdata/crlf.golden @@ -1,8 +1,8 @@ /* - Source containing CR/LF line endings. - The gofmt'ed output must only have LF - line endings. - Test case for issue 3961. +Source containing CR/LF line endings. +The gofmt'ed output must only have LF +line endings. +Test case for issue 3961. */ package main diff --git a/src/cmd/gofmt/testdata/crlf.input b/src/cmd/gofmt/testdata/crlf.input index ae7e14dbf1..3cd4934caf 100644 --- a/src/cmd/gofmt/testdata/crlf.input +++ b/src/cmd/gofmt/testdata/crlf.input @@ -1,8 +1,8 @@ /* - Source containing CR/LF line endings. - The gofmt'ed output must only have LF - line endings. - Test case for issue 3961. +Source containing CR/LF line endings. +The gofmt'ed output must only have LF +line endings. +Test case for issue 3961. */ package main diff --git a/src/cmd/gofmt/testdata/typeswitch.golden b/src/cmd/gofmt/testdata/typeswitch.golden index 2b1905edd3..3cf4dca7d4 100644 --- a/src/cmd/gofmt/testdata/typeswitch.golden +++ b/src/cmd/gofmt/testdata/typeswitch.golden @@ -1,17 +1,17 @@ /* - Parenthesized type switch expressions originally - accepted by gofmt must continue to be rewritten - into the correct unparenthesized form. +Parenthesized type switch expressions originally +accepted by gofmt must continue to be rewritten +into the correct unparenthesized form. - Only type-switches that didn't declare a variable - in the type switch type assertion and which - contained only "expression-like" (named) types in their - cases were permitted to have their type assertion parenthesized - by go/parser (due to a weak predicate in the parser). All others - were rejected always, either with a syntax error in the - type switch header or in the case. +Only type-switches that didn't declare a variable +in the type switch type assertion and which +contained only "expression-like" (named) types in their +cases were permitted to have their type assertion parenthesized +by go/parser (due to a weak predicate in the parser). All others +were rejected always, either with a syntax error in the +type switch header or in the case. - See also issue 4470. +See also issue 4470. */ package p diff --git a/src/cmd/gofmt/testdata/typeswitch.input b/src/cmd/gofmt/testdata/typeswitch.input index 8f8cba9b85..992a772d52 100644 --- a/src/cmd/gofmt/testdata/typeswitch.input +++ b/src/cmd/gofmt/testdata/typeswitch.input @@ -1,17 +1,17 @@ /* - Parenthesized type switch expressions originally - accepted by gofmt must continue to be rewritten - into the correct unparenthesized form. +Parenthesized type switch expressions originally +accepted by gofmt must continue to be rewritten +into the correct unparenthesized form. - Only type-switches that didn't declare a variable - in the type switch type assertion and which - contained only "expression-like" (named) types in their - cases were permitted to have their type assertion parenthesized - by go/parser (due to a weak predicate in the parser). All others - were rejected always, either with a syntax error in the - type switch header or in the case. +Only type-switches that didn't declare a variable +in the type switch type assertion and which +contained only "expression-like" (named) types in their +cases were permitted to have their type assertion parenthesized +by go/parser (due to a weak predicate in the parser). All others +were rejected always, either with a syntax error in the +type switch header or in the case. - See also issue 4470. +See also issue 4470. */ package p diff --git a/src/cmd/internal/archive/archive_test.go b/src/cmd/internal/archive/archive_test.go index c284a9cf0d..9573495dec 100644 --- a/src/cmd/internal/archive/archive_test.go +++ b/src/cmd/internal/archive/archive_test.go @@ -109,11 +109,11 @@ func buildGoobj() error { go1src := filepath.Join("testdata", "go1.go") go2src := filepath.Join("testdata", "go2.go") - out, err := exec.Command(gotool, "tool", "compile", "-o", go1obj, go1src).CombinedOutput() + out, err := exec.Command(gotool, "tool", "compile", "-p=p", "-o", go1obj, go1src).CombinedOutput() if err != nil { return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go1obj, go1src, err, out) } - out, err = exec.Command(gotool, "tool", "compile", "-o", go2obj, go2src).CombinedOutput() + out, err = exec.Command(gotool, "tool", "compile", "-p=p", "-o", go2obj, go2src).CombinedOutput() if err != nil { return fmt.Errorf("go tool compile -o %s %s: %v\n%s", go2obj, go2src, err, out) } diff --git a/src/cmd/internal/diff/diff.go b/src/cmd/internal/diff/diff.go deleted file mode 100644 index 0ec2d7f8f9..0000000000 --- a/src/cmd/internal/diff/diff.go +++ /dev/null @@ -1,78 +0,0 @@ -// Copyright 2019 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 diff implements a Diff function that compare two inputs -// using the 'diff' tool. -package diff - -import ( - "bytes" - exec "internal/execabs" - "io/ioutil" - "os" - "runtime" -) - -// Returns diff of two arrays of bytes in diff tool format. -func Diff(prefix string, b1, b2 []byte) ([]byte, error) { - f1, err := writeTempFile(prefix, b1) - if err != nil { - return nil, err - } - defer os.Remove(f1) - - f2, err := writeTempFile(prefix, b2) - if err != nil { - return nil, err - } - defer os.Remove(f2) - - cmd := "diff" - if runtime.GOOS == "plan9" { - cmd = "/bin/ape/diff" - } - - data, err := exec.Command(cmd, "-u", f1, f2).CombinedOutput() - if len(data) > 0 { - // diff exits with a non-zero status when the files don't match. - // Ignore that failure as long as we get output. - err = nil - } - - // If we are on Windows and the diff is Cygwin diff, - // machines can get into a state where every Cygwin - // command works fine but prints a useless message like: - // - // Cygwin WARNING: - // Couldn't compute FAST_CWD pointer. This typically occurs if you're using - // an older Cygwin version on a newer Windows. Please update to the latest - // available Cygwin version from https://cygwin.com/. If the problem persists, - // please see https://cygwin.com/problems.html - // - // Skip over that message and just return the actual diff. - if len(data) > 0 && !bytes.HasPrefix(data, []byte("--- ")) { - i := bytes.Index(data, []byte("\n--- ")) - if i >= 0 && i < 80*10 && bytes.Contains(data[:i], []byte("://cygwin.com/")) { - data = data[i+1:] - } - } - - return data, err -} - -func writeTempFile(prefix string, data []byte) (string, error) { - file, err := ioutil.TempFile("", prefix) - if err != nil { - return "", err - } - _, err = file.Write(data) - if err1 := file.Close(); err == nil { - err = err1 - } - if err != nil { - os.Remove(file.Name()) - return "", err - } - return file.Name(), nil -} diff --git a/src/cmd/internal/goobj/objfile.go b/src/cmd/internal/goobj/objfile.go index 9765058392..ff225bedd7 100644 --- a/src/cmd/internal/goobj/objfile.go +++ b/src/cmd/internal/goobj/objfile.go @@ -283,6 +283,7 @@ const ( ObjFlagShared = 1 << iota // this object is built with -shared ObjFlagNeedNameExpansion // the linker needs to expand `"".` to package path in symbol names ObjFlagFromAssembly // object is from asm src, not go + ObjFlagUnlinkable // unlinkable package (linker will emit an error) ) // Sym.Flag @@ -869,3 +870,4 @@ func (r *Reader) Flags() uint32 { func (r *Reader) Shared() bool { return r.Flags()&ObjFlagShared != 0 } func (r *Reader) NeedNameExpansion() bool { return r.Flags()&ObjFlagNeedNameExpansion != 0 } func (r *Reader) FromAssembly() bool { return r.Flags()&ObjFlagFromAssembly != 0 } +func (r *Reader) Unlinkable() bool { return r.Flags()&ObjFlagUnlinkable != 0 } diff --git a/src/cmd/internal/metadata/main.go b/src/cmd/internal/metadata/main.go new file mode 100644 index 0000000000..157226e890 --- /dev/null +++ b/src/cmd/internal/metadata/main.go @@ -0,0 +1,27 @@ +// Copyright 2022 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. + +// Metadata prints basic system metadata to include in test logs. This is +// separate from cmd/dist so it does not need to build with the bootstrap +// toolchain. +package main + +import ( + "cmd/internal/osinfo" + "fmt" + "internal/sysinfo" + "runtime" +) + +func main() { + fmt.Printf("# GOARCH: %s\n", runtime.GOARCH) + fmt.Printf("# CPU: %s\n", sysinfo.CPU.Name()) + + fmt.Printf("# GOOS: %s\n", runtime.GOOS) + ver, err := osinfo.Version() + if err != nil { + ver = fmt.Sprintf("UNKNOWN: error determining OS version: %v", err) + } + fmt.Printf("# OS Version: %s\n", ver) +} diff --git a/src/cmd/internal/moddeps/moddeps_test.go b/src/cmd/internal/moddeps/moddeps_test.go index 56c3b2585c..a63ac71a16 100644 --- a/src/cmd/internal/moddeps/moddeps_test.go +++ b/src/cmd/internal/moddeps/moddeps_test.go @@ -15,7 +15,6 @@ import ( "os" "os/exec" "path/filepath" - "runtime" "strings" "sync" "testing" @@ -153,7 +152,7 @@ func TestAllDependencies(t *testing.T) { // module version specified in GOROOT/src/cmd/go.mod. bundleDir := t.TempDir() r := runner{ - Dir: filepath.Join(runtime.GOROOT(), "src/cmd"), + Dir: filepath.Join(testenv.GOROOT(t), "src/cmd"), Env: append(os.Environ(), modcacheEnv...), } r.run(t, goBin, "build", "-mod=readonly", "-o", bundleDir, "golang.org/x/tools/cmd/bundle") @@ -183,9 +182,9 @@ func TestAllDependencies(t *testing.T) { } }() - rel, err := filepath.Rel(runtime.GOROOT(), m.Dir) + rel, err := filepath.Rel(testenv.GOROOT(t), m.Dir) if err != nil { - t.Fatalf("filepath.Rel(%q, %q): %v", runtime.GOROOT(), m.Dir, err) + t.Fatalf("filepath.Rel(%q, %q): %v", testenv.GOROOT(t), m.Dir, err) } r := runner{ Dir: filepath.Join(gorootCopyDir, rel), @@ -252,22 +251,22 @@ func packagePattern(modulePath string) string { func makeGOROOTCopy(t *testing.T) string { t.Helper() gorootCopyDir := t.TempDir() - err := filepath.Walk(runtime.GOROOT(), func(src string, info os.FileInfo, err error) error { + err := filepath.Walk(testenv.GOROOT(t), func(src string, info os.FileInfo, err error) error { if err != nil { return err } - if info.IsDir() && src == filepath.Join(runtime.GOROOT(), ".git") { + if info.IsDir() && src == filepath.Join(testenv.GOROOT(t), ".git") { return filepath.SkipDir } - rel, err := filepath.Rel(runtime.GOROOT(), src) + rel, err := filepath.Rel(testenv.GOROOT(t), src) if err != nil { - return fmt.Errorf("filepath.Rel(%q, %q): %v", runtime.GOROOT(), src, err) + return fmt.Errorf("filepath.Rel(%q, %q): %v", testenv.GOROOT(t), src, err) } dst := filepath.Join(gorootCopyDir, rel) - if info.IsDir() && (src == filepath.Join(runtime.GOROOT(), "bin") || - src == filepath.Join(runtime.GOROOT(), "pkg")) { + if info.IsDir() && (src == filepath.Join(testenv.GOROOT(t), "bin") || + src == filepath.Join(testenv.GOROOT(t), "pkg")) { // If the OS supports symlinks, use them instead // of copying the bin and pkg directories. if err := os.Symlink(src, dst); err == nil { @@ -435,14 +434,14 @@ func findGorootModules(t *testing.T) []gorootModule { goBin := testenv.GoToolPath(t) goroot.once.Do(func() { - goroot.err = filepath.WalkDir(runtime.GOROOT(), func(path string, info fs.DirEntry, err error) error { + goroot.err = filepath.WalkDir(testenv.GOROOT(t), func(path string, info fs.DirEntry, err error) error { if err != nil { return err } if info.IsDir() && (info.Name() == "vendor" || info.Name() == "testdata") { return filepath.SkipDir } - if info.IsDir() && path == filepath.Join(runtime.GOROOT(), "pkg") { + if info.IsDir() && path == filepath.Join(testenv.GOROOT(t), "pkg") { // GOROOT/pkg contains generated artifacts, not source code. // // In https://golang.org/issue/37929 it was observed to somehow contain diff --git a/src/cmd/internal/obj/arm64/a.out.go b/src/cmd/internal/obj/arm64/a.out.go index aa7c54df9a..f3480e0f5e 100644 --- a/src/cmd/internal/obj/arm64/a.out.go +++ b/src/cmd/internal/obj/arm64/a.out.go @@ -1053,6 +1053,8 @@ const ( AVUADDW2 AVUADDW AVUSRA + AVTRN1 + AVTRN2 ALAST AB = obj.AJMP ABL = obj.ACALL diff --git a/src/cmd/internal/obj/arm64/anames.go b/src/cmd/internal/obj/arm64/anames.go index 9cc5871648..ab97a1a130 100644 --- a/src/cmd/internal/obj/arm64/anames.go +++ b/src/cmd/internal/obj/arm64/anames.go @@ -537,5 +537,7 @@ var Anames = []string{ "VUADDW2", "VUADDW", "VUSRA", + "VTRN1", + "VTRN2", "LAST", } diff --git a/src/cmd/internal/obj/arm64/asm7.go b/src/cmd/internal/obj/arm64/asm7.go index f4111f4f5c..244430eb8f 100644 --- a/src/cmd/internal/obj/arm64/asm7.go +++ b/src/cmd/internal/obj/arm64/asm7.go @@ -321,11 +321,8 @@ var optab = []Optab{ {ACMP, C_VCON, C_REG, C_NONE, C_NONE, 13, 20, 0, 0, 0}, {AADD, C_SHIFT, C_REG, C_NONE, C_REG, 3, 4, 0, 0, 0}, {AADD, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0}, - {AADD, C_SHIFT, C_RSP, C_NONE, C_RSP, 26, 4, 0, 0, 0}, - {AADD, C_SHIFT, C_NONE, C_NONE, C_RSP, 26, 4, 0, 0, 0}, {AMVN, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0}, {ACMP, C_SHIFT, C_REG, C_NONE, C_NONE, 3, 4, 0, 0, 0}, - {ACMP, C_SHIFT, C_RSP, C_NONE, C_NONE, 26, 4, 0, 0, 0}, {ANEG, C_SHIFT, C_NONE, C_NONE, C_REG, 3, 4, 0, 0, 0}, {AADD, C_REG, C_RSP, C_NONE, C_RSP, 27, 4, 0, 0, 0}, {AADD, C_REG, C_NONE, C_NONE, C_RSP, 27, 4, 0, 0, 0}, @@ -1687,7 +1684,8 @@ func rclass(r int16) int { return C_ARNG case r >= REG_ELEM && r < REG_ELEM_END: return C_ELEM - case r >= REG_UXTB && r < REG_SPECIAL: + case r >= REG_UXTB && r < REG_SPECIAL, + r >= REG_LSL && r < REG_ARNG: return C_EXTREG case r >= REG_SPECIAL: return C_SPR @@ -2987,6 +2985,8 @@ func buildop(ctxt *obj.Link) { case AVZIP1: oprangeset(AVZIP2, t) + oprangeset(AVTRN1, t) + oprangeset(AVTRN2, t) case AVUXTL: oprangeset(AVUXTL2, t) @@ -3666,52 +3666,18 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { rt := int(p.To.Reg) o1 |= (uint32(rf&31) << 16) | (REGZERO & 31 << 5) | uint32(rt&31) - case 26: // op R<> 10) & 63 - shift := (p.From.Offset >> 22) & 3 - if shift != 0 { - c.ctxt.Diag("illegal combination: %v", p) - break - } - - if amount > 4 { - c.ctxt.Diag("the left shift amount out of range 0 to 4: %v", p) - break - } - rf := (p.From.Offset >> 16) & 31 - rt := int(p.To.Reg) - r := int(p.Reg) - if p.To.Type == obj.TYPE_NONE { - rt = REGZERO - } - if r == 0 { - r = rt - } - - o1 = c.opxrrr(p, p.As, false) - o1 |= uint32(rf)<<16 | uint32(amount&7)<<10 | (uint32(r&31) << 5) | uint32(rt&31) - case 27: /* op Rm<= REG_LSL && p.From.Reg < REG_ARNG) { amount := (p.From.Reg >> 5) & 7 if amount > 4 { c.ctxt.Diag("shift amount out of range 0 to 4: %v", p) } o1 = c.opxrrr(p, p.As, true) - o1 |= c.encRegShiftOrExt(&p.From, p.From.Reg) /* includes reg, op, etc */ + o1 |= c.encRegShiftOrExt(p, &p.From, p.From.Reg) /* includes reg, op, etc */ } else { o1 = c.opxrrr(p, p.As, false) o1 |= uint32(p.From.Reg&31) << 16 @@ -5344,7 +5310,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { c.checkShiftAmount(p, &p.From) o1 = c.opldrr(p, p.As, true) - o1 |= c.encRegShiftOrExt(&p.From, p.From.Index) /* includes reg, op, etc */ + o1 |= c.encRegShiftOrExt(p, &p.From, p.From.Index) /* includes reg, op, etc */ } else { // (Rn)(Rm), no extension or shift. o1 = c.opldrr(p, p.As, false) @@ -5360,7 +5326,7 @@ func (c *ctxt7) asmout(p *obj.Prog, o *Optab, out []uint32) { c.checkShiftAmount(p, &p.To) o1 = c.opstrr(p, p.As, true) - o1 |= c.encRegShiftOrExt(&p.To, p.To.Index) /* includes reg, op, etc */ + o1 |= c.encRegShiftOrExt(p, &p.To, p.To.Index) /* includes reg, op, etc */ } else { // (Rn)(Rm), no extension or shift. o1 = c.opstrr(p, p.As, false) @@ -6215,6 +6181,12 @@ func (c *ctxt7) oprrr(p *obj.Prog, a obj.As) uint32 { case AVUADDW, AVUADDW2: return 0x17<<25 | 1<<21 | 1<<12 + + case AVTRN1: + return 7<<25 | 5<<11 + + case AVTRN2: + return 7<<25 | 1<<14 | 5<<11 } c.ctxt.Diag("%v: bad rrr %d %v", p, a, a) @@ -7427,7 +7399,7 @@ func roff(rm int16, o uint32, amount int16) uint32 { } // encRegShiftOrExt returns the encoding of shifted/extended register, Rx<> 5) & 7 rm = r & 31 @@ -7472,8 +7444,13 @@ func (c *ctxt7) encRegShiftOrExt(a *obj.Addr, r int16) uint32 { } else { return roff(rm, 7, num) } - case REG_LSL <= r && r < (REG_LSL+1<<8): - return roff(rm, 3, 6) + case REG_LSL <= r && r < REG_ARNG: + if a.Type == obj.TYPE_MEM { // (R1)(R2<<1) + return roff(rm, 3, 6) + } else if isADDWop(p.As) { + return roff(rm, 2, num) + } + return roff(rm, 3, num) default: c.ctxt.Diag("unsupported register extension type.") } diff --git a/src/cmd/internal/obj/arm64/obj7.go b/src/cmd/internal/obj/arm64/obj7.go index e9eb786cb2..ee5a6fa273 100644 --- a/src/cmd/internal/obj/arm64/obj7.go +++ b/src/cmd/internal/obj/arm64/obj7.go @@ -165,21 +165,13 @@ func (c *ctxt7) stacksplit(p *obj.Prog, framesize int32) *obj.Prog { q := (*obj.Prog)(nil) if framesize <= objabi.StackSmall { // small stack: SP < stackguard - // MOV SP, RT2 - // CMP stackguard, RT2 - p = obj.Appendp(p, c.newprog) - - p.As = AMOVD - p.From.Type = obj.TYPE_REG - p.From.Reg = REGSP - p.To.Type = obj.TYPE_REG - p.To.Reg = REGRT2 + // CMP stackguard, SP p = obj.Appendp(p, c.newprog) p.As = ACMP p.From.Type = obj.TYPE_REG p.From.Reg = REGRT1 - p.Reg = REGRT2 + p.Reg = REGSP } else if framesize <= objabi.StackBig { // large stack: SP-framesize < stackguard-StackSmall // SUB $(framesize-StackSmall), SP, RT2 @@ -630,92 +622,124 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { var prologueEnd *obj.Prog aoffset := c.autosize - if aoffset > 0xF0 { - aoffset = 0xF0 + if aoffset > 0x1f0 { + // LDP offset variant range is -512 to 504, SP should be 16-byte aligned, + // so the maximum aoffset value is 496. + aoffset = 0x1f0 } // Frame is non-empty. Make sure to save link register, even if // it is a leaf function, so that traceback works. q = p if c.autosize > aoffset { - // Frame size is too large for a MOVD.W instruction. - // Store link register before decrementing SP, so if a signal comes - // during the execution of the function prologue, the traceback - // code will not see a half-updated stack frame. - // This sequence is not async preemptible, as if we open a frame - // at the current SP, it will clobber the saved LR. - q = c.ctxt.StartUnsafePoint(q, c.newprog) - - q = obj.Appendp(q, c.newprog) - q.Pos = p.Pos - q.As = ASUB - q.From.Type = obj.TYPE_CONST - q.From.Offset = int64(c.autosize) - q.Reg = REGSP - q.To.Type = obj.TYPE_REG - q.To.Reg = REGTMP - - prologueEnd = q - - q = obj.Appendp(q, c.newprog) - q.Pos = p.Pos - q.As = AMOVD - q.From.Type = obj.TYPE_REG - q.From.Reg = REGLINK - q.To.Type = obj.TYPE_MEM - q.To.Reg = REGTMP + // Frame size is too large for a STP instruction. Store the frame pointer + // register and link register before decrementing SP, so if a signal comes + // during the execution of the function prologue, the traceback code will + // not see a half-updated stack frame. + // SUB $autosize, RSP, R20 q1 = obj.Appendp(q, c.newprog) q1.Pos = p.Pos + q1.As = ASUB + q1.From.Type = obj.TYPE_CONST + q1.From.Offset = int64(c.autosize) + q1.Reg = REGSP + q1.To.Type = obj.TYPE_REG + q1.To.Reg = REG_R20 + + prologueEnd = q1 + + // STP (R29, R30), -8(R20) + q1 = obj.Appendp(q1, c.newprog) + q1.Pos = p.Pos + q1.As = ASTP + q1.From.Type = obj.TYPE_REGREG + q1.From.Reg = REGFP + q1.From.Offset = REGLINK + q1.To.Type = obj.TYPE_MEM + q1.To.Reg = REG_R20 + q1.To.Offset = -8 + + // This is not async preemptible, as if we open a frame + // at the current SP, it will clobber the saved LR. + q1 = c.ctxt.StartUnsafePoint(q1, c.newprog) + + // MOVD R20, RSP + q1 = obj.Appendp(q1, c.newprog) + q1.Pos = p.Pos q1.As = AMOVD q1.From.Type = obj.TYPE_REG - q1.From.Reg = REGTMP + q1.From.Reg = REG_R20 q1.To.Type = obj.TYPE_REG q1.To.Reg = REGSP q1.Spadj = c.autosize + q1 = c.ctxt.EndUnsafePoint(q1, c.newprog, -1) + if buildcfg.GOOS == "ios" { // iOS does not support SA_ONSTACK. We will run the signal handler // on the G stack. If we write below SP, it may be clobbered by - // the signal handler. So we save LR after decrementing SP. + // the signal handler. So we save FP and LR after decrementing SP. + // STP (R29, R30), -8(RSP) q1 = obj.Appendp(q1, c.newprog) q1.Pos = p.Pos - q1.As = AMOVD - q1.From.Type = obj.TYPE_REG - q1.From.Reg = REGLINK + q1.As = ASTP + q1.From.Type = obj.TYPE_REGREG + q1.From.Reg = REGFP + q1.From.Offset = REGLINK q1.To.Type = obj.TYPE_MEM q1.To.Reg = REGSP + q1.To.Offset = -8 } - - q1 = c.ctxt.EndUnsafePoint(q1, c.newprog, -1) } else { - // small frame, update SP and save LR in a single MOVD.W instruction + // small frame, save FP and LR with one STP instruction, then update SP. + // Store first, so if a signal comes during the execution of the function + // prologue, the traceback code will not see a half-updated stack frame. + // STP (R29, R30), -aoffset-8(RSP) q1 = obj.Appendp(q, c.newprog) - q1.As = AMOVD + q1.As = ASTP q1.Pos = p.Pos - q1.From.Type = obj.TYPE_REG - q1.From.Reg = REGLINK + q1.From.Type = obj.TYPE_REGREG + q1.From.Reg = REGFP + q1.From.Offset = REGLINK q1.To.Type = obj.TYPE_MEM - q1.Scond = C_XPRE - q1.To.Offset = int64(-aoffset) + q1.To.Offset = int64(-aoffset - 8) + q1.To.Reg = REGSP + + prologueEnd = q1 + + q1 = c.ctxt.StartUnsafePoint(q1, c.newprog) + // This instruction is not async preemptible, see the above comment. + // SUB $aoffset, RSP, RSP + q1 = obj.Appendp(q1, c.newprog) + q1.Pos = p.Pos + q1.As = ASUB + q1.From.Type = obj.TYPE_CONST + q1.From.Offset = int64(aoffset) + q1.Reg = REGSP + q1.To.Type = obj.TYPE_REG q1.To.Reg = REGSP q1.Spadj = aoffset - prologueEnd = q1 + q1 = c.ctxt.EndUnsafePoint(q1, c.newprog, -1) + + if buildcfg.GOOS == "ios" { + // See the above comment. + // STP (R29, R30), -8(RSP) + q1 = obj.Appendp(q1, c.newprog) + q1.As = ASTP + q1.Pos = p.Pos + q1.From.Type = obj.TYPE_REGREG + q1.From.Reg = REGFP + q1.From.Offset = REGLINK + q1.To.Type = obj.TYPE_MEM + q1.To.Offset = int64(-8) + q1.To.Reg = REGSP + } } prologueEnd.Pos = prologueEnd.Pos.WithXlogue(src.PosPrologueEnd) - // Frame pointer. - q1 = obj.Appendp(q1, c.newprog) - q1.Pos = p.Pos - q1.As = AMOVD - q1.From.Type = obj.TYPE_REG - q1.From.Reg = REGFP - q1.To.Type = obj.TYPE_MEM - q1.To.Reg = REGSP - q1.To.Offset = -8 - q1 = obj.Appendp(q1, c.newprog) q1.Pos = p.Pos q1.As = ASUB @@ -858,48 +882,28 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { p.To.Reg = REGFP } } else { - /* want write-back pre-indexed SP+autosize -> SP, loading REGLINK*/ - - // Frame pointer. - p.As = AMOVD - p.From.Type = obj.TYPE_MEM - p.From.Reg = REGSP - p.From.Offset = -8 - p.To.Type = obj.TYPE_REG - p.To.Reg = REGFP - p = obj.Appendp(p, c.newprog) - aoffset := c.autosize + // LDP -8(RSP), (R29, R30) + p.As = ALDP + p.From.Type = obj.TYPE_MEM + p.From.Offset = -8 + p.From.Reg = REGSP + p.To.Type = obj.TYPE_REGREG + p.To.Reg = REGFP + p.To.Offset = REGLINK - if aoffset <= 0xF0 { - p.As = AMOVD - p.From.Type = obj.TYPE_MEM - p.Scond = C_XPOST - p.From.Offset = int64(aoffset) - p.From.Reg = REGSP - p.To.Type = obj.TYPE_REG - p.To.Reg = REGLINK - p.Spadj = -aoffset - } else { - p.As = AMOVD - p.From.Type = obj.TYPE_MEM - p.From.Offset = 0 - p.From.Reg = REGSP - p.To.Type = obj.TYPE_REG - p.To.Reg = REGLINK - - q = newprog() - q.As = AADD - q.From.Type = obj.TYPE_CONST - q.From.Offset = int64(aoffset) - q.To.Type = obj.TYPE_REG - q.To.Reg = REGSP - q.Link = p.Link - q.Spadj = int32(-q.From.Offset) - q.Pos = p.Pos - p.Link = q - p = q - } + // ADD $aoffset, RSP, RSP + q = newprog() + q.As = AADD + q.From.Type = obj.TYPE_CONST + q.From.Offset = int64(aoffset) + q.To.Type = obj.TYPE_REG + q.To.Reg = REGSP + q.Spadj = -aoffset + q.Pos = p.Pos + q.Link = p.Link + p.Link = q + p = q } // If enabled, this code emits 'MOV PC, R27' before every 'MOV LR, PC', @@ -1085,6 +1089,24 @@ func preprocess(ctxt *obj.Link, cursym *obj.LSym, newprog obj.ProgAlloc) { } } } + if p.From.Type == obj.TYPE_SHIFT && (p.To.Reg == REG_RSP || p.Reg == REG_RSP) { + offset := p.From.Offset + op := offset & (3 << 22) + if op != SHIFT_LL { + ctxt.Diag("illegal combination: %v", p) + } + r := (offset >> 16) & 31 + shift := (offset >> 10) & 63 + if shift > 4 { + // the shift amount is out of range, in order to avoid repeated error + // reportings, don't call ctxt.Diag, because asmout case 27 has the + // same check. + shift = 7 + } + p.From.Type = obj.TYPE_REG + p.From.Reg = int16(REG_LSL + r + (shift&7)<<5) + p.From.Offset = 0 + } } } diff --git a/src/cmd/internal/obj/objfile.go b/src/cmd/internal/obj/objfile.go index 560e8e24c4..7bae31f343 100644 --- a/src/cmd/internal/obj/objfile.go +++ b/src/cmd/internal/obj/objfile.go @@ -23,6 +23,8 @@ import ( "strings" ) +const UnlinkablePkg = "" // invalid package path, used when compiled without -p flag + // Entry point of writing new object file. func WriteObjFile(ctxt *Link, b *bio.Writer) { @@ -45,6 +47,9 @@ func WriteObjFile(ctxt *Link, b *bio.Writer) { if ctxt.Flag_shared { flags |= goobj.ObjFlagShared } + if w.pkgpath == UnlinkablePkg { + flags |= goobj.ObjFlagUnlinkable + } if w.pkgpath == "" { flags |= goobj.ObjFlagNeedNameExpansion } @@ -168,6 +173,7 @@ func WriteObjFile(ctxt *Link, b *bio.Writer) { h.Offsets[goobj.BlkReloc] = w.Offset() for _, list := range lists { for _, s := range list { + sort.Sort(relocByOff(s.R)) // some platforms (e.g. PE) requires relocations in address order for i := range s.R { w.Reloc(&s.R[i]) } diff --git a/src/cmd/internal/obj/objfile_test.go b/src/cmd/internal/obj/objfile_test.go index 146627b62b..f5a4016eec 100644 --- a/src/cmd/internal/obj/objfile_test.go +++ b/src/cmd/internal/obj/objfile_test.go @@ -111,7 +111,7 @@ func TestSymbolTooLarge(t *testing.T) { // Issue 42054 t.Fatalf("failed to write source file: %v\n", err) } obj := filepath.Join(tmpdir, "p.o") - cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", obj, src) + cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=p", "-o", obj, src) out, err := cmd.CombinedOutput() if err == nil { t.Fatalf("did not fail\noutput: %s", out) diff --git a/src/cmd/internal/obj/ppc64/a.out.go b/src/cmd/internal/obj/ppc64/a.out.go index 1e74e64a29..25081efcee 100644 --- a/src/cmd/internal/obj/ppc64/a.out.go +++ b/src/cmd/internal/obj/ppc64/a.out.go @@ -362,13 +362,14 @@ const ( BI_LT = 0 BI_GT = 1 BI_EQ = 2 - BI_OVF = 3 + BI_FU = 3 ) // Common values for the BO field. const ( BO_BCTR = 16 // decrement ctr, branch on ctr != 0 + BO_NOTBCTR = 18 // decrement ctr, branch on ctr == 0 BO_BCR = 12 // branch on cr value BO_BCRBCTR = 8 // decrement ctr, branch on ctr != 0 and cr value BO_NOTBCR = 4 // branch on not cr value @@ -480,9 +481,11 @@ const ( ABGT ABLE // not GT = L/E/U ABLT - ABNE // not EQ = L/G/U - ABVC // Unordered-clear - ABVS // Unordered-set + ABNE // not EQ = L/G/U + ABVC // Branch if float not unordered (also branch on not summary overflow) + ABVS // Branch if float unordered (also branch on summary overflow) + ABDNZ // Decrement CTR, and branch if CTR != 0 + ABDZ // Decrement CTR, and branch if CTR == 0 ACMP ACMPU ACMPEQB diff --git a/src/cmd/internal/obj/ppc64/anames.go b/src/cmd/internal/obj/ppc64/anames.go index 0da73ca91e..7521a92ab4 100644 --- a/src/cmd/internal/obj/ppc64/anames.go +++ b/src/cmd/internal/obj/ppc64/anames.go @@ -42,6 +42,8 @@ var Anames = []string{ "BNE", "BVC", "BVS", + "BDNZ", + "BDZ", "CMP", "CMPU", "CMPEQB", diff --git a/src/cmd/internal/obj/ppc64/asm9.go b/src/cmd/internal/obj/ppc64/asm9.go index 70ce9050b6..50c9b37f02 100644 --- a/src/cmd/internal/obj/ppc64/asm9.go +++ b/src/cmd/internal/obj/ppc64/asm9.go @@ -305,6 +305,7 @@ var optab = []Optab{ {as: ABC, a1: C_SCON, a2: C_REG, a6: C_LR, type_: 18, size: 4}, {as: ABC, a1: C_SCON, a2: C_REG, a6: C_CTR, type_: 18, size: 4}, {as: ABC, a6: C_ZOREG, type_: 15, size: 8}, + {as: ABDNZ, a6: C_SBRA, type_: 16, size: 4}, {as: ASYNC, type_: 46, size: 4}, {as: AWORD, a1: C_LCON, type_: 40, size: 4}, {as: ADWORD, a1: C_64CON, type_: 31, size: 8}, @@ -1778,6 +1779,9 @@ func buildop(ctxt *obj.Link) { case ABC: opset(ABCL, r0) + case ABDNZ: + opset(ABDZ, r0) + case AEXTSB: /* op Rs, Ra */ opset(AEXTSBCC, r0) @@ -4875,21 +4879,25 @@ func (c *ctxt9) opirr(a obj.As) uint32 { return OPVCC(16, 0, 0, 0) | 1 case ABEQ: - return AOP_RRR(16<<26, 12, 2, 0) + return AOP_RRR(16<<26, BO_BCR, BI_EQ, 0) case ABGE: - return AOP_RRR(16<<26, 4, 0, 0) + return AOP_RRR(16<<26, BO_NOTBCR, BI_LT, 0) case ABGT: - return AOP_RRR(16<<26, 12, 1, 0) + return AOP_RRR(16<<26, BO_BCR, BI_GT, 0) case ABLE: - return AOP_RRR(16<<26, 4, 1, 0) + return AOP_RRR(16<<26, BO_NOTBCR, BI_GT, 0) case ABLT: - return AOP_RRR(16<<26, 12, 0, 0) + return AOP_RRR(16<<26, BO_BCR, BI_LT, 0) case ABNE: - return AOP_RRR(16<<26, 4, 2, 0) + return AOP_RRR(16<<26, BO_NOTBCR, BI_EQ, 0) case ABVC: - return AOP_RRR(16<<26, 4, 3, 0) // apparently unordered-clear + return AOP_RRR(16<<26, BO_NOTBCR, BI_FU, 0) case ABVS: - return AOP_RRR(16<<26, 12, 3, 0) // apparently unordered-set + return AOP_RRR(16<<26, BO_BCR, BI_FU, 0) + case ABDZ: + return AOP_RRR(16<<26, BO_NOTBCTR, 0, 0) + case ABDNZ: + return AOP_RRR(16<<26, BO_BCTR, 0, 0) case ACMP: return OPVCC(11, 0, 0, 0) | 1<<21 /* L=1 */ diff --git a/src/cmd/internal/obj/riscv/cpu.go b/src/cmd/internal/obj/riscv/cpu.go index d9434e7415..8c2daf6e5b 100644 --- a/src/cmd/internal/obj/riscv/cpu.go +++ b/src/cmd/internal/obj/riscv/cpu.go @@ -125,13 +125,13 @@ const ( REG_A7 = REG_X17 REG_S2 = REG_X18 REG_S3 = REG_X19 - REG_S4 = REG_X20 // aka REG_CTXT + REG_S4 = REG_X20 REG_S5 = REG_X21 REG_S6 = REG_X22 REG_S7 = REG_X23 REG_S8 = REG_X24 REG_S9 = REG_X25 - REG_S10 = REG_X26 + REG_S10 = REG_X26 // aka REG_CTXT REG_S11 = REG_X27 // aka REG_G REG_T3 = REG_X28 REG_T4 = REG_X29 @@ -139,8 +139,8 @@ const ( REG_T6 = REG_X31 // aka REG_TMP // Go runtime register names. + REG_CTXT = REG_S10 // Context for closures. REG_G = REG_S11 // G pointer. - REG_CTXT = REG_S4 // Context for closures. REG_LR = REG_RA // Link register. REG_TMP = REG_T6 // Reserved for assembler use. diff --git a/src/cmd/internal/objabi/flag.go b/src/cmd/internal/objabi/flag.go index f75c054fcb..acb2dd59ea 100644 --- a/src/cmd/internal/objabi/flag.go +++ b/src/cmd/internal/objabi/flag.go @@ -99,11 +99,11 @@ func (versionFlag) Set(s string) error { if s == "goexperiment" { // test/run.go uses this to discover the full set of // experiment tags. Report everything. - p = " X:" + strings.Join(buildcfg.AllExperiments(), ",") + p = " X:" + strings.Join(buildcfg.Experiment.All(), ",") } else { - // If the enabled experiments differ from the defaults, + // If the enabled experiments differ from the baseline, // include that difference. - if goexperiment := buildcfg.GOEXPERIMENT(); goexperiment != "" { + if goexperiment := buildcfg.Experiment.String(); goexperiment != "" { p = " X:" + goexperiment } } diff --git a/src/cmd/internal/objabi/line.go b/src/cmd/internal/objabi/line.go index 0b1e0bb181..beee1291b5 100644 --- a/src/cmd/internal/objabi/line.go +++ b/src/cmd/internal/objabi/line.go @@ -39,7 +39,7 @@ func AbsFile(dir, file, rewrites string) string { } abs, rewritten := ApplyRewrites(abs, rewrites) - if !rewritten && hasPathPrefix(abs, buildcfg.GOROOT) { + if !rewritten && buildcfg.GOROOT != "" && hasPathPrefix(abs, buildcfg.GOROOT) { abs = "$GOROOT" + abs[len(buildcfg.GOROOT):] } diff --git a/src/cmd/internal/objabi/util.go b/src/cmd/internal/objabi/util.go index 6bfa25a5ca..c2f1b204b9 100644 --- a/src/cmd/internal/objabi/util.go +++ b/src/cmd/internal/objabi/util.go @@ -22,5 +22,5 @@ const ( // or link object files that are incompatible with each other. This // string always starts with "go object ". func HeaderString() string { - return fmt.Sprintf("go object %s %s %s X:%s\n", buildcfg.GOOS, buildcfg.GOARCH, buildcfg.Version, strings.Join(buildcfg.EnabledExperiments(), ",")) + return fmt.Sprintf("go object %s %s %s X:%s\n", buildcfg.GOOS, buildcfg.GOARCH, buildcfg.Version, strings.Join(buildcfg.Experiment.Enabled(), ",")) } diff --git a/src/cmd/internal/osinfo/doc.go b/src/cmd/internal/osinfo/doc.go new file mode 100644 index 0000000000..1b5469d53a --- /dev/null +++ b/src/cmd/internal/osinfo/doc.go @@ -0,0 +1,6 @@ +// Copyright 2022 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 osinfo provides OS metadata. +package osinfo diff --git a/src/cmd/internal/osinfo/os_js.go b/src/cmd/internal/osinfo/os_js.go new file mode 100644 index 0000000000..882580d652 --- /dev/null +++ b/src/cmd/internal/osinfo/os_js.go @@ -0,0 +1,21 @@ +// Copyright 2022 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. + +//go:build js + +package osinfo + +import ( + "fmt" +) + +// Version returns the OS version name/number. +func Version() (string, error) { + // Version detection on wasm varies depending on the underlying runtime + // (browser, node, etc), nor is there a standard via something like + // WASI (see https://go.dev/issue/31105). We could attempt multiple + // combinations, but for now we leave this unimplemented for + // simplicity. + return "", fmt.Errorf("unimplemented") +} diff --git a/src/cmd/internal/osinfo/os_plan9.go b/src/cmd/internal/osinfo/os_plan9.go new file mode 100644 index 0000000000..e0225a93a2 --- /dev/null +++ b/src/cmd/internal/osinfo/os_plan9.go @@ -0,0 +1,21 @@ +// Copyright 2022 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. + +//go:build plan9 + +package osinfo + +import ( + "os" +) + +// Version returns the OS version name/number. +func Version() (string, error) { + b, err := os.ReadFile("/dev/osversion") + if err != nil { + return "", err + } + + return string(b), nil +} diff --git a/src/cmd/internal/osinfo/os_unix.go b/src/cmd/internal/osinfo/os_unix.go new file mode 100644 index 0000000000..fab9e08f82 --- /dev/null +++ b/src/cmd/internal/osinfo/os_unix.go @@ -0,0 +1,36 @@ +// Copyright 2022 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. + +//go:build aix || darwin || dragonfly || freebsd || linux || netbsd || openbsd || solaris + +package osinfo + +import ( + "bytes" + + "golang.org/x/sys/unix" +) + +func utsString(b []byte) string { + i := bytes.IndexByte(b, 0) + if i == -1 { + return string(b) + } + return string(b[:i]) +} + +// Version returns the OS version name/number. +func Version() (string, error) { + var uts unix.Utsname + if err := unix.Uname(&uts); err != nil { + return "", err + } + + sysname := utsString(uts.Sysname[:]) + release := utsString(uts.Release[:]) + version := utsString(uts.Version[:]) + machine := utsString(uts.Machine[:]) + + return sysname + " " + release + " " + version + " " + machine, nil +} diff --git a/src/cmd/internal/osinfo/os_windows.go b/src/cmd/internal/osinfo/os_windows.go new file mode 100644 index 0000000000..8ffe4f3f6d --- /dev/null +++ b/src/cmd/internal/osinfo/os_windows.go @@ -0,0 +1,19 @@ +// Copyright 2022 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. + +//go:build windows + +package osinfo + +import ( + "fmt" + + "golang.org/x/sys/windows" +) + +// Version returns the OS version name/number. +func Version() (string, error) { + major, minor, patch := windows.RtlGetNtVersionNumbers() + return fmt.Sprintf("%d.%d.%d", major, minor, patch), nil +} diff --git a/src/cmd/link/elf_test.go b/src/cmd/link/elf_test.go index 760d9ea60d..318bd76aba 100644 --- a/src/cmd/link/elf_test.go +++ b/src/cmd/link/elf_test.go @@ -455,6 +455,9 @@ func TestPIESize(t *testing.T) { extraexe := extrasize(elfexe) extrapie := extrasize(elfpie) + if sizepie < sizeexe || sizepie-extrapie < sizeexe-extraexe { + return + } diffReal := (sizepie - extrapie) - (sizeexe - extraexe) diffExpected := (textpie + dynpie) - (textexe + dynexe) diff --git a/src/cmd/link/internal/arm64/asm.go b/src/cmd/link/internal/arm64/asm.go index abae0f87bc..229a4d300b 100644 --- a/src/cmd/link/internal/arm64/asm.go +++ b/src/cmd/link/internal/arm64/asm.go @@ -1146,7 +1146,8 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) { if !ldr.AttrReachable(s) { continue } - if ldr.SymType(s) == sym.STEXT { + t := ldr.SymType(s) + if t == sym.STEXT { if ctxt.IsDarwin() || ctxt.IsWindows() { // Cannot relocate into middle of function. // Generate symbol names for every offset we need in duffcopy/duffzero (only 64 each). @@ -1159,6 +1160,9 @@ func gensymlate(ctxt *ld.Link, ldr *loader.Loader) { } continue // we don't target the middle of other functions } + if t >= sym.SDWARFSECT { + continue // no need to add label for DWARF symbols + } sz := ldr.SymSize(s) if sz <= limit { continue diff --git a/src/cmd/link/internal/ld/data.go b/src/cmd/link/internal/ld/data.go index 95a8e0facb..0ec1e526a9 100644 --- a/src/cmd/link/internal/ld/data.go +++ b/src/cmd/link/internal/ld/data.go @@ -2778,10 +2778,29 @@ func compressSyms(ctxt *Link, syms []loader.Sym) []byte { } var buf bytes.Buffer - buf.Write([]byte("ZLIB")) - var sizeBytes [8]byte - binary.BigEndian.PutUint64(sizeBytes[:], uint64(total)) - buf.Write(sizeBytes[:]) + if ctxt.IsELF { + switch ctxt.Arch.PtrSize { + case 8: + binary.Write(&buf, ctxt.Arch.ByteOrder, elf.Chdr64{ + Type: uint32(elf.COMPRESS_ZLIB), + Size: uint64(total), + Addralign: uint64(ctxt.Arch.Alignment), + }) + case 4: + binary.Write(&buf, ctxt.Arch.ByteOrder, elf.Chdr32{ + Type: uint32(elf.COMPRESS_ZLIB), + Size: uint32(total), + Addralign: uint32(ctxt.Arch.Alignment), + }) + default: + log.Fatalf("can't compress header size:%d", ctxt.Arch.PtrSize) + } + } else { + buf.Write([]byte("ZLIB")) + var sizeBytes [8]byte + binary.BigEndian.PutUint64(sizeBytes[:], uint64(total)) + buf.Write(sizeBytes[:]) + } var relocbuf []byte // temporary buffer for applying relocations diff --git a/src/cmd/link/internal/ld/deadcode.go b/src/cmd/link/internal/ld/deadcode.go index dba22323b0..3ba4b06f4a 100644 --- a/src/cmd/link/internal/ld/deadcode.go +++ b/src/cmd/link/internal/ld/deadcode.go @@ -355,7 +355,7 @@ func deadcode(ctxt *Link) { // in the last pass. rem := d.markableMethods[:0] for _, m := range d.markableMethods { - if (d.reflectSeen && m.isExported()) || d.ifaceMethod[m.m] || d.genericIfaceMethod[m.m.name] { + if (d.reflectSeen && (m.isExported() || d.dynlink)) || d.ifaceMethod[m.m] || d.genericIfaceMethod[m.m.name] { d.markMethod(m) } else { rem = append(rem, m) diff --git a/src/cmd/link/internal/ld/dwarf.go b/src/cmd/link/internal/ld/dwarf.go index 4aaed7baf0..2e209d0c6b 100644 --- a/src/cmd/link/internal/ld/dwarf.go +++ b/src/cmd/link/internal/ld/dwarf.go @@ -2227,11 +2227,18 @@ func dwarfcompress(ctxt *Link) { newDwarfp = append(newDwarfp, ds) Segdwarf.Sections = append(Segdwarf.Sections, ldr.SymSect(s)) } else { - compressedSegName := ".zdebug_" + ldr.SymSect(s).Name[len(".debug_"):] + var compressedSegName string + if ctxt.IsELF { + compressedSegName = ldr.SymSect(s).Name + } else { + compressedSegName = ".zdebug_" + ldr.SymSect(s).Name[len(".debug_"):] + } sect := addsection(ctxt.loader, ctxt.Arch, &Segdwarf, compressedSegName, 04) - sect.Align = 1 + sect.Align = int32(ctxt.Arch.Alignment) sect.Length = uint64(len(z.compressed)) - newSym := ldr.CreateSymForUpdate(compressedSegName, 0) + sect.Compressed = true + newSym := ldr.MakeSymbolBuilder(compressedSegName) + ldr.SetAttrReachable(s, true) newSym.SetData(z.compressed) newSym.SetSize(int64(len(z.compressed))) ldr.SetSymSect(newSym.Sym(), sect) diff --git a/src/cmd/link/internal/ld/elf.go b/src/cmd/link/internal/ld/elf.go index 1bdfb3369c..cb094a373a 100644 --- a/src/cmd/link/internal/ld/elf.go +++ b/src/cmd/link/internal/ld/elf.go @@ -1102,6 +1102,9 @@ func elfshbits(linkmode LinkMode, sect *sym.Section) *ElfShdr { } if strings.HasPrefix(sect.Name, ".debug") || strings.HasPrefix(sect.Name, ".zdebug") { sh.Flags = 0 + if sect.Compressed { + sh.Flags |= uint64(elf.SHF_COMPRESSED) + } } if linkmode != LinkExternal { @@ -2255,7 +2258,7 @@ func elfadddynsym(ldr *loader.Loader, target *Target, syms *ArchSyms, s loader.S dil := ldr.SymDynimplib(s) - if target.Arch.Family == sys.AMD64 && !cgoeDynamic && dil != "" && !seenlib[dil] { + if !cgoeDynamic && dil != "" && !seenlib[dil] { du := ldr.MakeSymbolUpdater(syms.Dynamic) Elfwritedynent(target.Arch, du, elf.DT_NEEDED, uint64(dstru.Addstring(dil))) seenlib[dil] = true diff --git a/src/cmd/link/internal/ld/elf_test.go b/src/cmd/link/internal/ld/elf_test.go index d86ebb89e0..15eaa1388b 100644 --- a/src/cmd/link/internal/ld/elf_test.go +++ b/src/cmd/link/internal/ld/elf_test.go @@ -86,7 +86,7 @@ func TestNoDuplicateNeededEntries(t *testing.T) { // across the board given the nature of the test). pair := runtime.GOOS + "-" + runtime.GOARCH switch pair { - case "linux-amd64", "freebsd-amd64", "openbsd-amd64": + case "linux-amd64", "linux-arm64", "freebsd-amd64", "openbsd-amd64": default: t.Skip("no need for test on " + pair) } diff --git a/src/cmd/link/internal/ld/ld.go b/src/cmd/link/internal/ld/ld.go index 954921844c..aaad152e6f 100644 --- a/src/cmd/link/internal/ld/ld.go +++ b/src/cmd/link/internal/ld/ld.go @@ -96,19 +96,7 @@ func (ctxt *Link) readImportCfg(file string) { } func pkgname(ctxt *Link, lib string) string { - name := path.Clean(lib) - - // When using importcfg, we have the final package name. - if ctxt.PackageFile != nil { - return name - } - - // runtime.a -> runtime, runtime.6 -> runtime - pkg := name - if len(pkg) >= 2 && pkg[len(pkg)-2] == '.' { - pkg = pkg[:len(pkg)-2] - } - return pkg + return path.Clean(lib) } func findlib(ctxt *Link, lib string) (string, bool) { @@ -127,34 +115,25 @@ func findlib(ctxt *Link, lib string) (string, bool) { return "", false } } else { - if filepath.IsAbs(name) { - pname = name - } else { - pkg := pkgname(ctxt, lib) - // Add .a if needed; the new -importcfg modes - // do not put .a into the package name anymore. - // This only matters when people try to mix - // compiles using -importcfg with links not using -importcfg, - // such as when running quick things like - // 'go tool compile x.go && go tool link x.o' - // by hand against a standard library built using -importcfg. - if !strings.HasSuffix(name, ".a") && !strings.HasSuffix(name, ".o") { - name += ".a" - } - // try dot, -L "libdir", and then goroot. - for _, dir := range ctxt.Libdir { - if ctxt.linkShared { - pname = filepath.Join(dir, pkg+".shlibname") - if _, err := os.Stat(pname); err == nil { - isshlib = true - break - } - } - pname = filepath.Join(dir, name) + pkg := pkgname(ctxt, lib) + + // search -L "libdir" directories + for _, dir := range ctxt.Libdir { + if ctxt.linkShared { + pname = filepath.Join(dir, pkg+".shlibname") if _, err := os.Stat(pname); err == nil { + isshlib = true break } } + pname = filepath.Join(dir, name+".a") + if _, err := os.Stat(pname); err == nil { + break + } + pname = filepath.Join(dir, name+".o") + if _, err := os.Stat(pname); err == nil { + break + } } pname = filepath.Clean(pname) } diff --git a/src/cmd/link/internal/ld/lib.go b/src/cmd/link/internal/ld/lib.go index 5b82dc287d..6055d4327e 100644 --- a/src/cmd/link/internal/ld/lib.go +++ b/src/cmd/link/internal/ld/lib.go @@ -390,7 +390,9 @@ func libinit(ctxt *Link) { suffix = "asan" } - Lflag(ctxt, filepath.Join(buildcfg.GOROOT, "pkg", fmt.Sprintf("%s_%s%s%s", buildcfg.GOOS, buildcfg.GOARCH, suffixsep, suffix))) + if buildcfg.GOROOT != "" { + Lflag(ctxt, filepath.Join(buildcfg.GOROOT, "pkg", fmt.Sprintf("%s_%s%s%s", buildcfg.GOOS, buildcfg.GOARCH, suffixsep, suffix))) + } mayberemoveoutfile() @@ -1478,7 +1480,7 @@ func (ctxt *Link) hostlink() { argv = append(argv, unusedArguments) } - const compressDWARF = "-Wl,--compress-debug-sections=zlib-gnu" + const compressDWARF = "-Wl,--compress-debug-sections=zlib" if ctxt.compressDWARF && linkerFlagSupported(ctxt.Arch, argv[0], altLinker, compressDWARF) { argv = append(argv, compressDWARF) } diff --git a/src/cmd/link/internal/ld/main.go b/src/cmd/link/internal/ld/main.go index 26f9db8ec4..fa95a7acf2 100644 --- a/src/cmd/link/internal/ld/main.go +++ b/src/cmd/link/internal/ld/main.go @@ -119,12 +119,16 @@ func Main(arch *sys.Arch, theArch Arch) { } } - final := gorootFinal() - addstrdata1(ctxt, "runtime.defaultGOROOT="+final) - addstrdata1(ctxt, "internal/buildcfg.defaultGOROOT="+final) + if final := gorootFinal(); final == "$GOROOT" { + // cmd/go sets GOROOT_FINAL to the dummy value "$GOROOT" when -trimpath is set, + // but runtime.GOROOT() should return the empty string, not a bogus value. + // (See https://go.dev/issue/51461.) + } else { + addstrdata1(ctxt, "runtime.defaultGOROOT="+final) + } buildVersion := buildcfg.Version - if goexperiment := buildcfg.GOEXPERIMENT(); goexperiment != "" { + if goexperiment := buildcfg.Experiment.String(); goexperiment != "" { buildVersion += " X:" + goexperiment } addstrdata1(ctxt, "runtime.buildVersion="+buildVersion) diff --git a/src/cmd/link/internal/ld/nooptcgolink_test.go b/src/cmd/link/internal/ld/nooptcgolink_test.go index 73548dabd4..0b76ecaecb 100644 --- a/src/cmd/link/internal/ld/nooptcgolink_test.go +++ b/src/cmd/link/internal/ld/nooptcgolink_test.go @@ -8,7 +8,6 @@ import ( "internal/testenv" "os/exec" "path/filepath" - "runtime" "testing" ) @@ -22,7 +21,7 @@ func TestNooptCgoBuild(t *testing.T) { testenv.MustHaveCGO(t) dir := t.TempDir() cmd := exec.Command(testenv.GoToolPath(t), "build", "-gcflags=-N -l", "-o", filepath.Join(dir, "a.out")) - cmd.Dir = filepath.Join(runtime.GOROOT(), "src", "runtime", "testdata", "testprogcgo") + cmd.Dir = filepath.Join(testenv.GOROOT(t), "src", "runtime", "testdata", "testprogcgo") out, err := cmd.CombinedOutput() if err != nil { t.Logf("go build output: %s", out) diff --git a/src/cmd/link/internal/ld/pcln.go b/src/cmd/link/internal/ld/pcln.go index b57e212794..a81490089f 100644 --- a/src/cmd/link/internal/ld/pcln.go +++ b/src/cmd/link/internal/ld/pcln.go @@ -804,7 +804,9 @@ func gorootFinal() string { func expandGoroot(s string) string { const n = len("$GOROOT") if len(s) >= n+1 && s[:n] == "$GOROOT" && (s[n] == '/' || s[n] == '\\') { - return filepath.ToSlash(filepath.Join(gorootFinal(), s[n:])) + if final := gorootFinal(); final != "" { + return filepath.ToSlash(filepath.Join(final, s[n:])) + } } return s } diff --git a/src/cmd/link/internal/loader/loader.go b/src/cmd/link/internal/loader/loader.go index 34c1c6a4c8..d46aa41181 100644 --- a/src/cmd/link/internal/loader/loader.go +++ b/src/cmd/link/internal/loader/loader.go @@ -75,8 +75,7 @@ func (a Aux) Sym() Sym { return a.l.resolve(a.r, a.Aux.Sym()) } type oReader struct { *goobj.Reader unit *sym.CompilationUnit - version int // version of static symbol - flags uint32 // read from object file + version int // version of static symbol pkgprefix string syms []Sym // Sym's global index, indexed by local index pkg []uint32 // indices of referenced package by PkgIdx (index into loader.objs array) @@ -262,8 +261,6 @@ type Loader struct { flags uint32 - hasUnknownPkgPath bool // if any Go object has unknown package path - strictDupMsgs int // number of strict-dup warning/errors, when FlagStrictDups is enabled elfsetstring elfsetstringFunc @@ -362,7 +359,7 @@ func (l *Loader) addObj(pkg string, r *oReader) Sym { l.start[r] = i l.objs = append(l.objs, objIdx{r, i}) if r.NeedNameExpansion() && !r.FromAssembly() { - l.hasUnknownPkgPath = true + panic("object compiled without -p") } return i } @@ -2076,7 +2073,6 @@ func (l *Loader) Preload(localSymVersion int, f *bio.Reader, lib *sym.Library, u Reader: r, unit: unit, version: localSymVersion, - flags: r.Flags(), pkgprefix: pkgprefix, syms: make([]Sym, ndef+nhashed64def+nhasheddef+r.NNonpkgdef()+r.NNonpkgref()), ndef: ndef, @@ -2085,6 +2081,10 @@ func (l *Loader) Preload(localSymVersion int, f *bio.Reader, lib *sym.Library, u objidx: uint32(len(l.objs)), } + if r.Unlinkable() { + log.Fatalf("link: unlinkable object (from package %s) - compiler requires -p flag", lib.Pkg) + } + // Autolib lib.Autolib = append(lib.Autolib, r.Autolib()...) @@ -2124,16 +2124,6 @@ func (st *loadState) preloadSyms(r *oReader, kind int) { case hashedDef: start = uint32(r.ndef + r.nhashed64def) end = uint32(r.ndef + r.nhashed64def + r.nhasheddef) - if l.hasUnknownPkgPath { - // The content hash depends on symbol name expansion. If any package is - // built without fully expanded names, the content hash is unreliable. - // Treat them as named symbols. - // This is rare. - // (We don't need to do this for hashed64Def case, as there the hash - // function is simply the identity function, which doesn't depend on - // name expansion.) - kind = nonPkgDef - } case nonPkgDef: start = uint32(r.ndef + r.nhashed64def + r.nhasheddef) end = uint32(r.ndef + r.nhashed64def + r.nhasheddef + r.NNonpkgdef()) diff --git a/src/cmd/link/internal/sym/segment.go b/src/cmd/link/internal/sym/segment.go index 97853b9355..c889e71ad6 100644 --- a/src/cmd/link/internal/sym/segment.go +++ b/src/cmd/link/internal/sym/segment.go @@ -63,4 +63,6 @@ type Section struct { Relcount uint32 Sym LoaderSym // symbol for the section, if any Index uint16 // each section has a unique index, used internally + + Compressed bool } diff --git a/src/cmd/link/link_test.go b/src/cmd/link/link_test.go index ad7658bb25..8df31d7fd4 100644 --- a/src/cmd/link/link_test.go +++ b/src/cmd/link/link_test.go @@ -55,7 +55,7 @@ func main() {} t.Fatalf("failed to write main.go: %v\n", err) } - cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "main.go") + cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=main", "main.go") cmd.Dir = tmpdir out, err := cmd.CombinedOutput() if err != nil { @@ -100,7 +100,7 @@ func TestIssue28429(t *testing.T) { // Compile a main package. write("main.go", "package main; func main() {}") - runGo("tool", "compile", "-p", "main", "main.go") + runGo("tool", "compile", "-p=main", "main.go") runGo("tool", "pack", "c", "main.a", "main.o") // Add an extra section with a short, non-.o name. @@ -236,7 +236,7 @@ void foo() { // Compile, assemble and pack the Go and C code. runGo("tool", "asm", "-gensymabis", "-o", "symabis", "x.s") - runGo("tool", "compile", "-symabis", "symabis", "-p", "main", "-o", "x1.o", "main.go") + runGo("tool", "compile", "-symabis", "symabis", "-p=main", "-o", "x1.o", "main.go") runGo("tool", "asm", "-o", "x2.o", "x.s") run(cc, append(cflags, "-c", "-o", "x3.o", "x.c")...) runGo("tool", "pack", "c", "x.a", "x1.o", "x2.o", "x3.o") @@ -431,7 +431,7 @@ func TestIssue34788Android386TLSSequence(t *testing.T) { } obj := filepath.Join(tmpdir, "blah.o") - cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", obj, src) + cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=blah", "-o", obj, src) cmd.Env = append(os.Environ(), "GOARCH=386", "GOOS=android") if out, err := cmd.CombinedOutput(); err != nil { t.Fatalf("failed to compile blah.go: %v, output: %s\n", err, out) @@ -765,13 +765,13 @@ func TestIndexMismatch(t *testing.T) { exe := filepath.Join(tmpdir, "main.exe") // Build a program with main package importing package a. - cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", aObj, aSrc) + cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=a", "-o", aObj, aSrc) t.Log(cmd) out, err := cmd.CombinedOutput() if err != nil { t.Fatalf("compiling a.go failed: %v\n%s", err, out) } - cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-I", tmpdir, "-o", mObj, mSrc) + cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=main", "-I", tmpdir, "-o", mObj, mSrc) t.Log(cmd) out, err = cmd.CombinedOutput() if err != nil { @@ -786,7 +786,7 @@ func TestIndexMismatch(t *testing.T) { // Now, overwrite a.o with the object of b.go. This should // result in an index mismatch. - cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", aObj, bSrc) + cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=a", "-o", aObj, bSrc) t.Log(cmd) out, err = cmd.CombinedOutput() if err != nil { @@ -1059,3 +1059,60 @@ func TestLargeReloc(t *testing.T) { } } } + +func TestUnlinkableObj(t *testing.T) { + // Test that the linker emits an error with unlinkable object. + testenv.MustHaveGoBuild(t) + t.Parallel() + + tmpdir := t.TempDir() + + xSrc := filepath.Join(tmpdir, "x.go") + pSrc := filepath.Join(tmpdir, "p.go") + xObj := filepath.Join(tmpdir, "x.o") + pObj := filepath.Join(tmpdir, "p.o") + exe := filepath.Join(tmpdir, "x.exe") + err := ioutil.WriteFile(xSrc, []byte("package main\nimport _ \"p\"\nfunc main() {}\n"), 0666) + if err != nil { + t.Fatalf("failed to write source file: %v", err) + } + err = ioutil.WriteFile(pSrc, []byte("package p\n"), 0666) + if err != nil { + t.Fatalf("failed to write source file: %v", err) + } + cmd := exec.Command(testenv.GoToolPath(t), "tool", "compile", "-o", pObj, pSrc) // without -p + out, err := cmd.CombinedOutput() + if err != nil { + t.Fatalf("compile p.go failed: %v. output:\n%s", err, out) + } + cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-I", tmpdir, "-p=main", "-o", xObj, xSrc) + out, err = cmd.CombinedOutput() + if err != nil { + t.Fatalf("compile x.go failed: %v. output:\n%s", err, out) + } + cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-L", tmpdir, "-o", exe, xObj) + out, err = cmd.CombinedOutput() + if err == nil { + t.Fatalf("link did not fail") + } + if !bytes.Contains(out, []byte("unlinkable object")) { + t.Errorf("did not see expected error message. out:\n%s", out) + } + + // It is okay to omit -p for (only) main package. + cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-p=p", "-o", pObj, pSrc) + out, err = cmd.CombinedOutput() + if err != nil { + t.Fatalf("compile p.go failed: %v. output:\n%s", err, out) + } + cmd = exec.Command(testenv.GoToolPath(t), "tool", "compile", "-I", tmpdir, "-o", xObj, xSrc) // without -p + out, err = cmd.CombinedOutput() + if err != nil { + t.Fatalf("compile failed: %v. output:\n%s", err, out) + } + cmd = exec.Command(testenv.GoToolPath(t), "tool", "link", "-L", tmpdir, "-o", exe, xObj) + out, err = cmd.CombinedOutput() + if err != nil { + t.Errorf("link failed: %v. output:\n%s", err, out) + } +} diff --git a/src/cmd/nm/nm_test.go b/src/cmd/nm/nm_test.go index 0d51b07a44..226c2c3bcd 100644 --- a/src/cmd/nm/nm_test.go +++ b/src/cmd/nm/nm_test.go @@ -66,7 +66,7 @@ func TestNonGoExecs(t *testing.T) { "internal/xcoff/testdata/gcc-ppc64-aix-dwarf2-exec", } for _, f := range testfiles { - exepath := filepath.Join(runtime.GOROOT(), "src", f) + exepath := filepath.Join(testenv.GOROOT(t), "src", f) if strings.HasSuffix(f, ".base64") { tf, err := obscuretestdata.DecodeToTempFile(exepath) if err != nil { diff --git a/src/cmd/objdump/objdump_test.go b/src/cmd/objdump/objdump_test.go index ff43161030..313cc7a809 100644 --- a/src/cmd/objdump/objdump_test.go +++ b/src/cmd/objdump/objdump_test.go @@ -267,7 +267,7 @@ func TestDisasmGoobj(t *testing.T) { mustHaveDisasm(t) hello := filepath.Join(tmp, "hello.o") - args := []string{"tool", "compile", "-o", hello} + args := []string{"tool", "compile", "-p=main", "-o", hello} args = append(args, "testdata/fmthello.go") out, err := exec.Command(testenv.GoToolPath(t), args...).CombinedOutput() if err != nil { diff --git a/src/cmd/pack/pack_test.go b/src/cmd/pack/pack_test.go index 81e78f53e2..6eec1f50ef 100644 --- a/src/cmd/pack/pack_test.go +++ b/src/cmd/pack/pack_test.go @@ -179,7 +179,7 @@ func TestHello(t *testing.T) { goBin := testenv.GoToolPath(t) run(goBin, "build", "cmd/pack") // writes pack binary to dir - run(goBin, "tool", "compile", "hello.go") + run(goBin, "tool", "compile", "-p=main", "hello.go") run("./pack", "grc", "hello.a", "hello.o") run(goBin, "tool", "link", "-o", "a.out", "hello.a") out := run("./a.out") @@ -246,9 +246,9 @@ func TestLargeDefs(t *testing.T) { goBin := testenv.GoToolPath(t) run(goBin, "build", "cmd/pack") // writes pack binary to dir - run(goBin, "tool", "compile", "large.go") + run(goBin, "tool", "compile", "-p=large", "large.go") run("./pack", "grc", "large.a", "large.o") - run(goBin, "tool", "compile", "-I", ".", "main.go") + run(goBin, "tool", "compile", "-p=main", "-I", ".", "main.go") run(goBin, "tool", "link", "-L", ".", "-o", "a.out", "main.o") out := run("./a.out") if out != "ok\n" { @@ -281,9 +281,9 @@ func TestIssue21703(t *testing.T) { goBin := testenv.GoToolPath(t) run(goBin, "build", "cmd/pack") // writes pack binary to dir - run(goBin, "tool", "compile", "a.go") + run(goBin, "tool", "compile", "-p=a", "a.go") run("./pack", "c", "a.a", "a.o") - run(goBin, "tool", "compile", "-I", ".", "b.go") + run(goBin, "tool", "compile", "-p=b", "-I", ".", "b.go") } // Test the "c" command can "see through" the archive generated by the compiler. @@ -305,7 +305,7 @@ func TestCreateWithCompilerObj(t *testing.T) { goBin := testenv.GoToolPath(t) run(goBin, "build", "cmd/pack") // writes pack binary to dir - run(goBin, "tool", "compile", "-pack", "-o", "p.a", "p.go") + run(goBin, "tool", "compile", "-pack", "-p=p", "-o", "p.a", "p.go") run("./pack", "c", "packed.a", "p.a") fi, err := os.Stat(filepath.Join(dir, "p.a")) if err != nil { @@ -323,7 +323,7 @@ func TestCreateWithCompilerObj(t *testing.T) { } // Test -linkobj flag as well. - run(goBin, "tool", "compile", "-linkobj", "p2.a", "-o", "p.x", "p.go") + run(goBin, "tool", "compile", "-p=p", "-linkobj", "p2.a", "-o", "p.x", "p.go") run("./pack", "c", "packed2.a", "p2.a") fi, err = os.Stat(filepath.Join(dir, "p2.a")) if err != nil { @@ -369,7 +369,7 @@ func TestRWithNonexistentFile(t *testing.T) { goBin := testenv.GoToolPath(t) run(goBin, "build", "cmd/pack") // writes pack binary to dir - run(goBin, "tool", "compile", "-o", "p.o", "p.go") + run(goBin, "tool", "compile", "-p=p", "-o", "p.o", "p.go") run("./pack", "r", "p.a", "p.o") // should succeed } diff --git a/src/cmd/pprof/pprof.go b/src/cmd/pprof/pprof.go index e72c765adc..c073c964b4 100644 --- a/src/cmd/pprof/pprof.go +++ b/src/cmd/pprof/pprof.go @@ -149,7 +149,7 @@ type objTool struct { disasmCache map[string]*objfile.Disasm } -func (*objTool) Open(name string, start, limit, offset uint64) (driver.ObjFile, error) { +func (*objTool) Open(name string, start, limit, offset uint64, relocationSymbol string) (driver.ObjFile, error) { of, err := objfile.Open(name) if err != nil { return nil, err diff --git a/src/cmd/vendor/github.com/google/pprof/driver/driver.go b/src/cmd/vendor/github.com/google/pprof/driver/driver.go index fc05f919ba..5a8222f70a 100644 --- a/src/cmd/vendor/github.com/google/pprof/driver/driver.go +++ b/src/cmd/vendor/github.com/google/pprof/driver/driver.go @@ -137,8 +137,10 @@ type MappingSources map[string][]struct { type ObjTool interface { // Open opens the named object file. If the object is a shared // library, start/limit/offset are the addresses where it is mapped - // into memory in the address space being inspected. - Open(file string, start, limit, offset uint64) (ObjFile, error) + // into memory in the address space being inspected. If the object + // is a linux kernel, relocationSymbol is the name of the symbol + // corresponding to the start address. + Open(file string, start, limit, offset uint64, relocationSymbol string) (ObjFile, error) // Disasm disassembles the named object file, starting at // the start address and stopping at (before) the end address. @@ -232,8 +234,8 @@ type internalObjTool struct { ObjTool } -func (o *internalObjTool) Open(file string, start, limit, offset uint64) (plugin.ObjFile, error) { - f, err := o.ObjTool.Open(file, start, limit, offset) +func (o *internalObjTool) Open(file string, start, limit, offset uint64, relocationSymbol string) (plugin.ObjFile, error) { + f, err := o.ObjTool.Open(file, start, limit, offset, relocationSymbol) if err != nil { return nil, err } diff --git a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go index e920eeb2fa..efa9167af7 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/binutils/binutils.go @@ -284,7 +284,7 @@ func (bu *Binutils) Disasm(file string, start, end uint64, intelSyntax bool) ([] } // Open satisfies the plugin.ObjTool interface. -func (bu *Binutils) Open(name string, start, limit, offset uint64) (plugin.ObjFile, error) { +func (bu *Binutils) Open(name string, start, limit, offset uint64, relocationSymbol string) (plugin.ObjFile, error) { b := bu.get() // Make sure file is a supported executable. @@ -316,7 +316,7 @@ func (bu *Binutils) Open(name string, start, limit, offset uint64) (plugin.ObjFi // Match against supported file types. if elfMagic == elf.ELFMAG { - f, err := b.openELF(name, start, limit, offset) + f, err := b.openELF(name, start, limit, offset, relocationSymbol) if err != nil { return nil, fmt.Errorf("error reading ELF file %s: %v", name, err) } @@ -425,7 +425,7 @@ func (b *binrep) openMachO(name string, start, limit, offset uint64) (plugin.Obj return b.openMachOCommon(name, of, start, limit, offset) } -func (b *binrep) openELF(name string, start, limit, offset uint64) (plugin.ObjFile, error) { +func (b *binrep) openELF(name string, start, limit, offset uint64, relocationSymbol string) (plugin.ObjFile, error) { ef, err := elfOpen(name) if err != nil { return nil, fmt.Errorf("error parsing %s: %v", name, err) @@ -440,8 +440,8 @@ func (b *binrep) openELF(name string, start, limit, offset uint64) (plugin.ObjFi } var ( - stextOffset *uint64 - pageAligned = func(addr uint64) bool { return addr%4096 == 0 } + kernelOffset *uint64 + pageAligned = func(addr uint64) bool { return addr%4096 == 0 } ) if strings.Contains(name, "vmlinux") || !pageAligned(start) || !pageAligned(limit) || !pageAligned(offset) { // Reading all Symbols is expensive, and we only rarely need it so @@ -455,10 +455,18 @@ func (b *binrep) openELF(name string, start, limit, offset uint64) (plugin.ObjFi if err != nil && err != elf.ErrNoSymbols { return nil, err } + + // The kernel relocation symbol (the mapping start address) can be either + // _text or _stext. When profiles are generated by `perf`, which one was used is + // distinguished by the mapping name for the kernel image: + // '[kernel.kallsyms]_text' or '[kernel.kallsyms]_stext', respectively. If we haven't + // been able to parse it from the mapping, we default to _stext. + if relocationSymbol == "" { + relocationSymbol = "_stext" + } for _, s := range symbols { - if s.Name == "_stext" { - // The kernel may use _stext as the mapping start address. - stextOffset = &s.Value + if s.Name == relocationSymbol { + kernelOffset = &s.Value break } } @@ -469,7 +477,7 @@ func (b *binrep) openELF(name string, start, limit, offset uint64) (plugin.ObjFi // value until we have a sample address for this mapping, so that we can // correctly identify the associated program segment that is needed to compute // the base. - if _, err := elfexec.GetBase(&ef.FileHeader, elfexec.FindTextProgHeader(ef), stextOffset, start, limit, offset); err != nil { + if _, err := elfexec.GetBase(&ef.FileHeader, elfexec.FindTextProgHeader(ef), kernelOffset, start, limit, offset); err != nil { return nil, fmt.Errorf("could not identify base for %s: %v", name, err) } @@ -478,14 +486,14 @@ func (b *binrep) openELF(name string, start, limit, offset uint64) (plugin.ObjFi b: b, name: name, buildID: buildID, - m: &elfMapping{start: start, limit: limit, offset: offset, stextOffset: stextOffset}, + m: &elfMapping{start: start, limit: limit, offset: offset, kernelOffset: kernelOffset}, }}, nil } return &fileAddr2Line{file: file{ b: b, name: name, buildID: buildID, - m: &elfMapping{start: start, limit: limit, offset: offset, stextOffset: stextOffset}, + m: &elfMapping{start: start, limit: limit, offset: offset, kernelOffset: kernelOffset}, }}, nil } @@ -521,8 +529,8 @@ func (b *binrep) openPE(name string, start, limit, offset uint64) (plugin.ObjFil type elfMapping struct { // Runtime mapping parameters. start, limit, offset uint64 - // Offset of _stext symbol. Only defined for kernel images, nil otherwise. - stextOffset *uint64 + // Offset of kernel relocation symbol. Only defined for kernel images, nil otherwise. + kernelOffset *uint64 } // findProgramHeader returns the program segment that matches the current @@ -535,7 +543,7 @@ func (m *elfMapping) findProgramHeader(ef *elf.File, addr uint64) (*elf.ProgHead // it's a kernel / .ko module mapping, because with quipper address remapping // enabled, the address would be in the lower half of the address space. - if m.stextOffset != nil || m.start >= m.limit || m.limit >= (uint64(1)<<63) { + if m.kernelOffset != nil || m.start >= m.limit || m.limit >= (uint64(1)<<63) { // For the kernel, find the program segment that includes the .text section. return elfexec.FindTextProgHeader(ef), nil } @@ -601,7 +609,7 @@ func (f *file) computeBase(addr uint64) error { return fmt.Errorf("failed to find program header for file %q, ELF mapping %#v, address %x: %v", f.name, *f.m, addr, err) } - base, err := elfexec.GetBase(&ef.FileHeader, ph, f.m.stextOffset, f.m.start, f.m.limit, f.m.offset) + base, err := elfexec.GetBase(&ef.FileHeader, ph, f.m.kernelOffset, f.m.start, f.m.limit, f.m.offset) if err != nil { return err } diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go index 492400c5f3..237cc33233 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/cli.go @@ -98,7 +98,7 @@ func parseFlags(o *plugin.Options) (*source, []string, error) { // Recognize first argument as an executable or buildid override. if len(args) > 1 { arg0 := args[0] - if file, err := o.Obj.Open(arg0, 0, ^uint64(0), 0); err == nil { + if file, err := o.Obj.Open(arg0, 0, ^uint64(0), 0, ""); err == nil { file.Close() execName = arg0 args = args[1:] diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go index b8a69e87fc..0b361651bc 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/fetch.go @@ -420,12 +420,14 @@ mapping: fileNames = append(fileNames, filepath.Join(path, m.File)) } for _, name := range fileNames { - if f, err := obj.Open(name, m.Start, m.Limit, m.Offset); err == nil { + if f, err := obj.Open(name, m.Start, m.Limit, m.Offset, m.KernelRelocationSymbol); err == nil { defer f.Close() fileBuildID := f.BuildID() if m.BuildID != "" && m.BuildID != fileBuildID { ui.PrintErr("Ignoring local file " + name + ": build-id mismatch (" + m.BuildID + " != " + fileBuildID + ")") } else { + // Explicitly do not update KernelRelocationSymbol -- + // the new local file name is most likely missing it. m.File = name continue mapping } @@ -449,6 +451,8 @@ mapping: if execName, buildID := s.ExecName, s.BuildID; execName != "" || buildID != "" { m := p.Mapping[0] if execName != "" { + // Explicitly do not update KernelRelocationSymbol -- + // the source override is most likely missing it. m.File = execName } if buildID != "" { diff --git a/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go b/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go index b9c73271b8..63df668321 100644 --- a/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go +++ b/src/cmd/vendor/github.com/google/pprof/internal/driver/webhtml.go @@ -17,13 +17,11 @@ package driver import ( "html/template" - "github.com/google/pprof/third_party/d3" "github.com/google/pprof/third_party/d3flamegraph" ) // addTemplates adds a set of template definitions to templates. func addTemplates(templates *template.Template) { - template.Must(templates.Parse(`{{define "d3script"}}` + d3.JSSource + `{{end}}`)) template.Must(templates.Parse(`{{define "d3flamegraphscript"}}` + d3flamegraph.JSSource + `{{end}}`)) template.Must(templates.Parse(`{{define "d3flamegraphcss"}}` + d3flamegraph.CSSSource + `{{end}}`)) template.Must(templates.Parse(` @@ -1329,40 +1327,29 @@ function viewer(baseUrl, nodes) { {{template "script" .}} -