mirror of
https://github.com/golang/go.git
synced 2024-09-22 02:48:50 +00:00
Merge remote-tracking branch 'origin/master' into feature/sync-atomic-and-or-loong64
This commit is contained in:
commit
9755db5406
45
.github/ISSUE_TEMPLATE/00-bug.md
vendored
45
.github/ISSUE_TEMPLATE/00-bug.md
vendored
@ -1,45 +0,0 @@
|
|||||||
---
|
|
||||||
name: Bugs
|
|
||||||
about: The go command, standard library, or anything else
|
|
||||||
title: "affected/package: "
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please answer these questions before submitting your issue. Thanks!
|
|
||||||
-->
|
|
||||||
|
|
||||||
### What version of Go are you using (`go version`)?
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
$ go version
|
|
||||||
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
### Does this issue reproduce with the latest release?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### What operating system and processor architecture are you using (`go env`)?
|
|
||||||
|
|
||||||
<details><summary><code>go env</code> Output</summary><br><pre>
|
|
||||||
$ go env
|
|
||||||
|
|
||||||
</pre></details>
|
|
||||||
|
|
||||||
### What did you do?
|
|
||||||
|
|
||||||
<!--
|
|
||||||
If possible, provide a recipe for reproducing the error.
|
|
||||||
A complete runnable program is good.
|
|
||||||
A link on go.dev/play is best.
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### What did you expect to see?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### What did you see instead?
|
|
||||||
|
|
||||||
|
|
94
.github/ISSUE_TEMPLATE/00-bug.yml
vendored
Normal file
94
.github/ISSUE_TEMPLATE/00-bug.yml
vendored
Normal file
@ -0,0 +1,94 @@
|
|||||||
|
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/configuring-issue-templates-for-your-repository#creating-issue-forms
|
||||||
|
# https://docs.github.com/en/communities/using-templates-to-encourage-useful-issues-and-pull-requests/syntax-for-githubs-form-schema
|
||||||
|
name: Bugs
|
||||||
|
description: The go command, standard library, or anything else
|
||||||
|
title: "import/path: issue title"
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
Thanks for helping us improve! 🙏 Please answer these questions and provide as much information as possible about your problem.
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: go-version
|
||||||
|
attributes:
|
||||||
|
label: Go version
|
||||||
|
description: |
|
||||||
|
What version of Go are you using (`go version`)?
|
||||||
|
|
||||||
|
Note: we only [support](https://go.dev/doc/devel/release#policy) the two most recent major releases.
|
||||||
|
placeholder: ex. go version go1.20.7 darwin/arm64
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: go-env
|
||||||
|
attributes:
|
||||||
|
label: "Output of `go env` in your module/workspace:"
|
||||||
|
placeholder: |
|
||||||
|
GO111MODULE=""
|
||||||
|
GOARCH="arm64"
|
||||||
|
GOBIN="/Users/gopher/go/bin"
|
||||||
|
GOCACHE="/Users/gopher/go/cache"
|
||||||
|
GOENV="/Users/gopher/Library/Application Support/go/env"
|
||||||
|
GOEXE=""
|
||||||
|
GOEXPERIMENT=""
|
||||||
|
GOFLAGS=""
|
||||||
|
GOHOSTARCH="arm64"
|
||||||
|
GOHOSTOS="darwin"
|
||||||
|
GOINSECURE=""
|
||||||
|
GOMODCACHE="/Users/gopher/go/pkg/mod"
|
||||||
|
GONOPROXY=""
|
||||||
|
GONOSUMDB=""
|
||||||
|
GOOS="darwin"
|
||||||
|
GOPATH="/Users/gopher/go"
|
||||||
|
GOPRIVATE=""
|
||||||
|
GOPROXY="https://proxy.golang.org,direct"
|
||||||
|
GOROOT="/usr/local/go"
|
||||||
|
GOSUMDB="sum.golang.org"
|
||||||
|
GOTMPDIR=""
|
||||||
|
GOTOOLDIR="/usr/local/go/pkg/tool/darwin_arm64"
|
||||||
|
GOVCS=""
|
||||||
|
GOVERSION="go1.20.7"
|
||||||
|
GCCGO="gccgo"
|
||||||
|
AR="ar"
|
||||||
|
CC="clang"
|
||||||
|
CXX="clang++"
|
||||||
|
CGO_ENABLED="1"
|
||||||
|
GOMOD="/dev/null"
|
||||||
|
GOWORK=""
|
||||||
|
CGO_CFLAGS="-O2 -g"
|
||||||
|
CGO_CPPFLAGS=""
|
||||||
|
CGO_CXXFLAGS="-O2 -g"
|
||||||
|
CGO_FFLAGS="-O2 -g"
|
||||||
|
CGO_LDFLAGS="-O2 -g"
|
||||||
|
PKG_CONFIG="pkg-config"
|
||||||
|
GOGCCFLAGS="-fPIC -arch arm64 -pthread -fno-caret-diagnostics -Qunused-arguments -fmessage-length=0 -fdebug-prefix-map=/var/folders/44/nbbyll_10jd0z8rj_qxm43740000gn/T/go-build2331607515=/tmp/go-build -gno-record-gcc-switches -fno-common"
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: what-did-you-do
|
||||||
|
attributes:
|
||||||
|
label: "What did you do?"
|
||||||
|
description: "If possible, provide a recipe for reproducing the error. A complete runnable program is good. A link on [go.dev/play](https://go.dev/play) is best."
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: actual-behavior
|
||||||
|
attributes:
|
||||||
|
label: "What did you see happen?"
|
||||||
|
description: Command invocations and their associated output, functions with their arguments and return results, full stacktraces for panics (upload a file if it is very long), etc. Prefer copying text output over using screenshots.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: expected-behavior
|
||||||
|
attributes:
|
||||||
|
label: "What did you expect to see?"
|
||||||
|
description: Why is the current output incorrect, and any additional context we may need to understand the issue.
|
||||||
|
validations:
|
||||||
|
required: true
|
49
.github/ISSUE_TEMPLATE/01-pkgsite.md
vendored
49
.github/ISSUE_TEMPLATE/01-pkgsite.md
vendored
@ -1,49 +0,0 @@
|
|||||||
---
|
|
||||||
name: Pkg.go.dev bugs or feature requests
|
|
||||||
about: Issues or feature requests for the documentation site
|
|
||||||
title: "x/pkgsite: "
|
|
||||||
labels: pkgsite
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please answer these questions before submitting your issue. Thanks!
|
|
||||||
-->
|
|
||||||
|
|
||||||
### What is the URL of the page with the issue?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### What is your user agent?
|
|
||||||
|
|
||||||
<!--
|
|
||||||
You can find your user agent here:
|
|
||||||
https://www.google.com/search?q=what+is+my+user+agent
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Screenshot
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please paste a screenshot of the page.
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### What did you do?
|
|
||||||
|
|
||||||
<!--
|
|
||||||
If possible, provide a recipe for reproducing the error.
|
|
||||||
|
|
||||||
Starting with a Private/Incognito tab/window may help rule out problematic browser extensions.
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### What did you expect to see?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### What did you see instead?
|
|
||||||
|
|
||||||
|
|
47
.github/ISSUE_TEMPLATE/01-pkgsite.yml
vendored
Normal file
47
.github/ISSUE_TEMPLATE/01-pkgsite.yml
vendored
Normal file
@ -0,0 +1,47 @@
|
|||||||
|
name: Pkg.go.dev bugs or feature requests
|
||||||
|
description: Issues or feature requests for the documentation site
|
||||||
|
title: "x/pkgsite: issue title"
|
||||||
|
labels: ["pkgsite"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: "Please answer these questions before submitting your issue. Thanks!"
|
||||||
|
- type: input
|
||||||
|
id: url
|
||||||
|
attributes:
|
||||||
|
label: "What is the URL of the page with the issue?"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: input
|
||||||
|
id: user-agent
|
||||||
|
attributes:
|
||||||
|
label: "What is your user agent?"
|
||||||
|
description: "You can find your user agent here: https://www.google.com/search?q=what+is+my+user+agent"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: screenshot
|
||||||
|
attributes:
|
||||||
|
label: "Screenshot"
|
||||||
|
description: "Please paste a screenshot of the page."
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
id: what-did-you-do
|
||||||
|
attributes:
|
||||||
|
label: "What did you do?"
|
||||||
|
description: "If possible, provide a recipe for reproducing the error. Starting with a Private/Incognito tab/window may help rule out problematic browser extensions."
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: actual-behavior
|
||||||
|
attributes:
|
||||||
|
label: "What did you see happen?"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: expected-behavior
|
||||||
|
attributes:
|
||||||
|
label: "What did you expect to see?"
|
||||||
|
validations:
|
||||||
|
required: true
|
39
.github/ISSUE_TEMPLATE/02-pkgsite-removal.md
vendored
39
.github/ISSUE_TEMPLATE/02-pkgsite-removal.md
vendored
@ -1,39 +0,0 @@
|
|||||||
---
|
|
||||||
name: Pkg.go.dev package removal request
|
|
||||||
about: Request a package be removed from the documentation site (pkg.go.dev)
|
|
||||||
title: "x/pkgsite: package removal request for [type path here]"
|
|
||||||
labels: pkgsite/package-removal
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please answer these questions before submitting your issue. Thanks!
|
|
||||||
-->
|
|
||||||
|
|
||||||
### What is the path of the package that you would like to have removed?
|
|
||||||
|
|
||||||
<!---
|
|
||||||
We can remove packages with a shared path prefix.
|
|
||||||
For example, a request for "github.com/author" would remove all pkg.go.dev pages with that package path prefix.
|
|
||||||
--->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Are you the owner of this package?
|
|
||||||
|
|
||||||
<!---
|
|
||||||
Only the package owners can request to have their packages removed from pkg.go.dev.
|
|
||||||
--->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### What is the reason that you could not retract this package instead?
|
|
||||||
|
|
||||||
<!---
|
|
||||||
If you would like to have your module removed from pkg.go.dev, we recommend that you retract them, so that they can be removed from the go command and proxy.golang.org as well.
|
|
||||||
|
|
||||||
Retracting a module version involves adding a retract directive to your go.mod file and publishing a new version. For example: https://github.com/jba/retract-demo/blob/main/go.mod#L5-L8
|
|
||||||
|
|
||||||
See https://pkg.go.dev/about#removing-a-package for additional tips on retractions.
|
|
||||||
--->
|
|
||||||
|
|
||||||
|
|
42
.github/ISSUE_TEMPLATE/02-pkgsite-removal.yml
vendored
Normal file
42
.github/ISSUE_TEMPLATE/02-pkgsite-removal.yml
vendored
Normal file
@ -0,0 +1,42 @@
|
|||||||
|
name: Pkg.go.dev package removal request
|
||||||
|
description: Request a package be removed from the documentation site (pkg.go.dev)
|
||||||
|
title: "x/pkgsite: package removal request for [type path here]"
|
||||||
|
labels: ["pkgsite/package-removal"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: "Please answer these questions before submitting your issue. Thanks!"
|
||||||
|
- type: input
|
||||||
|
id: package-path
|
||||||
|
attributes:
|
||||||
|
label: "What is the path of the package that you would like to have removed?"
|
||||||
|
description: |
|
||||||
|
We can remove packages with a shared path prefix.
|
||||||
|
For example, a request for 'github.com/author' would remove all pkg.go.dev pages with that package path prefix.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: package-owner
|
||||||
|
attributes:
|
||||||
|
label: "Are you the owner of this package?"
|
||||||
|
description: |
|
||||||
|
Only the package owners can request to have their packages removed from pkg.go.dev.
|
||||||
|
If the package path doesn't include your github username, please provide some other form of proof of ownership.
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: retraction-reason
|
||||||
|
attributes:
|
||||||
|
label: "What is the reason that you could not retract this package instead?"
|
||||||
|
description: |
|
||||||
|
Requesting we remove a module here only hides the generated documentation on pkg.go.dev.
|
||||||
|
It does not affect the behaviour of proxy.golang.org or the go command.
|
||||||
|
Instead we recommend using the retract directive which will be processed by all 3 of the above.
|
||||||
|
|
||||||
|
If you have deleted your repo, please recreate it and publish a retraction.
|
||||||
|
|
||||||
|
Retracting a module version involves adding a retract directive to your go.mod file and publishing a new version.
|
||||||
|
For example: https://github.com/jba/retract-demo/blob/main/go.mod#L5-L8.
|
||||||
|
See https://pkg.go.dev/about#removing-a-package for additional tips on retractions.
|
||||||
|
validations:
|
||||||
|
required: true
|
63
.github/ISSUE_TEMPLATE/03-gopls.md
vendored
63
.github/ISSUE_TEMPLATE/03-gopls.md
vendored
@ -1,63 +0,0 @@
|
|||||||
---
|
|
||||||
name: Gopls bugs or feature requests
|
|
||||||
about: Issues or feature requests for the Go language server (gopls)
|
|
||||||
title: "x/tools/gopls: "
|
|
||||||
labels:
|
|
||||||
- gopls
|
|
||||||
- Tools
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please answer these questions before submitting your issue. Thanks!
|
|
||||||
-->
|
|
||||||
|
|
||||||
### gopls version
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Output of `gopls -v version` on the command line
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### go env
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Output of `go env` on the command line in your workspace directory
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
### What did you do?
|
|
||||||
|
|
||||||
<!--
|
|
||||||
If possible, provide a recipe for reproducing the error.
|
|
||||||
A complete runnable program is good.
|
|
||||||
A link on go.dev/play is better.
|
|
||||||
A failing unit test is the best.
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### What did you expect to see?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### What did you see instead?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Editor and settings
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Your editor and any settings you have configured (for example, your VSCode settings.json file)
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### Logs
|
|
||||||
|
|
||||||
<!--
|
|
||||||
If possible please include gopls logs. Instructions for capturing them can be found here:
|
|
||||||
https://github.com/golang/tools/blob/master/gopls/doc/troubleshooting.md#capture-logs
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
56
.github/ISSUE_TEMPLATE/03-gopls.yml
vendored
Normal file
56
.github/ISSUE_TEMPLATE/03-gopls.yml
vendored
Normal file
@ -0,0 +1,56 @@
|
|||||||
|
name: Gopls bugs or feature requests
|
||||||
|
description: Issues or feature requests for the Go language server (gopls)
|
||||||
|
title: "x/tools/gopls: issue title"
|
||||||
|
labels: ["gopls", "Tools"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: "Please answer these questions before submitting your issue. Thanks!"
|
||||||
|
- type: input
|
||||||
|
id: gopls-version
|
||||||
|
attributes:
|
||||||
|
label: "gopls version"
|
||||||
|
description: "Output of `gopls -v version` on the command line"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: go-env
|
||||||
|
attributes:
|
||||||
|
label: "go env"
|
||||||
|
description: "Output of `go env` on the command line in your workspace directory"
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: what-did-you-do
|
||||||
|
attributes:
|
||||||
|
label: "What did you do?"
|
||||||
|
description: "If possible, provide a recipe for reproducing the error. A complete runnable program is good. A link on [go.dev/play](https://go.dev/play) is better. A failing unit test is the best."
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: actual-behavior
|
||||||
|
attributes:
|
||||||
|
label: "What did you see happen?"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: expected-behavior
|
||||||
|
attributes:
|
||||||
|
label: "What did you expect to see?"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: editor-and-settings
|
||||||
|
attributes:
|
||||||
|
label: "Editor and settings"
|
||||||
|
description: "Your editor and any settings you have configured (for example, your VSCode settings.json file)"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
- type: textarea
|
||||||
|
id: logs
|
||||||
|
attributes:
|
||||||
|
label: "Logs"
|
||||||
|
description: "If possible please include gopls logs. Instructions for capturing them can be found here: https://github.com/golang/tools/blob/master/gopls/doc/troubleshooting.md#capture-logs"
|
||||||
|
validations:
|
||||||
|
required: false
|
51
.github/ISSUE_TEMPLATE/04-vuln.md
vendored
51
.github/ISSUE_TEMPLATE/04-vuln.md
vendored
@ -1,51 +0,0 @@
|
|||||||
---
|
|
||||||
name: Go vulnerability management - bugs and feature requests
|
|
||||||
about: Issues or feature requests about Go vulnerability management
|
|
||||||
title: "x/vuln: "
|
|
||||||
labels: "vulncheck or vulndb"
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Please answer these questions before submitting your issue. Thanks!
|
|
||||||
|
|
||||||
To add a new vulnerability to the Go vulnerability database
|
|
||||||
(https://vuln.go.dev), see https://go.dev/s/vulndb-report-new.
|
|
||||||
|
|
||||||
To report an issue about a report, see https://go.dev/s/vulndb-report-feedback.
|
|
||||||
-->
|
|
||||||
|
|
||||||
### What version of Go are you using (`go version`)?
|
|
||||||
|
|
||||||
<pre>
|
|
||||||
$ go version
|
|
||||||
|
|
||||||
</pre>
|
|
||||||
|
|
||||||
### Does this issue reproduce at the latest version of golang.org/x/vuln?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### What operating system and processor architecture are you using (`go env`)?
|
|
||||||
|
|
||||||
<details><summary><code>go env</code> Output</summary><br><pre>
|
|
||||||
$ go env
|
|
||||||
|
|
||||||
</pre></details>
|
|
||||||
|
|
||||||
### What did you do?
|
|
||||||
|
|
||||||
<!--
|
|
||||||
If possible, provide a recipe for reproducing the error.
|
|
||||||
A complete runnable program is good.
|
|
||||||
A link on go.dev/play is best.
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### What did you expect to see?
|
|
||||||
|
|
||||||
|
|
||||||
|
|
||||||
### What did you see instead?
|
|
||||||
|
|
||||||
|
|
52
.github/ISSUE_TEMPLATE/04-vuln.yml
vendored
Normal file
52
.github/ISSUE_TEMPLATE/04-vuln.yml
vendored
Normal file
@ -0,0 +1,52 @@
|
|||||||
|
name: Go vulnerability management - bugs and feature requests
|
||||||
|
description: Issues or feature requests about Go vulnerability management
|
||||||
|
title: "x/vuln: issue title"
|
||||||
|
labels: ["vulncheck or vulndb"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: "Please answer these questions before submitting your issue. Thanks! To add a new vulnerability to the Go vulnerability database (https://vuln.go.dev), see https://go.dev/s/vulndb-report-new. To report an issue about a report, see https://go.dev/s/vulndb-report-feedback."
|
||||||
|
- type: textarea
|
||||||
|
id: govulncheck-version
|
||||||
|
attributes:
|
||||||
|
label: govulncheck version
|
||||||
|
description: What version of govulncheck are you using (`govulncheck -version`)?
|
||||||
|
placeholder: |
|
||||||
|
Go: devel go1.22-0262ea1ff9 Thu Oct 26 18:46:50 2023 +0000
|
||||||
|
Scanner: govulncheck@v1.0.2-0.20231108200754-fcf7dff7b242
|
||||||
|
DB: https://vuln.go.dev
|
||||||
|
DB updated: 2023-11-21 15:39:17 +0000 UTC
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: reproduce-latest-version
|
||||||
|
attributes:
|
||||||
|
label: "Does this issue reproduce at the latest version of golang.org/x/vuln?"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: go-env
|
||||||
|
attributes:
|
||||||
|
label: "Output of `go env` in your module/workspace:"
|
||||||
|
render: shell
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: what-did-you-do
|
||||||
|
attributes:
|
||||||
|
label: "What did you do?"
|
||||||
|
description: "If possible, provide a recipe for reproducing the error. A complete runnable program is good. A link on [go.dev/play](https://go.dev/play) is best."
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: actual-behavior
|
||||||
|
attributes:
|
||||||
|
label: "What did you see happen?"
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
- type: textarea
|
||||||
|
id: expected-behavior
|
||||||
|
attributes:
|
||||||
|
label: "What did you expect to see?"
|
||||||
|
validations:
|
||||||
|
required: true
|
13
.github/ISSUE_TEMPLATE/10-proposal.md
vendored
13
.github/ISSUE_TEMPLATE/10-proposal.md
vendored
@ -1,13 +0,0 @@
|
|||||||
---
|
|
||||||
name: Proposals
|
|
||||||
about: New external API or other notable changes
|
|
||||||
title: "proposal: affected/package: "
|
|
||||||
labels: Proposal
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Our proposal process is documented here:
|
|
||||||
https://go.dev/s/proposal-process
|
|
||||||
-->
|
|
||||||
|
|
||||||
|
|
15
.github/ISSUE_TEMPLATE/10-proposal.yml
vendored
Normal file
15
.github/ISSUE_TEMPLATE/10-proposal.yml
vendored
Normal file
@ -0,0 +1,15 @@
|
|||||||
|
name: Proposals
|
||||||
|
description: New external API or other notable changes
|
||||||
|
title: "proposal: import/path: proposal title"
|
||||||
|
labels: ["Proposal"]
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: "Our proposal process is documented here: https://go.dev/s/proposal-process"
|
||||||
|
- type: textarea
|
||||||
|
id: proposal-details
|
||||||
|
attributes:
|
||||||
|
label: "Proposal Details"
|
||||||
|
description: "Please provide the details of your proposal here."
|
||||||
|
validations:
|
||||||
|
required: true
|
55
.github/ISSUE_TEMPLATE/11-language-change.md
vendored
55
.github/ISSUE_TEMPLATE/11-language-change.md
vendored
@ -1,55 +0,0 @@
|
|||||||
---
|
|
||||||
name: Language Change Proposals
|
|
||||||
about: Changes to the language
|
|
||||||
title: "proposal: Go 2: "
|
|
||||||
labels:
|
|
||||||
- Proposal
|
|
||||||
- v2
|
|
||||||
- LanguageChange
|
|
||||||
---
|
|
||||||
|
|
||||||
<!--
|
|
||||||
Our process for evaluating language changes can be found here:
|
|
||||||
https://go.googlesource.com/proposal/+/refs/heads/master#language-changes
|
|
||||||
-->
|
|
||||||
|
|
||||||
### Author background
|
|
||||||
|
|
||||||
- **Would you consider yourself a novice, intermediate, or experienced Go programmer?**
|
|
||||||
- **What other languages do you have experience with?**
|
|
||||||
|
|
||||||
### Related proposals
|
|
||||||
|
|
||||||
- **Has this idea, or one like it, been proposed before?**
|
|
||||||
- **If so, how does this proposal differ?**
|
|
||||||
- **Does this affect error handling?**
|
|
||||||
- **If so, how does this differ from previous error handling proposals?**
|
|
||||||
- **Is this about generics?**
|
|
||||||
- **If so, how does this relate to the accepted design and other generics proposals?**
|
|
||||||
|
|
||||||
### Proposal
|
|
||||||
|
|
||||||
- **What is the proposed change?**
|
|
||||||
- **Who does this proposal help, and why?**
|
|
||||||
- **Please describe as precisely as possible the change to the language.**
|
|
||||||
- **What would change in the language spec?**
|
|
||||||
- **Please also describe the change informally, as in a class teaching Go.**
|
|
||||||
- **Is this change backward compatible?**
|
|
||||||
- Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit.
|
|
||||||
Show example code before and after the change.
|
|
||||||
- **Before**
|
|
||||||
- **After**
|
|
||||||
- **Orthogonality: how does this change interact or overlap with existing features?**
|
|
||||||
- **Is the goal of this change a performance improvement?**
|
|
||||||
- **If so, what quantifiable improvement should we expect?**
|
|
||||||
- **How would we measure it?**
|
|
||||||
|
|
||||||
### Costs
|
|
||||||
|
|
||||||
- **Would this change make Go easier or harder to learn, and why?**
|
|
||||||
- **What is the cost of this proposal? (Every language change has a cost).**
|
|
||||||
- **How many tools (such as vet, gopls, gofmt, goimports, etc.) would be affected?**
|
|
||||||
- **What is the compile time cost?**
|
|
||||||
- **What is the run time cost?**
|
|
||||||
- **Can you describe a possible implementation?**
|
|
||||||
- **Do you have a prototype? (This is not required.)**
|
|
165
.github/ISSUE_TEMPLATE/11-language-change.yml
vendored
Normal file
165
.github/ISSUE_TEMPLATE/11-language-change.yml
vendored
Normal file
@ -0,0 +1,165 @@
|
|||||||
|
name: Language Change Proposals
|
||||||
|
description: Changes to the language
|
||||||
|
labels: ["Proposal", "v2", "LanguageChange"]
|
||||||
|
title: "proposal: Go 2: proposal title"
|
||||||
|
|
||||||
|
|
||||||
|
body:
|
||||||
|
- type: markdown
|
||||||
|
attributes:
|
||||||
|
value: |
|
||||||
|
## Our process for evaluating language changes can be found [here](https://go.googlesource.com/proposal/+/refs/heads/master#language-changes)
|
||||||
|
|
||||||
|
- type: dropdown
|
||||||
|
id: author-go-experience
|
||||||
|
attributes:
|
||||||
|
label: "Go Programming Experience"
|
||||||
|
description: "Would you consider yourself a novice, intermediate, or experienced Go programmer?"
|
||||||
|
options:
|
||||||
|
- "Novice"
|
||||||
|
- "Intermediate"
|
||||||
|
- "Experienced"
|
||||||
|
default: 1
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: author-other-languages-experience
|
||||||
|
attributes:
|
||||||
|
label: "Other Languages Experience"
|
||||||
|
description: "What other languages do you have experience with?"
|
||||||
|
placeholder: "Go, Python, JS, Rust"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: checkboxes
|
||||||
|
id: related-idea
|
||||||
|
attributes:
|
||||||
|
label: "Related Idea"
|
||||||
|
options:
|
||||||
|
- label: "Has this idea, or one like it, been proposed before?"
|
||||||
|
- label: "Does this affect error handling?"
|
||||||
|
- label: "Is this about generics?"
|
||||||
|
- label: "Is this change backward compatible? Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit"
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: related-proposals
|
||||||
|
attributes:
|
||||||
|
label: Has this idea, or one like it, been proposed before?
|
||||||
|
description: If so, how does this proposal differ?
|
||||||
|
placeholder: |
|
||||||
|
Yes or No
|
||||||
|
|
||||||
|
If yes,
|
||||||
|
1. Mention the related proposals
|
||||||
|
2. then describe how this proposal differs
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: error-handling-proposal
|
||||||
|
attributes:
|
||||||
|
label: Does this affect error handling?
|
||||||
|
description: If so, how does this differ from previous error handling proposals?
|
||||||
|
placeholder: |
|
||||||
|
Yes or No
|
||||||
|
|
||||||
|
If yes,
|
||||||
|
1.how does this differ from previous error handling proposals?
|
||||||
|
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: generics-proposal
|
||||||
|
attributes:
|
||||||
|
label: Is this about generics?
|
||||||
|
description: If so, how does this relate to the accepted design and other generics proposals?
|
||||||
|
placeholder: |
|
||||||
|
Yes or No
|
||||||
|
|
||||||
|
If yes,
|
||||||
|
1. how does this relate to the accepted design and other generics proposals?
|
||||||
|
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: proposal
|
||||||
|
attributes:
|
||||||
|
label: "Proposal"
|
||||||
|
description: "What is the proposed change? Who does this proposal help, and why? Please describe as precisely as possible the change to the language."
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: language-spec-changes
|
||||||
|
attributes:
|
||||||
|
label: "Language Spec Changes"
|
||||||
|
description: "What would change in the language spec?"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: informal-change
|
||||||
|
attributes:
|
||||||
|
label: "Informal Change"
|
||||||
|
description: "Please also describe the change informally, as in a class teaching Go."
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: go-backwards-compatiblity
|
||||||
|
attributes:
|
||||||
|
label: Is this change backward compatible?
|
||||||
|
description: Breaking the Go 1 compatibility guarantee is a large cost and requires a large benefit.
|
||||||
|
placeholder: |
|
||||||
|
Yes or No
|
||||||
|
|
||||||
|
If yes,
|
||||||
|
1. Show example code before and after the change.
|
||||||
|
|
||||||
|
validations:
|
||||||
|
required: true
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: orthogonality
|
||||||
|
attributes:
|
||||||
|
label: "Orthogonality: How does this change interact or overlap with existing features?"
|
||||||
|
description: "Is the goal of this change a performance improvement? If so, what quantifiable improvement should we expect? How would we measure it?"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: learning-curve
|
||||||
|
attributes:
|
||||||
|
label: "Would this change make Go easier or harder to learn, and why?"
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: cost-description
|
||||||
|
attributes:
|
||||||
|
label: "Cost Description"
|
||||||
|
description: "What is the cost of this proposal? (Every language change has a cost)"
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: go-toolchain
|
||||||
|
attributes:
|
||||||
|
label: Changes to Go ToolChain
|
||||||
|
description: "How many tools (such as vet, gopls, gofmt, goimports, etc.) would be affected? "
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: input
|
||||||
|
id: perf-costs
|
||||||
|
attributes:
|
||||||
|
label: Performance Costs
|
||||||
|
description: "What is the compile time cost? What is the run time cost? "
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
||||||
|
- type: textarea
|
||||||
|
id: prototype
|
||||||
|
attributes:
|
||||||
|
label: "Prototype"
|
||||||
|
description: "Can you describe a possible implementation?"
|
||||||
|
validations:
|
||||||
|
required: false
|
||||||
|
|
2
.github/ISSUE_TEMPLATE/12-telemetry.yml
vendored
2
.github/ISSUE_TEMPLATE/12-telemetry.yml
vendored
@ -1,6 +1,6 @@
|
|||||||
name: Go Telemetry Proposals
|
name: Go Telemetry Proposals
|
||||||
description: New telemetry counter or update on an existing one
|
description: New telemetry counter or update on an existing one
|
||||||
title: "x/telemetry/config: "
|
title: "x/telemetry/config: proposal title"
|
||||||
labels: ["Telemetry-Proposal"]
|
labels: ["Telemetry-Proposal"]
|
||||||
projects: ["golang/29"]
|
projects: ["golang/29"]
|
||||||
body:
|
body:
|
||||||
|
2
.github/ISSUE_TEMPLATE/config.yml
vendored
2
.github/ISSUE_TEMPLATE/config.yml
vendored
@ -1,4 +1,4 @@
|
|||||||
blank_issues_enabled: false
|
blank_issues_enabled: true
|
||||||
contact_links:
|
contact_links:
|
||||||
- name: Questions
|
- name: Questions
|
||||||
about: Please use one of the forums for questions or general discussions
|
about: Please use one of the forums for questions or general discussions
|
||||||
|
144
api/go1.22.txt
Normal file
144
api/go1.22.txt
Normal file
@ -0,0 +1,144 @@
|
|||||||
|
pkg archive/tar, method (*Writer) AddFS(fs.FS) error #58000
|
||||||
|
pkg archive/tar, type FileInfoNames interface { Gname, IsDir, ModTime, Mode, Name, Size, Sys, Uname } #50102
|
||||||
|
pkg archive/tar, type FileInfoNames interface, Gname(int) (string, error) #50102
|
||||||
|
pkg archive/tar, type FileInfoNames interface, IsDir() bool #50102
|
||||||
|
pkg archive/tar, type FileInfoNames interface, ModTime() time.Time #50102
|
||||||
|
pkg archive/tar, type FileInfoNames interface, Mode() fs.FileMode #50102
|
||||||
|
pkg archive/tar, type FileInfoNames interface, Name() string #50102
|
||||||
|
pkg archive/tar, type FileInfoNames interface, Size() int64 #50102
|
||||||
|
pkg archive/tar, type FileInfoNames interface, Sys() interface{} #50102
|
||||||
|
pkg archive/tar, type FileInfoNames interface, Uname(int) (string, error) #50102
|
||||||
|
pkg archive/zip, method (*Writer) AddFS(fs.FS) error #54898
|
||||||
|
pkg cmp, func Or[$0 comparable](...$0) $0 #60204
|
||||||
|
pkg crypto/x509, func OIDFromInts([]uint64) (OID, error) #60665
|
||||||
|
pkg crypto/x509, method (*CertPool) AddCertWithConstraint(*Certificate, func([]*Certificate) error) #57178
|
||||||
|
pkg crypto/x509, method (OID) Equal(OID) bool #60665
|
||||||
|
pkg crypto/x509, method (OID) EqualASN1OID(asn1.ObjectIdentifier) bool #60665
|
||||||
|
pkg crypto/x509, method (OID) String() string #60665
|
||||||
|
pkg crypto/x509, type Certificate struct, Policies []OID #60665
|
||||||
|
pkg crypto/x509, type OID struct #60665
|
||||||
|
pkg database/sql, method (*Null[$0]) Scan(interface{}) error #60370
|
||||||
|
pkg database/sql, method (Null[$0]) Value() (driver.Value, error) #60370
|
||||||
|
pkg database/sql, type Null[$0 interface{}] struct #60370
|
||||||
|
pkg database/sql, type Null[$0 interface{}] struct, V $0 #60370
|
||||||
|
pkg database/sql, type Null[$0 interface{}] struct, Valid bool #60370
|
||||||
|
pkg debug/elf, const R_LARCH_64_PCREL = 109 #63725
|
||||||
|
pkg debug/elf, const R_LARCH_64_PCREL R_LARCH #63725
|
||||||
|
pkg debug/elf, const R_LARCH_ADD6 = 105 #63725
|
||||||
|
pkg debug/elf, const R_LARCH_ADD6 R_LARCH #63725
|
||||||
|
pkg debug/elf, const R_LARCH_ADD_ULEB128 = 107 #63725
|
||||||
|
pkg debug/elf, const R_LARCH_ADD_ULEB128 R_LARCH #63725
|
||||||
|
pkg debug/elf, const R_LARCH_ALIGN = 102 #63725
|
||||||
|
pkg debug/elf, const R_LARCH_ALIGN R_LARCH #63725
|
||||||
|
pkg debug/elf, const R_LARCH_CFA = 104 #63725
|
||||||
|
pkg debug/elf, const R_LARCH_CFA R_LARCH #63725
|
||||||
|
pkg debug/elf, const R_LARCH_DELETE = 101 #63725
|
||||||
|
pkg debug/elf, const R_LARCH_DELETE R_LARCH #63725
|
||||||
|
pkg debug/elf, const R_LARCH_PCREL20_S2 = 103 #63725
|
||||||
|
pkg debug/elf, const R_LARCH_PCREL20_S2 R_LARCH #63725
|
||||||
|
pkg debug/elf, const R_LARCH_SUB6 = 106 #63725
|
||||||
|
pkg debug/elf, const R_LARCH_SUB6 R_LARCH #63725
|
||||||
|
pkg debug/elf, const R_LARCH_SUB_ULEB128 = 108 #63725
|
||||||
|
pkg debug/elf, const R_LARCH_SUB_ULEB128 R_LARCH #63725
|
||||||
|
pkg debug/elf, const R_MIPS_PC32 = 248 #61974
|
||||||
|
pkg debug/elf, const R_MIPS_PC32 R_MIPS #61974
|
||||||
|
pkg encoding/base32, method (*Encoding) AppendDecode([]uint8, []uint8) ([]uint8, error) #53693
|
||||||
|
pkg encoding/base32, method (*Encoding) AppendEncode([]uint8, []uint8) []uint8 #53693
|
||||||
|
pkg encoding/base64, method (*Encoding) AppendDecode([]uint8, []uint8) ([]uint8, error) #53693
|
||||||
|
pkg encoding/base64, method (*Encoding) AppendEncode([]uint8, []uint8) []uint8 #53693
|
||||||
|
pkg encoding/hex, func AppendDecode([]uint8, []uint8) ([]uint8, error) #53693
|
||||||
|
pkg encoding/hex, func AppendEncode([]uint8, []uint8) []uint8 #53693
|
||||||
|
pkg go/ast, func NewPackage //deprecated #52463
|
||||||
|
pkg go/ast, func Unparen(Expr) Expr #60061
|
||||||
|
pkg go/ast, type Importer //deprecated #52463
|
||||||
|
pkg go/ast, type Object //deprecated #52463
|
||||||
|
pkg go/ast, type Package //deprecated #52463
|
||||||
|
pkg go/ast, type Scope //deprecated #52463
|
||||||
|
pkg go/types, func NewAlias(*TypeName, Type) *Alias #63223
|
||||||
|
pkg go/types, func Unalias(Type) Type #63223
|
||||||
|
pkg go/types, method (*Alias) Obj() *TypeName #63223
|
||||||
|
pkg go/types, method (*Alias) String() string #63223
|
||||||
|
pkg go/types, method (*Alias) Underlying() Type #63223
|
||||||
|
pkg go/types, method (*Info) PkgNameOf(*ast.ImportSpec) *PkgName #62037
|
||||||
|
pkg go/types, method (Checker) PkgNameOf(*ast.ImportSpec) *PkgName #62037
|
||||||
|
pkg go/types, type Alias struct #63223
|
||||||
|
pkg go/types, type Info struct, FileVersions map[*ast.File]string #62605
|
||||||
|
pkg go/version, func Compare(string, string) int #62039
|
||||||
|
pkg go/version, func IsValid(string) bool #62039
|
||||||
|
pkg go/version, func Lang(string) string #62039
|
||||||
|
pkg html/template, const ErrJSTemplate //deprecated #61619
|
||||||
|
pkg io, method (*SectionReader) Outer() (ReaderAt, int64, int64) #61870
|
||||||
|
pkg log/slog, func SetLogLoggerLevel(Level) Level #62418
|
||||||
|
pkg math/big, method (*Rat) FloatPrec() (int, bool) #50489
|
||||||
|
pkg math/rand/v2, func ExpFloat64() float64 #61716
|
||||||
|
pkg math/rand/v2, func Float32() float32 #61716
|
||||||
|
pkg math/rand/v2, func Float64() float64 #61716
|
||||||
|
pkg math/rand/v2, func Int() int #61716
|
||||||
|
pkg math/rand/v2, func Int32() int32 #61716
|
||||||
|
pkg math/rand/v2, func Int32N(int32) int32 #61716
|
||||||
|
pkg math/rand/v2, func Int64() int64 #61716
|
||||||
|
pkg math/rand/v2, func Int64N(int64) int64 #61716
|
||||||
|
pkg math/rand/v2, func IntN(int) int #61716
|
||||||
|
pkg math/rand/v2, func N[$0 intType]($0) $0 #61716
|
||||||
|
pkg math/rand/v2, func New(Source) *Rand #61716
|
||||||
|
pkg math/rand/v2, func NewChaCha8([32]uint8) *ChaCha8 #61716
|
||||||
|
pkg math/rand/v2, func NewPCG(uint64, uint64) *PCG #61716
|
||||||
|
pkg math/rand/v2, func NewZipf(*Rand, float64, float64, uint64) *Zipf #61716
|
||||||
|
pkg math/rand/v2, func NormFloat64() float64 #61716
|
||||||
|
pkg math/rand/v2, func Perm(int) []int #61716
|
||||||
|
pkg math/rand/v2, func Shuffle(int, func(int, int)) #61716
|
||||||
|
pkg math/rand/v2, func Uint32() uint32 #61716
|
||||||
|
pkg math/rand/v2, func Uint32N(uint32) uint32 #61716
|
||||||
|
pkg math/rand/v2, func Uint64() uint64 #61716
|
||||||
|
pkg math/rand/v2, func Uint64N(uint64) uint64 #61716
|
||||||
|
pkg math/rand/v2, func UintN(uint) uint #61716
|
||||||
|
pkg math/rand/v2, method (*ChaCha8) MarshalBinary() ([]uint8, error) #61716
|
||||||
|
pkg math/rand/v2, method (*ChaCha8) Seed([32]uint8) #61716
|
||||||
|
pkg math/rand/v2, method (*ChaCha8) Uint64() uint64 #61716
|
||||||
|
pkg math/rand/v2, method (*ChaCha8) UnmarshalBinary([]uint8) error #61716
|
||||||
|
pkg math/rand/v2, method (*PCG) MarshalBinary() ([]uint8, error) #61716
|
||||||
|
pkg math/rand/v2, method (*PCG) Seed(uint64, uint64) #61716
|
||||||
|
pkg math/rand/v2, method (*PCG) Uint64() uint64 #61716
|
||||||
|
pkg math/rand/v2, method (*PCG) UnmarshalBinary([]uint8) error #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) ExpFloat64() float64 #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) Float32() float32 #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) Float64() float64 #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) Int() int #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) Int32() int32 #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) Int32N(int32) int32 #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) Int64() int64 #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) Int64N(int64) int64 #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) IntN(int) int #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) NormFloat64() float64 #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) Perm(int) []int #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) Shuffle(int, func(int, int)) #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) Uint32() uint32 #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) Uint32N(uint32) uint32 #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) Uint64() uint64 #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) Uint64N(uint64) uint64 #61716
|
||||||
|
pkg math/rand/v2, method (*Rand) UintN(uint) uint #61716
|
||||||
|
pkg math/rand/v2, method (*Zipf) Uint64() uint64 #61716
|
||||||
|
pkg math/rand/v2, type ChaCha8 struct #61716
|
||||||
|
pkg math/rand/v2, type PCG struct #61716
|
||||||
|
pkg math/rand/v2, type Rand struct #61716
|
||||||
|
pkg math/rand/v2, type Source interface { Uint64 } #61716
|
||||||
|
pkg math/rand/v2, type Source interface, Uint64() uint64 #61716
|
||||||
|
pkg math/rand/v2, type Zipf struct #61716
|
||||||
|
pkg net, method (*TCPConn) WriteTo(io.Writer) (int64, error) #58808
|
||||||
|
pkg net/http, func FileServerFS(fs.FS) Handler #51971
|
||||||
|
pkg net/http, func NewFileTransportFS(fs.FS) RoundTripper #51971
|
||||||
|
pkg net/http, func ServeFileFS(ResponseWriter, *Request, fs.FS, string) #51971
|
||||||
|
pkg net/http, method (*Request) PathValue(string) string #61410
|
||||||
|
pkg net/http, method (*Request) SetPathValue(string, string) #61410
|
||||||
|
pkg net/netip, method (AddrPort) Compare(AddrPort) int #61642
|
||||||
|
pkg os, method (*File) WriteTo(io.Writer) (int64, error) #58808
|
||||||
|
pkg reflect, func PtrTo //deprecated #59599
|
||||||
|
pkg reflect, func TypeFor[$0 interface{}]() Type #60088
|
||||||
|
pkg slices, func Concat[$0 interface{ ~[]$1 }, $1 interface{}](...$0) $0 #56353
|
||||||
|
pkg syscall (linux-386), type SysProcAttr struct, PidFD *int #51246
|
||||||
|
pkg syscall (linux-386-cgo), type SysProcAttr struct, PidFD *int #51246
|
||||||
|
pkg syscall (linux-amd64), type SysProcAttr struct, PidFD *int #51246
|
||||||
|
pkg syscall (linux-amd64-cgo), type SysProcAttr struct, PidFD *int #51246
|
||||||
|
pkg syscall (linux-arm), type SysProcAttr struct, PidFD *int #51246
|
||||||
|
pkg syscall (linux-arm-cgo), type SysProcAttr struct, PidFD *int #51246
|
||||||
|
pkg testing/slogtest, func Run(*testing.T, func(*testing.T) slog.Handler, func(*testing.T) map[string]interface{}) #61758
|
@ -1,9 +0,0 @@
|
|||||||
pkg archive/tar, type FileInfoNames interface { Gname, IsDir, ModTime, Mode, Name, Size, Sys, Uname } #50102
|
|
||||||
pkg archive/tar, type FileInfoNames interface, Gname(int) (string, error) #50102
|
|
||||||
pkg archive/tar, type FileInfoNames interface, IsDir() bool #50102
|
|
||||||
pkg archive/tar, type FileInfoNames interface, ModTime() time.Time #50102
|
|
||||||
pkg archive/tar, type FileInfoNames interface, Mode() fs.FileMode #50102
|
|
||||||
pkg archive/tar, type FileInfoNames interface, Name() string #50102
|
|
||||||
pkg archive/tar, type FileInfoNames interface, Size() int64 #50102
|
|
||||||
pkg archive/tar, type FileInfoNames interface, Sys() interface{} #50102
|
|
||||||
pkg archive/tar, type FileInfoNames interface, Uname(int) (string, error) #50102
|
|
@ -1,6 +0,0 @@
|
|||||||
pkg syscall (linux-386), type SysProcAttr struct, PidFD *int #51246
|
|
||||||
pkg syscall (linux-386-cgo), type SysProcAttr struct, PidFD *int #51246
|
|
||||||
pkg syscall (linux-amd64), type SysProcAttr struct, PidFD *int #51246
|
|
||||||
pkg syscall (linux-amd64-cgo), type SysProcAttr struct, PidFD *int #51246
|
|
||||||
pkg syscall (linux-arm), type SysProcAttr struct, PidFD *int #51246
|
|
||||||
pkg syscall (linux-arm-cgo), type SysProcAttr struct, PidFD *int #51246
|
|
@ -1,3 +0,0 @@
|
|||||||
pkg net/http, func ServeFileFS(ResponseWriter, *Request, fs.FS, string) #51971
|
|
||||||
pkg net/http, func FileServerFS(fs.FS) Handler #51971
|
|
||||||
pkg net/http, func NewFileTransportFS(fs.FS) RoundTripper #51971
|
|
@ -1,6 +0,0 @@
|
|||||||
pkg encoding/base32, method (*Encoding) AppendDecode([]uint8, []uint8) ([]uint8, error) #53693
|
|
||||||
pkg encoding/base32, method (*Encoding) AppendEncode([]uint8, []uint8) []uint8 #53693
|
|
||||||
pkg encoding/base64, method (*Encoding) AppendDecode([]uint8, []uint8) ([]uint8, error) #53693
|
|
||||||
pkg encoding/base64, method (*Encoding) AppendEncode([]uint8, []uint8) []uint8 #53693
|
|
||||||
pkg encoding/hex, func AppendDecode([]uint8, []uint8) ([]uint8, error) #53693
|
|
||||||
pkg encoding/hex, func AppendEncode([]uint8, []uint8) []uint8 #53693
|
|
@ -1 +0,0 @@
|
|||||||
pkg archive/zip, method (*Writer) AddFS(fs.FS) error #54898
|
|
@ -1 +0,0 @@
|
|||||||
pkg slices, func Concat[$0 interface{ ~[]$1 }, $1 interface{}](...$0) $0 #56353
|
|
@ -1 +0,0 @@
|
|||||||
pkg archive/tar, method (*Writer) AddFS(fs.FS) error #58000
|
|
@ -1 +0,0 @@
|
|||||||
pkg reflect, func PtrTo //deprecated #59599
|
|
@ -1 +0,0 @@
|
|||||||
pkg go/ast, func Unparen(Expr) Expr #60061
|
|
@ -1 +0,0 @@
|
|||||||
pkg reflect, func TypeFor[$0 interface{}]() Type #60088
|
|
@ -1 +0,0 @@
|
|||||||
pkg cmp, func Or[$0 comparable](...$0) $0 #60204
|
|
@ -1,5 +0,0 @@
|
|||||||
pkg database/sql, method (*Null[$0]) Scan(interface{}) error #60370
|
|
||||||
pkg database/sql, method (Null[$0]) Value() (driver.Value, error) #60370
|
|
||||||
pkg database/sql, type Null[$0 interface{}] struct #60370
|
|
||||||
pkg database/sql, type Null[$0 interface{}] struct, Valid bool #60370
|
|
||||||
pkg database/sql, type Null[$0 interface{}] struct, V $0 #60370
|
|
@ -1,2 +0,0 @@
|
|||||||
pkg net/http, method (*Request) PathValue(string) string #61410
|
|
||||||
pkg net/http, method (*Request) SetPathValue(string, string) #61410
|
|
@ -1,2 +0,0 @@
|
|||||||
pkg net/netip, method (AddrPort) Compare(AddrPort) int #61642
|
|
||||||
pkg net/netip, method (Prefix) Compare(Prefix) int #61642
|
|
@ -1 +0,0 @@
|
|||||||
pkg testing/slogtest, func Run(*testing.T, func(*testing.T) slog.Handler, func(*testing.T) map[string]interface{}) #61758
|
|
@ -1,2 +0,0 @@
|
|||||||
pkg debug/elf, const R_MIPS_PC32 = 248 #61974
|
|
||||||
pkg debug/elf, const R_MIPS_PC32 R_MIPS #61974
|
|
17
doc/asm.html
17
doc/asm.html
@ -464,6 +464,23 @@ Function is the outermost frame of the call stack. Traceback should stop at this
|
|||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
|
|
||||||
|
<h3 id="special-instructions">Special instructions</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The <code>PCALIGN</code> pseudo-instruction is used to indicate that the next instruction should be aligned
|
||||||
|
to a specified boundary by padding with no-op instructions.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
It is currently supported on arm64, amd64, ppc64, loong64 and riscv64.
|
||||||
|
|
||||||
|
For example, the start of the <code>MOVD</code> instruction below is aligned to 32 bytes:
|
||||||
|
<pre>
|
||||||
|
PCALIGN $32
|
||||||
|
MOVD $2, R0
|
||||||
|
</pre>
|
||||||
|
</p>
|
||||||
|
|
||||||
<h3 id="data-offsets">Interacting with Go types and constants</h3>
|
<h3 id="data-offsets">Interacting with Go types and constants</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -7,8 +7,11 @@
|
|||||||
<h2 id="Introduction">Introduction</h2>
|
<h2 id="Introduction">Introduction</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
This is a reference manual for the Go programming language. For
|
This is the reference manual for the Go programming language as it was for
|
||||||
more information and other documents, see <a href="/">golang.org</a>.
|
language version 1.17, in October 2021, before the introduction of generics.
|
||||||
|
It is provided for historical interest.
|
||||||
|
The current reference manual can be found <a href="/doc/go_spec.html">here</a>.
|
||||||
|
For more information and other documents, see <a href="/">go.dev</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
951
doc/go1.22.html
951
doc/go1.22.html
File diff suppressed because it is too large
Load Diff
317
doc/go_spec.html
317
doc/go_spec.html
@ -1,6 +1,6 @@
|
|||||||
<!--{
|
<!--{
|
||||||
"Title": "The Go Programming Language Specification",
|
"Title": "The Go Programming Language Specification",
|
||||||
"Subtitle": "Version of Sep 13, 2023",
|
"Subtitle": "Version of Dec 27, 2023",
|
||||||
"Path": "/ref/spec"
|
"Path": "/ref/spec"
|
||||||
}-->
|
}-->
|
||||||
|
|
||||||
@ -10,7 +10,7 @@
|
|||||||
This is the reference manual for the Go programming language.
|
This is the reference manual for the Go programming language.
|
||||||
The pre-Go1.18 version, without generics, can be found
|
The pre-Go1.18 version, without generics, can be found
|
||||||
<a href="/doc/go1.17_spec.html">here</a>.
|
<a href="/doc/go1.17_spec.html">here</a>.
|
||||||
For more information and other documents, see <a href="/">golang.org</a>.
|
For more information and other documents, see <a href="/">go.dev</a>.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -70,6 +70,14 @@ enumerations or code snippets that are not further specified. The character <cod
|
|||||||
language.
|
language.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
A link of the form [<a href="#Language_versions">Go 1.xx</a>] indicates that a described
|
||||||
|
language feature (or some aspect of it) was changed or added with language version 1.xx and
|
||||||
|
thus requires at minimum that language version to build.
|
||||||
|
For details, see the <a href="#Language_versions">linked section</a>
|
||||||
|
in the <a href="#Appendix">appendix</a>.
|
||||||
|
</p>
|
||||||
|
|
||||||
<h2 id="Source_code_representation">Source code representation</h2>
|
<h2 id="Source_code_representation">Source code representation</h2>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -263,7 +271,8 @@ continue for import return var
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
The following character sequences represent <a href="#Operators">operators</a>
|
The following character sequences represent <a href="#Operators">operators</a>
|
||||||
(including <a href="#Assignment_statements">assignment operators</a>) and punctuation:
|
(including <a href="#Assignment_statements">assignment operators</a>) and punctuation
|
||||||
|
[<a href="#Go_1.18">Go 1.18</a>]:
|
||||||
</p>
|
</p>
|
||||||
<pre class="grammar">
|
<pre class="grammar">
|
||||||
+ & += &= && == != ( )
|
+ & += &= && == != ( )
|
||||||
@ -281,7 +290,8 @@ An integer literal is a sequence of digits representing an
|
|||||||
<a href="#Constants">integer constant</a>.
|
<a href="#Constants">integer constant</a>.
|
||||||
An optional prefix sets a non-decimal base: <code>0b</code> or <code>0B</code>
|
An optional prefix sets a non-decimal base: <code>0b</code> or <code>0B</code>
|
||||||
for binary, <code>0</code>, <code>0o</code>, or <code>0O</code> for octal,
|
for binary, <code>0</code>, <code>0o</code>, or <code>0O</code> for octal,
|
||||||
and <code>0x</code> or <code>0X</code> for hexadecimal.
|
and <code>0x</code> or <code>0X</code> for hexadecimal
|
||||||
|
[<a href="#Go_1.13">Go 1.13</a>].
|
||||||
A single <code>0</code> is considered a decimal zero.
|
A single <code>0</code> is considered a decimal zero.
|
||||||
In hexadecimal literals, letters <code>a</code> through <code>f</code>
|
In hexadecimal literals, letters <code>a</code> through <code>f</code>
|
||||||
and <code>A</code> through <code>F</code> represent values 10 through 15.
|
and <code>A</code> through <code>F</code> represent values 10 through 15.
|
||||||
@ -347,7 +357,8 @@ prefix, an integer part (hexadecimal digits), a radix point, a fractional part (
|
|||||||
and an exponent part (<code>p</code> or <code>P</code> followed by an optional sign and decimal digits).
|
and an exponent part (<code>p</code> or <code>P</code> followed by an optional sign and decimal digits).
|
||||||
One of the integer part or the fractional part may be elided; the radix point may be elided as well,
|
One of the integer part or the fractional part may be elided; the radix point may be elided as well,
|
||||||
but the exponent part is required. (This syntax matches the one given in IEEE 754-2008 §5.12.3.)
|
but the exponent part is required. (This syntax matches the one given in IEEE 754-2008 §5.12.3.)
|
||||||
An exponent value exp scales the mantissa (integer and fractional part) by 2<sup>exp</sup>.
|
An exponent value exp scales the mantissa (integer and fractional part) by 2<sup>exp</sup>
|
||||||
|
[<a href="#Go_1.13">Go 1.13</a>].
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -411,7 +422,8 @@ It consists of an <a href="#Integer_literals">integer</a> or
|
|||||||
<a href="#Floating-point_literals">floating-point</a> literal
|
<a href="#Floating-point_literals">floating-point</a> literal
|
||||||
followed by the lowercase letter <code>i</code>.
|
followed by the lowercase letter <code>i</code>.
|
||||||
The value of an imaginary literal is the value of the respective
|
The value of an imaginary literal is the value of the respective
|
||||||
integer or floating-point literal multiplied by the imaginary unit <i>i</i>.
|
integer or floating-point literal multiplied by the imaginary unit <i>i</i>
|
||||||
|
[<a href="#Go_1.13">Go 1.13</a>]
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre class="ebnf">
|
<pre class="ebnf">
|
||||||
@ -1340,6 +1352,7 @@ interface{}
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
For convenience, the predeclared type <code>any</code> is an alias for the empty interface.
|
For convenience, the predeclared type <code>any</code> is an alias for the empty interface.
|
||||||
|
[<a href="#Go_1.18">Go 1.18</a>]
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -1375,13 +1388,15 @@ as the <code>File</code> interface.
|
|||||||
In a slightly more general form
|
In a slightly more general form
|
||||||
an interface <code>T</code> may use a (possibly qualified) interface type
|
an interface <code>T</code> may use a (possibly qualified) interface type
|
||||||
name <code>E</code> as an interface element. This is called
|
name <code>E</code> as an interface element. This is called
|
||||||
<i>embedding</i> interface <code>E</code> in <code>T</code>.
|
<i>embedding</i> interface <code>E</code> in <code>T</code>
|
||||||
|
[<a href="#Go_1.14">Go 1.14</a>].
|
||||||
The type set of <code>T</code> is the <i>intersection</i> of the type sets
|
The type set of <code>T</code> is the <i>intersection</i> of the type sets
|
||||||
defined by <code>T</code>'s explicitly declared methods and the type sets
|
defined by <code>T</code>'s explicitly declared methods and the type sets
|
||||||
of <code>T</code>’s embedded interfaces.
|
of <code>T</code>’s embedded interfaces.
|
||||||
In other words, the type set of <code>T</code> is the set of all types that implement all the
|
In other words, the type set of <code>T</code> is the set of all types that implement all the
|
||||||
explicitly declared methods of <code>T</code> and also all the methods of
|
explicitly declared methods of <code>T</code> and also all the methods of
|
||||||
<code>E</code>.
|
<code>E</code>
|
||||||
|
[<a href="#Go_1.18">Go 1.18</a>].
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
@ -1420,7 +1435,8 @@ type ReadCloser interface {
|
|||||||
<p>
|
<p>
|
||||||
In their most general form, an interface element may also be an arbitrary type term
|
In their most general form, an interface element may also be an arbitrary type term
|
||||||
<code>T</code>, or a term of the form <code>~T</code> specifying the underlying type <code>T</code>,
|
<code>T</code>, or a term of the form <code>~T</code> specifying the underlying type <code>T</code>,
|
||||||
or a union of terms <code>t<sub>1</sub>|t<sub>2</sub>|…|t<sub>n</sub></code>.
|
or a union of terms <code>t<sub>1</sub>|t<sub>2</sub>|…|t<sub>n</sub></code>
|
||||||
|
[<a href="#Go_1.18">Go 1.18</a>].
|
||||||
Together with method specifications, these elements enable the precise
|
Together with method specifications, these elements enable the precise
|
||||||
definition of an interface's type set as follows:
|
definition of an interface's type set as follows:
|
||||||
</p>
|
</p>
|
||||||
@ -2303,7 +2319,9 @@ as an <a href="#Operands">operand</a>, and in <a href="#Assignment_statements">a
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
The following identifiers are implicitly declared in the
|
The following identifiers are implicitly declared in the
|
||||||
<a href="#Blocks">universe block</a>:
|
<a href="#Blocks">universe block</a>
|
||||||
|
[<a href="#Go_1.18">Go 1.18</a>]
|
||||||
|
[<a href="#Go_1.21">Go 1.21</a>]:
|
||||||
</p>
|
</p>
|
||||||
<pre class="grammar">
|
<pre class="grammar">
|
||||||
Types:
|
Types:
|
||||||
@ -2487,7 +2505,8 @@ TypeSpec = AliasDecl | TypeDef .
|
|||||||
<h4 id="Alias_declarations">Alias declarations</h4>
|
<h4 id="Alias_declarations">Alias declarations</h4>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
An alias declaration binds an identifier to the given type.
|
An alias declaration binds an identifier to the given type
|
||||||
|
[<a href="#Go_1.9">Go 1.9</a>].
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre class="ebnf">
|
<pre class="ebnf">
|
||||||
@ -2636,7 +2655,8 @@ func (l *List[T]) Len() int { … }
|
|||||||
A type parameter list declares the <i>type parameters</i> of a generic function or type declaration.
|
A type parameter list declares the <i>type parameters</i> of a generic function or type declaration.
|
||||||
The type parameter list looks like an ordinary <a href="#Function_types">function parameter list</a>
|
The type parameter list looks like an ordinary <a href="#Function_types">function parameter list</a>
|
||||||
except that the type parameter names must all be present and the list is enclosed
|
except that the type parameter names must all be present and the list is enclosed
|
||||||
in square brackets rather than parentheses.
|
in square brackets rather than parentheses
|
||||||
|
[<a href="#Go_1.18">Go 1.18</a>].
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre class="ebnf">
|
<pre class="ebnf">
|
||||||
@ -2719,7 +2739,8 @@ type T6[P int] struct{ f *T6[P] } // ok: reference to T6 is not in type para
|
|||||||
<p>
|
<p>
|
||||||
A <i>type constraint</i> is an <a href="#Interface_types">interface</a> that defines the
|
A <i>type constraint</i> is an <a href="#Interface_types">interface</a> that defines the
|
||||||
set of permissible type arguments for the respective type parameter and controls the
|
set of permissible type arguments for the respective type parameter and controls the
|
||||||
operations supported by values of that type parameter.
|
operations supported by values of that type parameter
|
||||||
|
[<a href="#Go_1.18">Go 1.18</a>].
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre class="ebnf">
|
<pre class="ebnf">
|
||||||
@ -2749,7 +2770,8 @@ other interfaces based on their type sets. But this should get us going for now.
|
|||||||
The <a href="#Predeclared_identifiers">predeclared</a>
|
The <a href="#Predeclared_identifiers">predeclared</a>
|
||||||
<a href="#Interface_types">interface type</a> <code>comparable</code>
|
<a href="#Interface_types">interface type</a> <code>comparable</code>
|
||||||
denotes the set of all non-interface types that are
|
denotes the set of all non-interface types that are
|
||||||
<a href="#Comparison_operators">strictly comparable</a>.
|
<a href="#Comparison_operators">strictly comparable</a>
|
||||||
|
[<a href="#Go_1.18">Go 1.18</a>].
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -2782,7 +2804,8 @@ if <code>T</code> is an element of the type set defined by <code>C</code>; i.e.,
|
|||||||
if <code>T</code> <a href="#Implementing_an_interface">implements</a> <code>C</code>.
|
if <code>T</code> <a href="#Implementing_an_interface">implements</a> <code>C</code>.
|
||||||
As an exception, a <a href="#Comparison_operators">strictly comparable</a>
|
As an exception, a <a href="#Comparison_operators">strictly comparable</a>
|
||||||
type constraint may also be satisfied by a <a href="#Comparison_operators">comparable</a>
|
type constraint may also be satisfied by a <a href="#Comparison_operators">comparable</a>
|
||||||
(not necessarily strictly comparable) type argument.
|
(not necessarily strictly comparable) type argument
|
||||||
|
[<a href="#Go_1.20">Go 1.20</a>].
|
||||||
More precisely:
|
More precisely:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -4306,7 +4329,7 @@ with the same underlying array.
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
A generic function or type is <i>instantiated</i> by substituting <i>type arguments</i>
|
A generic function or type is <i>instantiated</i> by substituting <i>type arguments</i>
|
||||||
for the type parameters.
|
for the type parameters [<a href="#Go_1.18">Go 1.18</a>].
|
||||||
Instantiation proceeds in two steps:
|
Instantiation proceeds in two steps:
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -4759,6 +4782,7 @@ to the type of the other operand.
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
The right operand in a shift expression must have <a href="#Numeric_types">integer type</a>
|
The right operand in a shift expression must have <a href="#Numeric_types">integer type</a>
|
||||||
|
[<a href="#Go_1.13">Go 1.13</a>]
|
||||||
or be an untyped constant <a href="#Representability">representable</a> by a
|
or be an untyped constant <a href="#Representability">representable</a> by a
|
||||||
value of type <code>uint</code>.
|
value of type <code>uint</code>.
|
||||||
If the left operand of a non-constant shift expression is an untyped constant,
|
If the left operand of a non-constant shift expression is an untyped constant,
|
||||||
@ -4826,12 +4850,13 @@ For instance, <code>x / y * z</code> is the same as <code>(x / y) * z</code>.
|
|||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre>
|
<pre>
|
||||||
+x
|
+x // x
|
||||||
23 + 3*x[i]
|
42 + a - b // (42 + a) - b
|
||||||
x <= f()
|
23 + 3*x[i] // 23 + (3 * x[i])
|
||||||
^a >> b
|
x <= f() // x <= f()
|
||||||
f() || g()
|
^a >> b // (^a) >> b
|
||||||
x == y+1 && <-chanInt > 0
|
f() || g() // f() || g()
|
||||||
|
x == y+1 && <-chanInt > 0 // (x == (y+1)) && ((<-chanInt) > 0)
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
@ -5425,7 +5450,8 @@ in any of these cases:
|
|||||||
<code>x</code> is a string and <code>T</code> is a slice of bytes or runes.
|
<code>x</code> is a string and <code>T</code> is a slice of bytes or runes.
|
||||||
</li>
|
</li>
|
||||||
<li>
|
<li>
|
||||||
<code>x</code> is a slice, <code>T</code> is an array or a pointer to an array,
|
<code>x</code> is a slice, <code>T</code> is an array [<a href="#Go_1.20">Go 1.20</a>]
|
||||||
|
or a pointer to an array [<a href="#Go_1.17">Go 1.17</a>],
|
||||||
and the slice and array types have <a href="#Type_identity">identical</a> element types.
|
and the slice and array types have <a href="#Type_identity">identical</a> element types.
|
||||||
</li>
|
</li>
|
||||||
</ul>
|
</ul>
|
||||||
@ -6515,7 +6541,6 @@ additionally it may specify an <i>init</i>
|
|||||||
and a <i>post</i> statement, such as an assignment,
|
and a <i>post</i> statement, such as an assignment,
|
||||||
an increment or decrement statement. The init statement may be a
|
an increment or decrement statement. The init statement may be a
|
||||||
<a href="#Short_variable_declarations">short variable declaration</a>, but the post statement must not.
|
<a href="#Short_variable_declarations">short variable declaration</a>, but the post statement must not.
|
||||||
Variables declared by the init statement are re-used in each iteration.
|
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre class="ebnf">
|
<pre class="ebnf">
|
||||||
@ -6547,12 +6572,55 @@ for cond { S() } is the same as for ; cond ; { S() }
|
|||||||
for { S() } is the same as for true { S() }
|
for { S() } is the same as for true { S() }
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Each iteration has its own separate declared variable (or variables)
|
||||||
|
[<a href="#Go_1.22">Go 1.22</a>].
|
||||||
|
The variable used by the first iteration is declared by the init statement.
|
||||||
|
The variable used by each subsequent iteration is declared implicitly before
|
||||||
|
executing the post statement and initialized to the value of the previous
|
||||||
|
iteration's variable at that moment.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
var prints []func()
|
||||||
|
for i := 0; i < 5; i++ {
|
||||||
|
prints = append(prints, func() { println(i) })
|
||||||
|
i++
|
||||||
|
}
|
||||||
|
for _, p := range prints {
|
||||||
|
p()
|
||||||
|
}
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
prints
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
1
|
||||||
|
3
|
||||||
|
5
|
||||||
|
</pre>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
Prior to [<a href="#Go_1.22">Go 1.22</a>], iterations share one set of variables
|
||||||
|
instead of having their own separate variables.
|
||||||
|
In that case, the example above prints
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<pre>
|
||||||
|
6
|
||||||
|
6
|
||||||
|
6
|
||||||
|
</pre>
|
||||||
|
|
||||||
<h4 id="For_range">For statements with <code>range</code> clause</h4>
|
<h4 id="For_range">For statements with <code>range</code> clause</h4>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
A "for" statement with a "range" clause
|
A "for" statement with a "range" clause
|
||||||
iterates through all entries of an array, slice, string or map,
|
iterates through all entries of an array, slice, string or map, values received on
|
||||||
or values received on a channel. For each entry it assigns <i>iteration values</i>
|
a channel, or integer values from zero to an upper limit [<a href="#Go_1.22">Go 1.22</a>].
|
||||||
|
For each entry it assigns <i>iteration values</i>
|
||||||
to corresponding <i>iteration variables</i> if present and then executes the block.
|
to corresponding <i>iteration variables</i> if present and then executes the block.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -6563,12 +6631,12 @@ RangeClause = [ ExpressionList "=" | IdentifierList ":=" ] "range" Expression .
|
|||||||
<p>
|
<p>
|
||||||
The expression on the right in the "range" clause is called the <i>range expression</i>,
|
The expression on the right in the "range" clause is called the <i>range expression</i>,
|
||||||
its <a href="#Core_types">core type</a> must be
|
its <a href="#Core_types">core type</a> must be
|
||||||
an array, pointer to an array, slice, string, map, or channel permitting
|
an array, pointer to an array, slice, string, map, channel permitting
|
||||||
<a href="#Receive_operator">receive operations</a>.
|
<a href="#Receive_operator">receive operations</a>, or an integer.
|
||||||
As with an assignment, if present the operands on the left must be
|
As with an assignment, if present the operands on the left must be
|
||||||
<a href="#Address_operators">addressable</a> or map index expressions; they
|
<a href="#Address_operators">addressable</a> or map index expressions; they
|
||||||
denote the iteration variables. If the range expression is a channel, at most
|
denote the iteration variables. If the range expression is a channel or integer,
|
||||||
one iteration variable is permitted, otherwise there may be up to two.
|
at most one iteration variable is permitted, otherwise there may be up to two.
|
||||||
If the last iteration variable is the <a href="#Blank_identifier">blank identifier</a>,
|
If the last iteration variable is the <a href="#Blank_identifier">blank identifier</a>,
|
||||||
the range clause is equivalent to the same clause without that identifier.
|
the range clause is equivalent to the same clause without that identifier.
|
||||||
</p>
|
</p>
|
||||||
@ -6593,6 +6661,7 @@ array or slice a [n]E, *[n]E, or []E index i int a[i] E
|
|||||||
string s string type index i int see below rune
|
string s string type index i int see below rune
|
||||||
map m map[K]V key k K m[k] V
|
map m map[K]V key k K m[k] V
|
||||||
channel c chan E, <-chan E element e E
|
channel c chan E, <-chan E element e E
|
||||||
|
integer n integer type I value i I
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
<ol>
|
<ol>
|
||||||
@ -6631,6 +6700,12 @@ For channels, the iteration values produced are the successive values sent on
|
|||||||
the channel until the channel is <a href="#Close">closed</a>. If the channel
|
the channel until the channel is <a href="#Close">closed</a>. If the channel
|
||||||
is <code>nil</code>, the range expression blocks forever.
|
is <code>nil</code>, the range expression blocks forever.
|
||||||
</li>
|
</li>
|
||||||
|
|
||||||
|
<li>
|
||||||
|
For an integer value <code>n</code>, the iteration values 0 through <code>n-1</code>
|
||||||
|
are produced in increasing order, with the same type as <code>n</code>.
|
||||||
|
If <code>n</code> <= 0, the loop does not run any iterations.
|
||||||
|
</li>
|
||||||
</ol>
|
</ol>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -6643,9 +6718,10 @@ The iteration variables may be declared by the "range" clause using a form of
|
|||||||
<a href="#Short_variable_declarations">short variable declaration</a>
|
<a href="#Short_variable_declarations">short variable declaration</a>
|
||||||
(<code>:=</code>).
|
(<code>:=</code>).
|
||||||
In this case their types are set to the types of the respective iteration values
|
In this case their types are set to the types of the respective iteration values
|
||||||
and their <a href="#Declarations_and_scope">scope</a> is the block of the "for"
|
and their <a href="#Declarations_and_scope">scope</a> is the block of the "for" statement;
|
||||||
statement; they are re-used in each iteration.
|
each iteration has its own separate variables [<a href="#Go_1.22">Go 1.22</a>]
|
||||||
If the iteration variables are declared outside the "for" statement,
|
(see also <a href="#For_clause">"for" statements with a ForClause</a>).
|
||||||
|
If the iteration variables are declared outside the “for” statement,
|
||||||
after execution their values will be those of the last iteration.
|
after execution their values will be those of the last iteration.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -6683,6 +6759,12 @@ for w := range ch {
|
|||||||
|
|
||||||
// empty a channel
|
// empty a channel
|
||||||
for range ch {}
|
for range ch {}
|
||||||
|
|
||||||
|
// call f(0), f(1), ... f(9)
|
||||||
|
for i := range 10 {
|
||||||
|
// type of i is int (default type for untyped constant 10)
|
||||||
|
f(i)
|
||||||
|
}
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
|
|
||||||
@ -7234,7 +7316,8 @@ n3 := copy(b, "Hello, World!") // n3 == 5, b is []byte("Hello")
|
|||||||
<p>
|
<p>
|
||||||
The built-in function <code>clear</code> takes an argument of <a href="#Map_types">map</a>,
|
The built-in function <code>clear</code> takes an argument of <a href="#Map_types">map</a>,
|
||||||
<a href="#Slice_types">slice</a>, or <a href="#Type_parameter_declarations">type parameter</a> type,
|
<a href="#Slice_types">slice</a>, or <a href="#Type_parameter_declarations">type parameter</a> type,
|
||||||
and deletes or zeroes out all elements.
|
and deletes or zeroes out all elements
|
||||||
|
[<a href="#Go_1.21">Go 1.21</a>].
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<pre class="grammar">
|
<pre class="grammar">
|
||||||
@ -7501,7 +7584,8 @@ The precise behavior is implementation-dependent.
|
|||||||
The built-in functions <code>min</code> and <code>max</code> compute the
|
The built-in functions <code>min</code> and <code>max</code> compute the
|
||||||
smallest—or largest, respectively—value of a fixed number of
|
smallest—or largest, respectively—value of a fixed number of
|
||||||
arguments of <a href="#Comparison_operators">ordered types</a>.
|
arguments of <a href="#Comparison_operators">ordered types</a>.
|
||||||
There must be at least one argument.
|
There must be at least one argument
|
||||||
|
[<a href="#Go_1.21">Go 1.21</a>].
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -8217,8 +8301,8 @@ of if the general conversion rules take care of this.
|
|||||||
<p>
|
<p>
|
||||||
A <code>Pointer</code> is a <a href="#Pointer_types">pointer type</a> but a <code>Pointer</code>
|
A <code>Pointer</code> is a <a href="#Pointer_types">pointer type</a> but a <code>Pointer</code>
|
||||||
value may not be <a href="#Address_operators">dereferenced</a>.
|
value may not be <a href="#Address_operators">dereferenced</a>.
|
||||||
Any pointer or value of <a href="#Underlying_types">underlying type</a> <code>uintptr</code> can be
|
Any pointer or value of <a href="#Core_types">core type</a> <code>uintptr</code> can be
|
||||||
<a href="#Conversions">converted</a> to a type of underlying type <code>Pointer</code> and vice versa.
|
<a href="#Conversions">converted</a> to a type of core type <code>Pointer</code> and vice versa.
|
||||||
The effect of converting between <code>Pointer</code> and <code>uintptr</code> is implementation-defined.
|
The effect of converting between <code>Pointer</code> and <code>uintptr</code> is implementation-defined.
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
@ -8229,6 +8313,10 @@ bits = *(*uint64)(unsafe.Pointer(&f))
|
|||||||
type ptr unsafe.Pointer
|
type ptr unsafe.Pointer
|
||||||
bits = *(*uint64)(ptr(&f))
|
bits = *(*uint64)(ptr(&f))
|
||||||
|
|
||||||
|
func f[P ~*B, B any](p P) uintptr {
|
||||||
|
return uintptr(unsafe.Pointer(p))
|
||||||
|
}
|
||||||
|
|
||||||
var p ptr = nil
|
var p ptr = nil
|
||||||
</pre>
|
</pre>
|
||||||
|
|
||||||
@ -8277,7 +8365,8 @@ of constant size.
|
|||||||
|
|
||||||
<p>
|
<p>
|
||||||
The function <code>Add</code> adds <code>len</code> to <code>ptr</code>
|
The function <code>Add</code> adds <code>len</code> to <code>ptr</code>
|
||||||
and returns the updated pointer <code>unsafe.Pointer(uintptr(ptr) + uintptr(len))</code>.
|
and returns the updated pointer <code>unsafe.Pointer(uintptr(ptr) + uintptr(len))</code>
|
||||||
|
[<a href="#Go_1.17">Go 1.17</a>].
|
||||||
The <code>len</code> argument must be of <a href="#Numeric_types">integer type</a> or an untyped <a href="#Constants">constant</a>.
|
The <code>len</code> argument must be of <a href="#Numeric_types">integer type</a> or an untyped <a href="#Constants">constant</a>.
|
||||||
A constant <code>len</code> argument must be <a href="#Representability">representable</a> by a value of type <code>int</code>;
|
A constant <code>len</code> argument must be <a href="#Representability">representable</a> by a value of type <code>int</code>;
|
||||||
if it is an untyped constant it is given type <code>int</code>.
|
if it is an untyped constant it is given type <code>int</code>.
|
||||||
@ -8297,7 +8386,8 @@ and whose length and capacity are <code>len</code>.
|
|||||||
<p>
|
<p>
|
||||||
except that, as a special case, if <code>ptr</code>
|
except that, as a special case, if <code>ptr</code>
|
||||||
is <code>nil</code> and <code>len</code> is zero,
|
is <code>nil</code> and <code>len</code> is zero,
|
||||||
<code>Slice</code> returns <code>nil</code>.
|
<code>Slice</code> returns <code>nil</code>
|
||||||
|
[<a href="#Go_1.17">Go 1.17</a>].
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -8306,14 +8396,16 @@ A constant <code>len</code> argument must be non-negative and <a href="#Represen
|
|||||||
if it is an untyped constant it is given type <code>int</code>.
|
if it is an untyped constant it is given type <code>int</code>.
|
||||||
At run time, if <code>len</code> is negative,
|
At run time, if <code>len</code> is negative,
|
||||||
or if <code>ptr</code> is <code>nil</code> and <code>len</code> is not zero,
|
or if <code>ptr</code> is <code>nil</code> and <code>len</code> is not zero,
|
||||||
a <a href="#Run_time_panics">run-time panic</a> occurs.
|
a <a href="#Run_time_panics">run-time panic</a> occurs
|
||||||
|
[<a href="#Go_1.17">Go 1.17</a>].
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The function <code>SliceData</code> returns a pointer to the underlying array of the <code>slice</code> argument.
|
The function <code>SliceData</code> returns a pointer to the underlying array of the <code>slice</code> argument.
|
||||||
If the slice's capacity <code>cap(slice)</code> is not zero, that pointer is <code>&slice[:1][0]</code>.
|
If the slice's capacity <code>cap(slice)</code> is not zero, that pointer is <code>&slice[:1][0]</code>.
|
||||||
If <code>slice</code> is <code>nil</code>, the result is <code>nil</code>.
|
If <code>slice</code> is <code>nil</code>, the result is <code>nil</code>.
|
||||||
Otherwise it is a non-<code>nil</code> pointer to an unspecified memory address.
|
Otherwise it is a non-<code>nil</code> pointer to an unspecified memory address
|
||||||
|
[<a href="#Go_1.20">Go 1.20</a>].
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
@ -8322,12 +8414,14 @@ The function <code>String</code> returns a <code>string</code> value whose under
|
|||||||
The same requirements apply to the <code>ptr</code> and <code>len</code> argument as in the function
|
The same requirements apply to the <code>ptr</code> and <code>len</code> argument as in the function
|
||||||
<code>Slice</code>. If <code>len</code> is zero, the result is the empty string <code>""</code>.
|
<code>Slice</code>. If <code>len</code> is zero, the result is the empty string <code>""</code>.
|
||||||
Since Go strings are immutable, the bytes passed to <code>String</code> must not be modified afterwards.
|
Since Go strings are immutable, the bytes passed to <code>String</code> must not be modified afterwards.
|
||||||
|
[<a href="#Go_1.20">Go 1.20</a>]
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
The function <code>StringData</code> returns a pointer to the underlying bytes of the <code>str</code> argument.
|
The function <code>StringData</code> returns a pointer to the underlying bytes of the <code>str</code> argument.
|
||||||
For an empty string the return value is unspecified, and may be <code>nil</code>.
|
For an empty string the return value is unspecified, and may be <code>nil</code>.
|
||||||
Since Go strings are immutable, the bytes returned by <code>StringData</code> must not be modified.
|
Since Go strings are immutable, the bytes returned by <code>StringData</code> must not be modified
|
||||||
|
[<a href="#Go_1.20">Go 1.20</a>].
|
||||||
</p>
|
</p>
|
||||||
|
|
||||||
<h3 id="Size_and_alignment_guarantees">Size and alignment guarantees</h3>
|
<h3 id="Size_and_alignment_guarantees">Size and alignment guarantees</h3>
|
||||||
@ -8368,6 +8462,145 @@ A struct or array type has size zero if it contains no fields (or elements, resp
|
|||||||
|
|
||||||
<h2 id="Appendix">Appendix</h2>
|
<h2 id="Appendix">Appendix</h2>
|
||||||
|
|
||||||
|
<h3 id="Language_versions">Language versions</h3>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The <a href="/doc/go1compat">Go 1 compatibility guarantee</a> ensures that
|
||||||
|
programs written to the Go 1 specification will continue to compile and run
|
||||||
|
correctly, unchanged, over the lifetime of that specification.
|
||||||
|
More generally, as adjustments are made and features added to the language,
|
||||||
|
the compatibility guarantee ensures that a Go program that works with a
|
||||||
|
specific Go language version will continue to work with any subsequent version.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
For instance, the ability to use the prefix <code>0b</code> for binary
|
||||||
|
integer literals was introduced with Go 1.13, indicated
|
||||||
|
by [<a href="#Go_1.13">Go 1.13</a>] in the section on
|
||||||
|
<a href="#Integer_literals">integer literals</a>.
|
||||||
|
Source code containing an integer literal such as <code>0b1011</code>
|
||||||
|
will be rejected if the implied or required language version used by
|
||||||
|
the compiler is older than Go 1.13.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<p>
|
||||||
|
The following table describes the minimum language version required for
|
||||||
|
features introduced after Go 1.
|
||||||
|
</p>
|
||||||
|
|
||||||
|
<h4 id="Go_1.9">Go 1.9</h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
An <a href="#Alias_declarations">alias declaration</a> may be used to declare an alias name for a type.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4 id="Go_1.13">Go 1.13</h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
<a href="#Integer_literals">Integer literals</a> may use the prefixes <code>0b</code>, <code>0B</code>, <code>0o</code>,
|
||||||
|
and <code>0O</code> for binary, and octal literals, respectively.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Hexadecimal <a href="#Floating-point_literals">floating-point literals</a> may be written using the prefixes
|
||||||
|
<code>0x</code> and <code>0X</code>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
The <a href="#Imaginary_literals">imaginary suffix</a> <code>i</code> may be used with any (binary, decimal, hexadecimal)
|
||||||
|
integer or floating-point literal, not just decimal literals.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
The digits of any number literal may be <a href="#Integer_literals">separated</a> (grouped)
|
||||||
|
using underscores <code>_</code>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
The shift count in a <a href="#Operators">shift operation</a> may be a signed integer type.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4 id="Go_1.14">Go 1.14</h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
Emdedding a method more than once through different <a href="#Embedded_interfaces">embedded interfaces</a>
|
||||||
|
is not an error.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4 id="Go_1.17">Go 1.17</h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
A slice may be <a href="#Conversions">converted</a> to an array pointer if the slice and array element
|
||||||
|
types match, and the array is not longer than the slice.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
The built-in <a href="#Package_unsafe">package <code>unsafe</code></a> includes the new functions
|
||||||
|
<code>Add</code> and <code>Slice</code>.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4 id="Go_1.18">Go 1.18</h4>
|
||||||
|
<p>
|
||||||
|
The 1.18 release adds polymorphic functions and types ("generics") to the language.
|
||||||
|
Specifically:
|
||||||
|
</p>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
The set of <a href="#Operators_and_punctuation">operators and punctuation</a> includes the new token <code>~</code>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Function and type declarations may declare <a href="#Type_parameter_declarations">type parameters</a>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
Interface types may <a href="#General_interfaces">embed arbitrary types</a> (not just type names of interfaces)
|
||||||
|
as well as union and <code>~T</code> type elements.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
The set of <a href="#Predeclared_identifiers">predeclared</a> types includes the new types
|
||||||
|
<code>any</code> and <code>comparable</code>.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4 id="Go_1.20">Go 1.20</h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
A slice may be <a href="#Conversions">converted</a> to an array if the slice and array element
|
||||||
|
types match and the array is not longer than the slice.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
The built-in <a href="#Package_unsafe">package <code>unsafe</code></a> includes the new functions
|
||||||
|
<code>SliceData</code>, <code>String</code>, and <code>StringData</code>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#Comparison_operators">Comparable types</a> (such as ordinary interfaces) may satisfy
|
||||||
|
<code>comparable</code> constraints, even if the type arguments are not strictly comparable.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4 id="Go_1.21">Go 1.21</h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
The set of <a href="#Predeclared_identifiers">predeclared</a> functions includes the new functions
|
||||||
|
<code>min</code>, <code>max</code>, and <code>clear</code>.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
<a href="#Type_inference">Type inference</a> uses the types of interface methods for inference.
|
||||||
|
It also infers type arguments for generic functions assigned to variables or
|
||||||
|
passed as arguments to other (possibly generic) functions.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
|
<h4 id="Go_1.22">Go 1.22</h4>
|
||||||
|
<ul>
|
||||||
|
<li>
|
||||||
|
In a <a href="#For_statements">"for" statement</a>, each iteration has its own set of iteration
|
||||||
|
variables rather than sharing the same variables in each iteration.
|
||||||
|
</li>
|
||||||
|
<li>
|
||||||
|
A "for" statement with <a href="#For_range">"range" clause</a> may iterate over
|
||||||
|
integer values from zero to an upper limit.
|
||||||
|
</li>
|
||||||
|
</ul>
|
||||||
|
|
||||||
<h3 id="Type_unification_rules">Type unification rules</h3>
|
<h3 id="Type_unification_rules">Type unification rules</h3>
|
||||||
|
|
||||||
<p>
|
<p>
|
||||||
|
@ -138,6 +138,62 @@ Go 1.22 made it an error for a request or response read by a net/http
|
|||||||
client or server to have an empty Content-Length header.
|
client or server to have an empty Content-Length header.
|
||||||
This behavior is controlled by the `httplaxcontentlength` setting.
|
This behavior is controlled by the `httplaxcontentlength` setting.
|
||||||
|
|
||||||
|
Go 1.22 changed the behavior of ServeMux to accept extended
|
||||||
|
patterns and unescape both patterns and request paths by segment.
|
||||||
|
This behavior can be controlled by the
|
||||||
|
[`httpmuxgo121` setting](/pkg/net/http/#ServeMux).
|
||||||
|
|
||||||
|
Go 1.22 added the [Alias type](/pkg/go/types#Alias) to [go/types](/pkg/go/types)
|
||||||
|
for the explicit representation of [type aliases](/ref/spec#Type_declarations).
|
||||||
|
Whether the type checker produces `Alias` types or not is controlled by the
|
||||||
|
[`gotypesalias` setting](/pkg/go/types#Alias).
|
||||||
|
For Go 1.22 it defaults to `gotypesalias=0`.
|
||||||
|
For Go 1.23, `gotypealias=1` will become the default.
|
||||||
|
This setting will be removed in a future release, Go 1.24 at the earliest.
|
||||||
|
|
||||||
|
Go 1.22 changed the default minimum TLS version supported by both servers
|
||||||
|
and clients to TLS 1.2. The default can be reverted to TLS 1.0 using the
|
||||||
|
[`tls10server` setting](/pkg/crypto/tls/#Config).
|
||||||
|
|
||||||
|
Go 1.22 changed the default TLS cipher suites used by clients and servers when
|
||||||
|
not explicitly configured, removing the cipher suites which used RSA based key
|
||||||
|
exchange. The default can be revert using the [`tlsrsakex` setting](/pkg/crypto/tls/#Config).
|
||||||
|
|
||||||
|
Go 1.22 disabled
|
||||||
|
[`ConnectionState.ExportKeyingMaterial`](/pkg/crypto/tls/#ConnectionState.ExportKeyingMaterial)
|
||||||
|
when the connection supports neither TLS 1.3 nor Extended Master Secret
|
||||||
|
(implemented in Go 1.21). It can be reenabled with the [`tlsunsafeekm`
|
||||||
|
setting](/pkg/crypto/tls/#ConnectionState.ExportKeyingMaterial).
|
||||||
|
|
||||||
|
Go 1.22 changed how the runtime interacts with transparent huge pages on Linux.
|
||||||
|
In particular, a common default Linux kernel configuration can result in
|
||||||
|
significant memory overheads, and Go 1.22 no longer works around this default.
|
||||||
|
To work around this issue without adjusting kernel settings, transparent huge
|
||||||
|
pages can be disabled for Go memory with the
|
||||||
|
[`disablethp` setting](/pkg/runtime#hdr-Environment_Variable).
|
||||||
|
This behavior was backported to Go 1.21.1, but the setting is only available
|
||||||
|
starting with Go 1.21.6.
|
||||||
|
This setting may be removed in a future release, and users impacted by this issue
|
||||||
|
should adjust their Linux configuration according to the recommendations in the
|
||||||
|
[GC guide](/doc/gc-guide#Linux_transparent_huge_pages), or switch to a Linux
|
||||||
|
distribution that disables transparent huge pages altogether.
|
||||||
|
|
||||||
|
Go 1.22 added contention on runtime-internal locks to the [`mutex`
|
||||||
|
profile](/pkg/runtime/pprof#Profile). Contention on these locks is always
|
||||||
|
reported at `runtime._LostContendedRuntimeLock`. Complete stack traces of
|
||||||
|
runtime locks can be enabled with the [`runtimecontentionstacks`
|
||||||
|
setting](/pkg/runtime#hdr-Environment_Variable). These stack traces have
|
||||||
|
non-standard semantics, see setting documentation for details.
|
||||||
|
|
||||||
|
Go 1.22 added a new [`crypto/x509.Certificate`](/pkg/crypto/x509/#Certificate)
|
||||||
|
field, [`Policies`](/pkg/crypto/x509/#Certificate.Policies), which supports
|
||||||
|
certificate policy OIDs with components larger than 31 bits. By default this
|
||||||
|
field is only used during parsing, when it is populated with policy OIDs, but
|
||||||
|
not used during marshaling. It can be used to marshal these larger OIDs, instead
|
||||||
|
of the existing PolicyIdentifiers field, by using the
|
||||||
|
[`x509usepolicies` setting.](/pkg/crypto/x509/#CreateCertificate).
|
||||||
|
|
||||||
|
|
||||||
### Go 1.21
|
### Go 1.21
|
||||||
|
|
||||||
Go 1.21 made it a run-time error to call `panic` with a nil interface value,
|
Go 1.21 made it a run-time error to call `panic` with a nil interface value,
|
||||||
|
@ -24,8 +24,8 @@
|
|||||||
# in the CL match the update.bash in the CL.
|
# in the CL match the update.bash in the CL.
|
||||||
|
|
||||||
# Versions to use.
|
# Versions to use.
|
||||||
CODE=2023c
|
CODE=2023d
|
||||||
DATA=2023c
|
DATA=2023d
|
||||||
|
|
||||||
set -e
|
set -e
|
||||||
|
|
||||||
|
Binary file not shown.
@ -3,7 +3,6 @@
|
|||||||
// license that can be found in the LICENSE file.
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
//go:build ignore
|
//go:build ignore
|
||||||
// +build ignore
|
|
||||||
|
|
||||||
// detect attempts to autodetect the correct
|
// detect attempts to autodetect the correct
|
||||||
// values of the environment variables
|
// values of the environment variables
|
||||||
|
@ -14,7 +14,15 @@ case "$GOWASIRUNTIME" in
|
|||||||
exec wazero run -mount /:/ -env-inherit -cachedir "${TMPDIR:-/tmp}"/wazero ${GOWASIRUNTIMEARGS:-} "$1" "${@:2}"
|
exec wazero run -mount /:/ -env-inherit -cachedir "${TMPDIR:-/tmp}"/wazero ${GOWASIRUNTIMEARGS:-} "$1" "${@:2}"
|
||||||
;;
|
;;
|
||||||
"wasmtime" | "")
|
"wasmtime" | "")
|
||||||
|
# Match the major version in "wasmtime-cli 14.0.0". For versions before 14
|
||||||
|
# we need to use the old CLI. This requires Bash v3.0 and above.
|
||||||
|
# TODO(johanbrandhorst): Remove this condition once 1.22 is released.
|
||||||
|
# From 1.23 onwards we'll only support the new wasmtime CLI.
|
||||||
|
if [[ "$(wasmtime --version)" =~ wasmtime-cli[[:space:]]([0-9]+)\.[0-9]+\.[0-9]+ && "${BASH_REMATCH[1]}" -lt 14 ]]; then
|
||||||
exec wasmtime run --dir=/ --env PWD="$PWD" --env PATH="$PATH" --max-wasm-stack 1048576 ${GOWASIRUNTIMEARGS:-} "$1" -- "${@:2}"
|
exec wasmtime run --dir=/ --env PWD="$PWD" --env PATH="$PATH" --max-wasm-stack 1048576 ${GOWASIRUNTIMEARGS:-} "$1" -- "${@:2}"
|
||||||
|
else
|
||||||
|
exec wasmtime run --dir=/ --env PWD="$PWD" --env PATH="$PATH" -W max-wasm-stack=1048576 ${GOWASIRUNTIMEARGS:-} "$1" "${@:2}"
|
||||||
|
fi
|
||||||
;;
|
;;
|
||||||
*)
|
*)
|
||||||
echo "Unknown Go WASI runtime specified: $GOWASIRUNTIME"
|
echo "Unknown Go WASI runtime specified: $GOWASIRUNTIME"
|
||||||
|
@ -634,7 +634,7 @@ const (
|
|||||||
c_ISSOCK = 0140000 // Socket
|
c_ISSOCK = 0140000 // Socket
|
||||||
)
|
)
|
||||||
|
|
||||||
// FileInfoHeader creates a partially-populated Header from fi.
|
// FileInfoHeader creates a partially-populated [Header] from fi.
|
||||||
// If fi describes a symlink, FileInfoHeader records link as the link target.
|
// If fi describes a symlink, FileInfoHeader records link as the link target.
|
||||||
// If fi describes a directory, a slash is appended to the name.
|
// If fi describes a directory, a slash is appended to the name.
|
||||||
//
|
//
|
||||||
|
@ -33,7 +33,7 @@ import "strings"
|
|||||||
// sub-second times | no | yes | no
|
// sub-second times | no | yes | no
|
||||||
// sparse files | no | yes | yes
|
// sparse files | no | yes | yes
|
||||||
//
|
//
|
||||||
// The table's upper portion shows the Header fields, where each format reports
|
// The table's upper portion shows the [Header] fields, where each format reports
|
||||||
// the maximum number of bytes allowed for each string field and
|
// the maximum number of bytes allowed for each string field and
|
||||||
// the integer type used to store each numeric field
|
// the integer type used to store each numeric field
|
||||||
// (where timestamps are stored as the number of seconds since the Unix epoch).
|
// (where timestamps are stored as the number of seconds since the Unix epoch).
|
||||||
|
@ -35,7 +35,7 @@ type fileReader interface {
|
|||||||
WriteTo(io.Writer) (int64, error)
|
WriteTo(io.Writer) (int64, error)
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewReader creates a new Reader reading from r.
|
// NewReader creates a new [Reader] reading from r.
|
||||||
func NewReader(r io.Reader) *Reader {
|
func NewReader(r io.Reader) *Reader {
|
||||||
return &Reader{r: r, curr: ®FileReader{r, 0}}
|
return &Reader{r: r, curr: ®FileReader{r, 0}}
|
||||||
}
|
}
|
||||||
@ -47,10 +47,10 @@ func NewReader(r io.Reader) *Reader {
|
|||||||
//
|
//
|
||||||
// If Next encounters a non-local name (as defined by [filepath.IsLocal])
|
// If Next encounters a non-local name (as defined by [filepath.IsLocal])
|
||||||
// and the GODEBUG environment variable contains `tarinsecurepath=0`,
|
// and the GODEBUG environment variable contains `tarinsecurepath=0`,
|
||||||
// Next returns the header with an ErrInsecurePath error.
|
// Next returns the header with an [ErrInsecurePath] error.
|
||||||
// A future version of Go may introduce this behavior by default.
|
// A future version of Go may introduce this behavior by default.
|
||||||
// Programs that want to accept non-local names can ignore
|
// Programs that want to accept non-local names can ignore
|
||||||
// the ErrInsecurePath error and use the returned header.
|
// the [ErrInsecurePath] error and use the returned header.
|
||||||
func (tr *Reader) Next() (*Header, error) {
|
func (tr *Reader) Next() (*Header, error) {
|
||||||
if tr.err != nil {
|
if tr.err != nil {
|
||||||
return nil, tr.err
|
return nil, tr.err
|
||||||
@ -623,14 +623,14 @@ func readGNUSparseMap0x1(paxHdrs map[string]string) (sparseDatas, error) {
|
|||||||
|
|
||||||
// Read reads from the current file in the tar archive.
|
// Read reads from the current file in the tar archive.
|
||||||
// It returns (0, io.EOF) when it reaches the end of that file,
|
// It returns (0, io.EOF) when it reaches the end of that file,
|
||||||
// until Next is called to advance to the next file.
|
// until [Next] is called to advance to the next file.
|
||||||
//
|
//
|
||||||
// If the current file is sparse, then the regions marked as a hole
|
// If the current file is sparse, then the regions marked as a hole
|
||||||
// are read back as NUL-bytes.
|
// are read back as NUL-bytes.
|
||||||
//
|
//
|
||||||
// Calling Read on special types like TypeLink, TypeSymlink, TypeChar,
|
// Calling Read on special types like [TypeLink], [TypeSymlink], [TypeChar],
|
||||||
// TypeBlock, TypeDir, and TypeFifo returns (0, io.EOF) regardless of what
|
// [TypeBlock], [TypeDir], and [TypeFifo] returns (0, [io.EOF]) regardless of what
|
||||||
// the Header.Size claims.
|
// the [Header.Size] claims.
|
||||||
func (tr *Reader) Read(b []byte) (int, error) {
|
func (tr *Reader) Read(b []byte) (int, error) {
|
||||||
if tr.err != nil {
|
if tr.err != nil {
|
||||||
return 0, tr.err
|
return 0, tr.err
|
||||||
|
@ -16,7 +16,7 @@ import (
|
|||||||
)
|
)
|
||||||
|
|
||||||
// Writer provides sequential writing of a tar archive.
|
// Writer provides sequential writing of a tar archive.
|
||||||
// Write.WriteHeader begins a new file with the provided Header,
|
// [Writer.WriteHeader] begins a new file with the provided [Header],
|
||||||
// and then Writer can be treated as an io.Writer to supply that file's data.
|
// and then Writer can be treated as an io.Writer to supply that file's data.
|
||||||
type Writer struct {
|
type Writer struct {
|
||||||
w io.Writer
|
w io.Writer
|
||||||
@ -46,7 +46,7 @@ type fileWriter interface {
|
|||||||
// Flush finishes writing the current file's block padding.
|
// Flush finishes writing the current file's block padding.
|
||||||
// The current file must be fully written before Flush can be called.
|
// The current file must be fully written before Flush can be called.
|
||||||
//
|
//
|
||||||
// This is unnecessary as the next call to WriteHeader or Close
|
// This is unnecessary as the next call to [Writer.WriteHeader] or [Writer.Close]
|
||||||
// will implicitly flush out the file's padding.
|
// will implicitly flush out the file's padding.
|
||||||
func (tw *Writer) Flush() error {
|
func (tw *Writer) Flush() error {
|
||||||
if tw.err != nil {
|
if tw.err != nil {
|
||||||
@ -464,12 +464,12 @@ func splitUSTARPath(name string) (prefix, suffix string, ok bool) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Write writes to the current file in the tar archive.
|
// Write writes to the current file in the tar archive.
|
||||||
// Write returns the error ErrWriteTooLong if more than
|
// Write returns the error [ErrWriteTooLong] if more than
|
||||||
// Header.Size bytes are written after WriteHeader.
|
// Header.Size bytes are written after [Writer.WriteHeader].
|
||||||
//
|
//
|
||||||
// Calling Write on special types like TypeLink, TypeSymlink, TypeChar,
|
// Calling Write on special types like [TypeLink], [TypeSymlink], [TypeChar],
|
||||||
// TypeBlock, TypeDir, and TypeFifo returns (0, ErrWriteTooLong) regardless
|
// [TypeBlock], [TypeDir], and [TypeFifo] returns (0, [ErrWriteTooLong]) regardless
|
||||||
// of what the Header.Size claims.
|
// of what the [Header.Size] claims.
|
||||||
func (tw *Writer) Write(b []byte) (int, error) {
|
func (tw *Writer) Write(b []byte) (int, error) {
|
||||||
if tw.err != nil {
|
if tw.err != nil {
|
||||||
return 0, tw.err
|
return 0, tw.err
|
||||||
@ -503,7 +503,7 @@ func (tw *Writer) readFrom(r io.Reader) (int64, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Close closes the tar archive by flushing the padding, and writing the footer.
|
// Close closes the tar archive by flushing the padding, and writing the footer.
|
||||||
// If the current file (from a prior call to WriteHeader) is not fully written,
|
// If the current file (from a prior call to [Writer.WriteHeader]) is not fully written,
|
||||||
// then this returns an error.
|
// then this returns an error.
|
||||||
func (tw *Writer) Close() error {
|
func (tw *Writer) Close() error {
|
||||||
if tw.err == ErrWriteAfterClose {
|
if tw.err == ErrWriteAfterClose {
|
||||||
|
@ -48,15 +48,15 @@ type Reader struct {
|
|||||||
fileList []fileListEntry
|
fileList []fileListEntry
|
||||||
}
|
}
|
||||||
|
|
||||||
// A ReadCloser is a Reader that must be closed when no longer needed.
|
// A ReadCloser is a [Reader] that must be closed when no longer needed.
|
||||||
type ReadCloser struct {
|
type ReadCloser struct {
|
||||||
f *os.File
|
f *os.File
|
||||||
Reader
|
Reader
|
||||||
}
|
}
|
||||||
|
|
||||||
// A File is a single file in a ZIP archive.
|
// A File is a single file in a ZIP archive.
|
||||||
// The file information is in the embedded FileHeader.
|
// The file information is in the embedded [FileHeader].
|
||||||
// The file content can be accessed by calling Open.
|
// The file content can be accessed by calling [File.Open].
|
||||||
type File struct {
|
type File struct {
|
||||||
FileHeader
|
FileHeader
|
||||||
zip *Reader
|
zip *Reader
|
||||||
@ -93,16 +93,16 @@ func OpenReader(name string) (*ReadCloser, error) {
|
|||||||
return r, err
|
return r, err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewReader returns a new Reader reading from r, which is assumed to
|
// NewReader returns a new [Reader] reading from r, which is assumed to
|
||||||
// have the given size in bytes.
|
// have the given size in bytes.
|
||||||
//
|
//
|
||||||
// If any file inside the archive uses a non-local name
|
// If any file inside the archive uses a non-local name
|
||||||
// (as defined by [filepath.IsLocal]) or a name containing backslashes
|
// (as defined by [filepath.IsLocal]) or a name containing backslashes
|
||||||
// and the GODEBUG environment variable contains `zipinsecurepath=0`,
|
// and the GODEBUG environment variable contains `zipinsecurepath=0`,
|
||||||
// NewReader returns the reader with an ErrInsecurePath error.
|
// NewReader returns the reader with an [ErrInsecurePath] error.
|
||||||
// A future version of Go may introduce this behavior by default.
|
// A future version of Go may introduce this behavior by default.
|
||||||
// Programs that want to accept non-local names can ignore
|
// Programs that want to accept non-local names can ignore
|
||||||
// the ErrInsecurePath error and use the returned reader.
|
// the [ErrInsecurePath] error and use the returned reader.
|
||||||
func NewReader(r io.ReaderAt, size int64) (*Reader, error) {
|
func NewReader(r io.ReaderAt, size int64) (*Reader, error) {
|
||||||
if size < 0 {
|
if size < 0 {
|
||||||
return nil, errors.New("zip: size cannot be negative")
|
return nil, errors.New("zip: size cannot be negative")
|
||||||
@ -178,7 +178,7 @@ func (r *Reader) init(rdr io.ReaderAt, size int64) error {
|
|||||||
|
|
||||||
// RegisterDecompressor registers or overrides a custom decompressor for a
|
// RegisterDecompressor registers or overrides a custom decompressor for a
|
||||||
// specific method ID. If a decompressor for a given method is not found,
|
// specific method ID. If a decompressor for a given method is not found,
|
||||||
// Reader will default to looking up the decompressor at the package level.
|
// [Reader] will default to looking up the decompressor at the package level.
|
||||||
func (r *Reader) RegisterDecompressor(method uint16, dcomp Decompressor) {
|
func (r *Reader) RegisterDecompressor(method uint16, dcomp Decompressor) {
|
||||||
if r.decompressors == nil {
|
if r.decompressors == nil {
|
||||||
r.decompressors = make(map[uint16]Decompressor)
|
r.decompressors = make(map[uint16]Decompressor)
|
||||||
@ -202,7 +202,7 @@ func (rc *ReadCloser) Close() error {
|
|||||||
// DataOffset returns the offset of the file's possibly-compressed
|
// DataOffset returns the offset of the file's possibly-compressed
|
||||||
// data, relative to the beginning of the zip file.
|
// data, relative to the beginning of the zip file.
|
||||||
//
|
//
|
||||||
// Most callers should instead use Open, which transparently
|
// Most callers should instead use [File.Open], which transparently
|
||||||
// decompresses data and verifies checksums.
|
// decompresses data and verifies checksums.
|
||||||
func (f *File) DataOffset() (offset int64, err error) {
|
func (f *File) DataOffset() (offset int64, err error) {
|
||||||
bodyOffset, err := f.findBodyOffset()
|
bodyOffset, err := f.findBodyOffset()
|
||||||
@ -212,7 +212,7 @@ func (f *File) DataOffset() (offset int64, err error) {
|
|||||||
return f.headerOffset + bodyOffset, nil
|
return f.headerOffset + bodyOffset, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Open returns a ReadCloser that provides access to the File's contents.
|
// Open returns a [ReadCloser] that provides access to the [File]'s contents.
|
||||||
// Multiple files may be read concurrently.
|
// Multiple files may be read concurrently.
|
||||||
func (f *File) Open() (io.ReadCloser, error) {
|
func (f *File) Open() (io.ReadCloser, error) {
|
||||||
bodyOffset, err := f.findBodyOffset()
|
bodyOffset, err := f.findBodyOffset()
|
||||||
@ -255,7 +255,7 @@ func (f *File) Open() (io.ReadCloser, error) {
|
|||||||
return rc, nil
|
return rc, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// OpenRaw returns a Reader that provides access to the File's contents without
|
// OpenRaw returns a [Reader] that provides access to the [File]'s contents without
|
||||||
// decompression.
|
// decompression.
|
||||||
func (f *File) OpenRaw() (io.Reader, error) {
|
func (f *File) OpenRaw() (io.Reader, error) {
|
||||||
bodyOffset, err := f.findBodyOffset()
|
bodyOffset, err := f.findBodyOffset()
|
||||||
|
@ -19,7 +19,7 @@ import (
|
|||||||
type Compressor func(w io.Writer) (io.WriteCloser, error)
|
type Compressor func(w io.Writer) (io.WriteCloser, error)
|
||||||
|
|
||||||
// A Decompressor returns a new decompressing reader, reading from r.
|
// A Decompressor returns a new decompressing reader, reading from r.
|
||||||
// The ReadCloser's Close method must be used to release associated resources.
|
// The [io.ReadCloser]'s Close method must be used to release associated resources.
|
||||||
// The Decompressor itself must be safe to invoke from multiple goroutines
|
// The Decompressor itself must be safe to invoke from multiple goroutines
|
||||||
// simultaneously, but each returned reader will be used only by
|
// simultaneously, but each returned reader will be used only by
|
||||||
// one goroutine at a time.
|
// one goroutine at a time.
|
||||||
@ -115,7 +115,7 @@ func init() {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RegisterDecompressor allows custom decompressors for a specified method ID.
|
// RegisterDecompressor allows custom decompressors for a specified method ID.
|
||||||
// The common methods Store and Deflate are built in.
|
// The common methods [Store] and [Deflate] are built in.
|
||||||
func RegisterDecompressor(method uint16, dcomp Decompressor) {
|
func RegisterDecompressor(method uint16, dcomp Decompressor) {
|
||||||
if _, dup := decompressors.LoadOrStore(method, dcomp); dup {
|
if _, dup := decompressors.LoadOrStore(method, dcomp); dup {
|
||||||
panic("decompressor already registered")
|
panic("decompressor already registered")
|
||||||
@ -123,7 +123,7 @@ func RegisterDecompressor(method uint16, dcomp Decompressor) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RegisterCompressor registers custom compressors for a specified method ID.
|
// RegisterCompressor registers custom compressors for a specified method ID.
|
||||||
// The common methods Store and Deflate are built in.
|
// The common methods [Store] and [Deflate] are built in.
|
||||||
func RegisterCompressor(method uint16, comp Compressor) {
|
func RegisterCompressor(method uint16, comp Compressor) {
|
||||||
if _, dup := compressors.LoadOrStore(method, comp); dup {
|
if _, dup := compressors.LoadOrStore(method, comp); dup {
|
||||||
panic("compressor already registered")
|
panic("compressor already registered")
|
||||||
|
@ -160,12 +160,12 @@ type FileHeader struct {
|
|||||||
ExternalAttrs uint32 // Meaning depends on CreatorVersion
|
ExternalAttrs uint32 // Meaning depends on CreatorVersion
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileInfo returns an fs.FileInfo for the FileHeader.
|
// FileInfo returns an fs.FileInfo for the [FileHeader].
|
||||||
func (h *FileHeader) FileInfo() fs.FileInfo {
|
func (h *FileHeader) FileInfo() fs.FileInfo {
|
||||||
return headerFileInfo{h}
|
return headerFileInfo{h}
|
||||||
}
|
}
|
||||||
|
|
||||||
// headerFileInfo implements fs.FileInfo.
|
// headerFileInfo implements [fs.FileInfo].
|
||||||
type headerFileInfo struct {
|
type headerFileInfo struct {
|
||||||
fh *FileHeader
|
fh *FileHeader
|
||||||
}
|
}
|
||||||
@ -194,7 +194,7 @@ func (fi headerFileInfo) String() string {
|
|||||||
return fs.FormatFileInfo(fi)
|
return fs.FormatFileInfo(fi)
|
||||||
}
|
}
|
||||||
|
|
||||||
// FileInfoHeader creates a partially-populated FileHeader from an
|
// FileInfoHeader creates a partially-populated [FileHeader] from an
|
||||||
// fs.FileInfo.
|
// fs.FileInfo.
|
||||||
// Because fs.FileInfo's Name method returns only the base name of
|
// Because fs.FileInfo's Name method returns only the base name of
|
||||||
// the file it describes, it may be necessary to modify the Name field
|
// the file it describes, it may be necessary to modify the Name field
|
||||||
@ -273,17 +273,17 @@ func timeToMsDosTime(t time.Time) (fDate uint16, fTime uint16) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ModTime returns the modification time in UTC using the legacy
|
// ModTime returns the modification time in UTC using the legacy
|
||||||
// ModifiedDate and ModifiedTime fields.
|
// [ModifiedDate] and [ModifiedTime] fields.
|
||||||
//
|
//
|
||||||
// Deprecated: Use Modified instead.
|
// Deprecated: Use [Modified] instead.
|
||||||
func (h *FileHeader) ModTime() time.Time {
|
func (h *FileHeader) ModTime() time.Time {
|
||||||
return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
|
return msDosTimeToTime(h.ModifiedDate, h.ModifiedTime)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetModTime sets the Modified, ModifiedTime, and ModifiedDate fields
|
// SetModTime sets the [Modified], [ModifiedTime], and [ModifiedDate] fields
|
||||||
// to the given time in UTC.
|
// to the given time in UTC.
|
||||||
//
|
//
|
||||||
// Deprecated: Use Modified instead.
|
// Deprecated: Use [Modified] instead.
|
||||||
func (h *FileHeader) SetModTime(t time.Time) {
|
func (h *FileHeader) SetModTime(t time.Time) {
|
||||||
t = t.UTC() // Convert to UTC for compatibility
|
t = t.UTC() // Convert to UTC for compatibility
|
||||||
h.Modified = t
|
h.Modified = t
|
||||||
@ -309,7 +309,7 @@ const (
|
|||||||
msdosReadOnly = 0x01
|
msdosReadOnly = 0x01
|
||||||
)
|
)
|
||||||
|
|
||||||
// Mode returns the permission and mode bits for the FileHeader.
|
// Mode returns the permission and mode bits for the [FileHeader].
|
||||||
func (h *FileHeader) Mode() (mode fs.FileMode) {
|
func (h *FileHeader) Mode() (mode fs.FileMode) {
|
||||||
switch h.CreatorVersion >> 8 {
|
switch h.CreatorVersion >> 8 {
|
||||||
case creatorUnix, creatorMacOSX:
|
case creatorUnix, creatorMacOSX:
|
||||||
@ -323,7 +323,7 @@ func (h *FileHeader) Mode() (mode fs.FileMode) {
|
|||||||
return mode
|
return mode
|
||||||
}
|
}
|
||||||
|
|
||||||
// SetMode changes the permission and mode bits for the FileHeader.
|
// SetMode changes the permission and mode bits for the [FileHeader].
|
||||||
func (h *FileHeader) SetMode(mode fs.FileMode) {
|
func (h *FileHeader) SetMode(mode fs.FileMode) {
|
||||||
h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
|
h.CreatorVersion = h.CreatorVersion&0xff | creatorUnix<<8
|
||||||
h.ExternalAttrs = fileModeToUnixMode(mode) << 16
|
h.ExternalAttrs = fileModeToUnixMode(mode) << 16
|
||||||
|
@ -41,7 +41,7 @@ type header struct {
|
|||||||
raw bool
|
raw bool
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWriter returns a new Writer writing a zip file to w.
|
// NewWriter returns a new [Writer] writing a zip file to w.
|
||||||
func NewWriter(w io.Writer) *Writer {
|
func NewWriter(w io.Writer) *Writer {
|
||||||
return &Writer{cw: &countWriter{w: bufio.NewWriter(w)}}
|
return &Writer{cw: &countWriter{w: bufio.NewWriter(w)}}
|
||||||
}
|
}
|
||||||
@ -64,7 +64,7 @@ func (w *Writer) Flush() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// SetComment sets the end-of-central-directory comment field.
|
// SetComment sets the end-of-central-directory comment field.
|
||||||
// It can only be called before Close.
|
// It can only be called before [Writer.Close].
|
||||||
func (w *Writer) SetComment(comment string) error {
|
func (w *Writer) SetComment(comment string) error {
|
||||||
if len(comment) > uint16max {
|
if len(comment) > uint16max {
|
||||||
return errors.New("zip: Writer.Comment too long")
|
return errors.New("zip: Writer.Comment too long")
|
||||||
@ -208,14 +208,14 @@ func (w *Writer) Close() error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Create adds a file to the zip file using the provided name.
|
// Create adds a file to the zip file using the provided name.
|
||||||
// It returns a Writer to which the file contents should be written.
|
// It returns a [Writer] to which the file contents should be written.
|
||||||
// The file contents will be compressed using the Deflate method.
|
// The file contents will be compressed using the [Deflate] method.
|
||||||
// The name must be a relative path: it must not start with a drive
|
// The name must be a relative path: it must not start with a drive
|
||||||
// letter (e.g. C:) or leading slash, and only forward slashes are
|
// letter (e.g. C:) or leading slash, and only forward slashes are
|
||||||
// allowed. To create a directory instead of a file, add a trailing
|
// allowed. To create a directory instead of a file, add a trailing
|
||||||
// slash to the name.
|
// slash to the name.
|
||||||
// The file's contents must be written to the io.Writer before the next
|
// The file's contents must be written to the [io.Writer] before the next
|
||||||
// call to Create, CreateHeader, or Close.
|
// call to [Writer.Create], [Writer.CreateHeader], or [Writer.Close].
|
||||||
func (w *Writer) Create(name string) (io.Writer, error) {
|
func (w *Writer) Create(name string) (io.Writer, error) {
|
||||||
header := &FileHeader{
|
header := &FileHeader{
|
||||||
Name: name,
|
Name: name,
|
||||||
@ -262,13 +262,13 @@ func (w *Writer) prepare(fh *FileHeader) error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateHeader adds a file to the zip archive using the provided FileHeader
|
// CreateHeader adds a file to the zip archive using the provided [FileHeader]
|
||||||
// for the file metadata. Writer takes ownership of fh and may mutate
|
// for the file metadata. [Writer] takes ownership of fh and may mutate
|
||||||
// its fields. The caller must not modify fh after calling CreateHeader.
|
// its fields. The caller must not modify fh after calling [Writer.CreateHeader].
|
||||||
//
|
//
|
||||||
// This returns a Writer to which the file contents should be written.
|
// This returns a [Writer] to which the file contents should be written.
|
||||||
// The file's contents must be written to the io.Writer before the next
|
// The file's contents must be written to the io.Writer before the next
|
||||||
// call to Create, CreateHeader, CreateRaw, or Close.
|
// call to [Writer.Create], [Writer.CreateHeader], [Writer.CreateRaw], or [Writer.Close].
|
||||||
func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
|
func (w *Writer) CreateHeader(fh *FileHeader) (io.Writer, error) {
|
||||||
if err := w.prepare(fh); err != nil {
|
if err := w.prepare(fh); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -427,12 +427,12 @@ func writeHeader(w io.Writer, h *header) error {
|
|||||||
return err
|
return err
|
||||||
}
|
}
|
||||||
|
|
||||||
// CreateRaw adds a file to the zip archive using the provided FileHeader and
|
// CreateRaw adds a file to the zip archive using the provided [FileHeader] and
|
||||||
// returns a Writer to which the file contents should be written. The file's
|
// returns a [Writer] to which the file contents should be written. The file's
|
||||||
// contents must be written to the io.Writer before the next call to Create,
|
// contents must be written to the io.Writer before the next call to [Writer.Create],
|
||||||
// CreateHeader, CreateRaw, or Close.
|
// [Writer.CreateHeader], [Writer.CreateRaw], or [Writer.Close].
|
||||||
//
|
//
|
||||||
// In contrast to CreateHeader, the bytes passed to Writer are not compressed.
|
// In contrast to [Writer.CreateHeader], the bytes passed to Writer are not compressed.
|
||||||
func (w *Writer) CreateRaw(fh *FileHeader) (io.Writer, error) {
|
func (w *Writer) CreateRaw(fh *FileHeader) (io.Writer, error) {
|
||||||
if err := w.prepare(fh); err != nil {
|
if err := w.prepare(fh); err != nil {
|
||||||
return nil, err
|
return nil, err
|
||||||
@ -464,7 +464,7 @@ func (w *Writer) CreateRaw(fh *FileHeader) (io.Writer, error) {
|
|||||||
return fw, nil
|
return fw, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy copies the file f (obtained from a Reader) into w. It copies the raw
|
// Copy copies the file f (obtained from a [Reader]) into w. It copies the raw
|
||||||
// form directly bypassing decompression, compression, and validation.
|
// form directly bypassing decompression, compression, and validation.
|
||||||
func (w *Writer) Copy(f *File) error {
|
func (w *Writer) Copy(f *File) error {
|
||||||
r, err := f.OpenRaw()
|
r, err := f.OpenRaw()
|
||||||
@ -480,7 +480,7 @@ func (w *Writer) Copy(f *File) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// RegisterCompressor registers or overrides a custom compressor for a specific
|
// RegisterCompressor registers or overrides a custom compressor for a specific
|
||||||
// method ID. If a compressor for a given method is not found, Writer will
|
// method ID. If a compressor for a given method is not found, [Writer] will
|
||||||
// default to looking up the compressor at the package level.
|
// default to looking up the compressor at the package level.
|
||||||
func (w *Writer) RegisterCompressor(method uint16, comp Compressor) {
|
func (w *Writer) RegisterCompressor(method uint16, comp Compressor) {
|
||||||
if w.compressors == nil {
|
if w.compressors == nil {
|
||||||
|
@ -41,24 +41,21 @@ type Reader struct {
|
|||||||
const minReadBufferSize = 16
|
const minReadBufferSize = 16
|
||||||
const maxConsecutiveEmptyReads = 100
|
const maxConsecutiveEmptyReads = 100
|
||||||
|
|
||||||
// NewReaderSize returns a new Reader whose buffer has at least the specified
|
// NewReaderSize returns a new [Reader] whose buffer has at least the specified
|
||||||
// size. If the argument io.Reader is already a Reader with large enough
|
// size. If the argument io.Reader is already a [Reader] with large enough
|
||||||
// size, it returns the underlying Reader.
|
// size, it returns the underlying [Reader].
|
||||||
func NewReaderSize(rd io.Reader, size int) *Reader {
|
func NewReaderSize(rd io.Reader, size int) *Reader {
|
||||||
// Is it already a Reader?
|
// Is it already a Reader?
|
||||||
b, ok := rd.(*Reader)
|
b, ok := rd.(*Reader)
|
||||||
if ok && len(b.buf) >= size {
|
if ok && len(b.buf) >= size {
|
||||||
return b
|
return b
|
||||||
}
|
}
|
||||||
if size < minReadBufferSize {
|
|
||||||
size = minReadBufferSize
|
|
||||||
}
|
|
||||||
r := new(Reader)
|
r := new(Reader)
|
||||||
r.reset(make([]byte, size), rd)
|
r.reset(make([]byte, max(size, minReadBufferSize)), rd)
|
||||||
return r
|
return r
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewReader returns a new Reader whose buffer has the default size.
|
// NewReader returns a new [Reader] whose buffer has the default size.
|
||||||
func NewReader(rd io.Reader) *Reader {
|
func NewReader(rd io.Reader) *Reader {
|
||||||
return NewReaderSize(rd, defaultBufSize)
|
return NewReaderSize(rd, defaultBufSize)
|
||||||
}
|
}
|
||||||
@ -68,9 +65,9 @@ func (b *Reader) Size() int { return len(b.buf) }
|
|||||||
|
|
||||||
// Reset discards any buffered data, resets all state, and switches
|
// Reset discards any buffered data, resets all state, and switches
|
||||||
// the buffered reader to read from r.
|
// the buffered reader to read from r.
|
||||||
// Calling Reset on the zero value of Reader initializes the internal buffer
|
// Calling Reset on the zero value of [Reader] initializes the internal buffer
|
||||||
// to the default size.
|
// to the default size.
|
||||||
// Calling b.Reset(b) (that is, resetting a Reader to itself) does nothing.
|
// Calling b.Reset(b) (that is, resetting a [Reader] to itself) does nothing.
|
||||||
func (b *Reader) Reset(r io.Reader) {
|
func (b *Reader) Reset(r io.Reader) {
|
||||||
// If a Reader r is passed to NewReader, NewReader will return r.
|
// If a Reader r is passed to NewReader, NewReader will return r.
|
||||||
// Different layers of code may do that, and then later pass r
|
// Different layers of code may do that, and then later pass r
|
||||||
@ -135,9 +132,9 @@ func (b *Reader) readErr() error {
|
|||||||
// Peek returns the next n bytes without advancing the reader. The bytes stop
|
// Peek returns the next n bytes without advancing the reader. The bytes stop
|
||||||
// being valid at the next read call. If Peek returns fewer than n bytes, it
|
// being valid at the next read call. If Peek returns fewer than n bytes, it
|
||||||
// also returns an error explaining why the read is short. The error is
|
// also returns an error explaining why the read is short. The error is
|
||||||
// ErrBufferFull if n is larger than b's buffer size.
|
// [ErrBufferFull] if n is larger than b's buffer size.
|
||||||
//
|
//
|
||||||
// Calling Peek prevents a UnreadByte or UnreadRune call from succeeding
|
// Calling Peek prevents a [Reader.UnreadByte] or [Reader.UnreadRune] call from succeeding
|
||||||
// until the next read operation.
|
// until the next read operation.
|
||||||
func (b *Reader) Peek(n int) ([]byte, error) {
|
func (b *Reader) Peek(n int) ([]byte, error) {
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
@ -207,10 +204,10 @@ func (b *Reader) Discard(n int) (discarded int, err error) {
|
|||||||
|
|
||||||
// Read reads data into p.
|
// Read reads data into p.
|
||||||
// It returns the number of bytes read into p.
|
// It returns the number of bytes read into p.
|
||||||
// The bytes are taken from at most one Read on the underlying Reader,
|
// The bytes are taken from at most one Read on the underlying [Reader],
|
||||||
// hence n may be less than len(p).
|
// hence n may be less than len(p).
|
||||||
// To read exactly len(p) bytes, use io.ReadFull(b, p).
|
// To read exactly len(p) bytes, use io.ReadFull(b, p).
|
||||||
// If the underlying Reader can return a non-zero count with io.EOF,
|
// If the underlying [Reader] can return a non-zero count with io.EOF,
|
||||||
// then this Read method can do so as well; see the [io.Reader] docs.
|
// then this Read method can do so as well; see the [io.Reader] docs.
|
||||||
func (b *Reader) Read(p []byte) (n int, err error) {
|
func (b *Reader) Read(p []byte) (n int, err error) {
|
||||||
n = len(p)
|
n = len(p)
|
||||||
@ -280,7 +277,7 @@ func (b *Reader) ReadByte() (byte, error) {
|
|||||||
// UnreadByte unreads the last byte. Only the most recently read byte can be unread.
|
// UnreadByte unreads the last byte. Only the most recently read byte can be unread.
|
||||||
//
|
//
|
||||||
// UnreadByte returns an error if the most recent method called on the
|
// UnreadByte returns an error if the most recent method called on the
|
||||||
// Reader was not a read operation. Notably, Peek, Discard, and WriteTo are not
|
// [Reader] was not a read operation. Notably, [Reader.Peek], [Reader.Discard], and [Reader.WriteTo] are not
|
||||||
// considered read operations.
|
// considered read operations.
|
||||||
func (b *Reader) UnreadByte() error {
|
func (b *Reader) UnreadByte() error {
|
||||||
if b.lastByte < 0 || b.r == 0 && b.w > 0 {
|
if b.lastByte < 0 || b.r == 0 && b.w > 0 {
|
||||||
@ -321,8 +318,8 @@ func (b *Reader) ReadRune() (r rune, size int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// UnreadRune unreads the last rune. If the most recent method called on
|
// UnreadRune unreads the last rune. If the most recent method called on
|
||||||
// the Reader was not a ReadRune, UnreadRune returns an error. (In this
|
// the [Reader] was not a [Reader.ReadRune], [Reader.UnreadRune] returns an error. (In this
|
||||||
// regard it is stricter than UnreadByte, which will unread the last byte
|
// regard it is stricter than [Reader.UnreadByte], which will unread the last byte
|
||||||
// from any read operation.)
|
// from any read operation.)
|
||||||
func (b *Reader) UnreadRune() error {
|
func (b *Reader) UnreadRune() error {
|
||||||
if b.lastRuneSize < 0 || b.r < b.lastRuneSize {
|
if b.lastRuneSize < 0 || b.r < b.lastRuneSize {
|
||||||
@ -342,10 +339,10 @@ func (b *Reader) Buffered() int { return b.w - b.r }
|
|||||||
// The bytes stop being valid at the next read.
|
// The bytes stop being valid at the next read.
|
||||||
// If ReadSlice encounters an error before finding a delimiter,
|
// If ReadSlice encounters an error before finding a delimiter,
|
||||||
// it returns all the data in the buffer and the error itself (often io.EOF).
|
// it returns all the data in the buffer and the error itself (often io.EOF).
|
||||||
// ReadSlice fails with error ErrBufferFull if the buffer fills without a delim.
|
// ReadSlice fails with error [ErrBufferFull] if the buffer fills without a delim.
|
||||||
// Because the data returned from ReadSlice will be overwritten
|
// Because the data returned from ReadSlice will be overwritten
|
||||||
// by the next I/O operation, most clients should use
|
// by the next I/O operation, most clients should use
|
||||||
// ReadBytes or ReadString instead.
|
// [Reader.ReadBytes] or ReadString instead.
|
||||||
// ReadSlice returns err != nil if and only if line does not end in delim.
|
// ReadSlice returns err != nil if and only if line does not end in delim.
|
||||||
func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
|
func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
|
||||||
s := 0 // search start index
|
s := 0 // search start index
|
||||||
@ -389,7 +386,7 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// ReadLine is a low-level line-reading primitive. Most callers should use
|
// ReadLine is a low-level line-reading primitive. Most callers should use
|
||||||
// ReadBytes('\n') or ReadString('\n') instead or use a Scanner.
|
// [Reader.ReadBytes]('\n') or [Reader.ReadString]('\n') instead or use a [Scanner].
|
||||||
//
|
//
|
||||||
// ReadLine tries to return a single line, not including the end-of-line bytes.
|
// ReadLine tries to return a single line, not including the end-of-line bytes.
|
||||||
// If the line was too long for the buffer then isPrefix is set and the
|
// If the line was too long for the buffer then isPrefix is set and the
|
||||||
@ -401,7 +398,7 @@ func (b *Reader) ReadSlice(delim byte) (line []byte, err error) {
|
|||||||
//
|
//
|
||||||
// The text returned from ReadLine does not include the line end ("\r\n" or "\n").
|
// The text returned from ReadLine does not include the line end ("\r\n" or "\n").
|
||||||
// No indication or error is given if the input ends without a final line end.
|
// No indication or error is given if the input ends without a final line end.
|
||||||
// Calling UnreadByte after ReadLine will always unread the last byte read
|
// Calling [Reader.UnreadByte] after ReadLine will always unread the last byte read
|
||||||
// (possibly a character belonging to the line end) even if that byte is not
|
// (possibly a character belonging to the line end) even if that byte is not
|
||||||
// part of the line returned by ReadLine.
|
// part of the line returned by ReadLine.
|
||||||
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) {
|
func (b *Reader) ReadLine() (line []byte, isPrefix bool, err error) {
|
||||||
@ -511,9 +508,9 @@ func (b *Reader) ReadString(delim byte) (string, error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteTo implements io.WriterTo.
|
// WriteTo implements io.WriterTo.
|
||||||
// This may make multiple calls to the Read method of the underlying Reader.
|
// This may make multiple calls to the [Reader.Read] method of the underlying [Reader].
|
||||||
// If the underlying reader supports the WriteTo method,
|
// If the underlying reader supports the [Reader.WriteTo] method,
|
||||||
// this calls the underlying WriteTo without buffering.
|
// this calls the underlying [Reader.WriteTo] without buffering.
|
||||||
func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
|
func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
b.lastByte = -1
|
b.lastByte = -1
|
||||||
b.lastRuneSize = -1
|
b.lastRuneSize = -1
|
||||||
@ -558,7 +555,7 @@ func (b *Reader) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
|
|
||||||
var errNegativeWrite = errors.New("bufio: writer returned negative count from Write")
|
var errNegativeWrite = errors.New("bufio: writer returned negative count from Write")
|
||||||
|
|
||||||
// writeBuf writes the Reader's buffer to the writer.
|
// writeBuf writes the [Reader]'s buffer to the writer.
|
||||||
func (b *Reader) writeBuf(w io.Writer) (int64, error) {
|
func (b *Reader) writeBuf(w io.Writer) (int64, error) {
|
||||||
n, err := w.Write(b.buf[b.r:b.w])
|
n, err := w.Write(b.buf[b.r:b.w])
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
@ -570,12 +567,12 @@ func (b *Reader) writeBuf(w io.Writer) (int64, error) {
|
|||||||
|
|
||||||
// buffered output
|
// buffered output
|
||||||
|
|
||||||
// Writer implements buffering for an io.Writer object.
|
// Writer implements buffering for an [io.Writer] object.
|
||||||
// If an error occurs writing to a Writer, no more data will be
|
// If an error occurs writing to a [Writer], no more data will be
|
||||||
// accepted and all subsequent writes, and Flush, will return the error.
|
// accepted and all subsequent writes, and [Writer.Flush], will return the error.
|
||||||
// After all data has been written, the client should call the
|
// After all data has been written, the client should call the
|
||||||
// Flush method to guarantee all data has been forwarded to
|
// [Writer.Flush] method to guarantee all data has been forwarded to
|
||||||
// the underlying io.Writer.
|
// the underlying [io.Writer].
|
||||||
type Writer struct {
|
type Writer struct {
|
||||||
err error
|
err error
|
||||||
buf []byte
|
buf []byte
|
||||||
@ -583,9 +580,9 @@ type Writer struct {
|
|||||||
wr io.Writer
|
wr io.Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWriterSize returns a new Writer whose buffer has at least the specified
|
// NewWriterSize returns a new [Writer] whose buffer has at least the specified
|
||||||
// size. If the argument io.Writer is already a Writer with large enough
|
// size. If the argument io.Writer is already a [Writer] with large enough
|
||||||
// size, it returns the underlying Writer.
|
// size, it returns the underlying [Writer].
|
||||||
func NewWriterSize(w io.Writer, size int) *Writer {
|
func NewWriterSize(w io.Writer, size int) *Writer {
|
||||||
// Is it already a Writer?
|
// Is it already a Writer?
|
||||||
b, ok := w.(*Writer)
|
b, ok := w.(*Writer)
|
||||||
@ -601,9 +598,9 @@ func NewWriterSize(w io.Writer, size int) *Writer {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewWriter returns a new Writer whose buffer has the default size.
|
// NewWriter returns a new [Writer] whose buffer has the default size.
|
||||||
// If the argument io.Writer is already a Writer with large enough buffer size,
|
// If the argument io.Writer is already a [Writer] with large enough buffer size,
|
||||||
// it returns the underlying Writer.
|
// it returns the underlying [Writer].
|
||||||
func NewWriter(w io.Writer) *Writer {
|
func NewWriter(w io.Writer) *Writer {
|
||||||
return NewWriterSize(w, defaultBufSize)
|
return NewWriterSize(w, defaultBufSize)
|
||||||
}
|
}
|
||||||
@ -613,9 +610,9 @@ func (b *Writer) Size() int { return len(b.buf) }
|
|||||||
|
|
||||||
// Reset discards any unflushed buffered data, clears any error, and
|
// Reset discards any unflushed buffered data, clears any error, and
|
||||||
// resets b to write its output to w.
|
// resets b to write its output to w.
|
||||||
// Calling Reset on the zero value of Writer initializes the internal buffer
|
// Calling Reset on the zero value of [Writer] initializes the internal buffer
|
||||||
// to the default size.
|
// to the default size.
|
||||||
// Calling w.Reset(w) (that is, resetting a Writer to itself) does nothing.
|
// Calling w.Reset(w) (that is, resetting a [Writer] to itself) does nothing.
|
||||||
func (b *Writer) Reset(w io.Writer) {
|
func (b *Writer) Reset(w io.Writer) {
|
||||||
// If a Writer w is passed to NewWriter, NewWriter will return w.
|
// If a Writer w is passed to NewWriter, NewWriter will return w.
|
||||||
// Different layers of code may do that, and then later pass w
|
// Different layers of code may do that, and then later pass w
|
||||||
@ -631,7 +628,7 @@ func (b *Writer) Reset(w io.Writer) {
|
|||||||
b.wr = w
|
b.wr = w
|
||||||
}
|
}
|
||||||
|
|
||||||
// Flush writes any buffered data to the underlying io.Writer.
|
// Flush writes any buffered data to the underlying [io.Writer].
|
||||||
func (b *Writer) Flush() error {
|
func (b *Writer) Flush() error {
|
||||||
if b.err != nil {
|
if b.err != nil {
|
||||||
return b.err
|
return b.err
|
||||||
@ -660,7 +657,7 @@ func (b *Writer) Available() int { return len(b.buf) - b.n }
|
|||||||
|
|
||||||
// AvailableBuffer returns an empty buffer with b.Available() capacity.
|
// AvailableBuffer returns an empty buffer with b.Available() capacity.
|
||||||
// This buffer is intended to be appended to and
|
// This buffer is intended to be appended to and
|
||||||
// passed to an immediately succeeding Write call.
|
// passed to an immediately succeeding [Writer.Write] call.
|
||||||
// The buffer is only valid until the next write operation on b.
|
// The buffer is only valid until the next write operation on b.
|
||||||
func (b *Writer) AvailableBuffer() []byte {
|
func (b *Writer) AvailableBuffer() []byte {
|
||||||
return b.buf[b.n:][:0]
|
return b.buf[b.n:][:0]
|
||||||
@ -777,7 +774,7 @@ func (b *Writer) WriteString(s string) (int, error) {
|
|||||||
return nn, nil
|
return nn, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadFrom implements io.ReaderFrom. If the underlying writer
|
// ReadFrom implements [io.ReaderFrom]. If the underlying writer
|
||||||
// supports the ReadFrom method, this calls the underlying ReadFrom.
|
// supports the ReadFrom method, this calls the underlying ReadFrom.
|
||||||
// If there is buffered data and an underlying ReadFrom, this fills
|
// If there is buffered data and an underlying ReadFrom, this fills
|
||||||
// the buffer and writes it before calling ReadFrom.
|
// the buffer and writes it before calling ReadFrom.
|
||||||
@ -829,14 +826,14 @@ func (b *Writer) ReadFrom(r io.Reader) (n int64, err error) {
|
|||||||
|
|
||||||
// buffered input and output
|
// buffered input and output
|
||||||
|
|
||||||
// ReadWriter stores pointers to a Reader and a Writer.
|
// ReadWriter stores pointers to a [Reader] and a [Writer].
|
||||||
// It implements io.ReadWriter.
|
// It implements [io.ReadWriter].
|
||||||
type ReadWriter struct {
|
type ReadWriter struct {
|
||||||
*Reader
|
*Reader
|
||||||
*Writer
|
*Writer
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewReadWriter allocates a new ReadWriter that dispatches to r and w.
|
// NewReadWriter allocates a new [ReadWriter] that dispatches to r and w.
|
||||||
func NewReadWriter(r *Reader, w *Writer) *ReadWriter {
|
func NewReadWriter(r *Reader, w *Writer) *ReadWriter {
|
||||||
return &ReadWriter{r, w}
|
return &ReadWriter{r, w}
|
||||||
}
|
}
|
||||||
|
@ -6,6 +6,7 @@ package bufio_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"bufio"
|
"bufio"
|
||||||
|
"bytes"
|
||||||
"fmt"
|
"fmt"
|
||||||
"os"
|
"os"
|
||||||
"strconv"
|
"strconv"
|
||||||
@ -137,3 +138,36 @@ func ExampleScanner_emptyFinalToken() {
|
|||||||
}
|
}
|
||||||
// Output: "1" "2" "3" "4" ""
|
// Output: "1" "2" "3" "4" ""
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Use a Scanner with a custom split function to parse a comma-separated
|
||||||
|
// list with an empty final value but stops at the token "STOP".
|
||||||
|
func ExampleScanner_earlyStop() {
|
||||||
|
onComma := func(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||||
|
i := bytes.IndexByte(data, ',')
|
||||||
|
if i == -1 {
|
||||||
|
if !atEOF {
|
||||||
|
return 0, nil, nil
|
||||||
|
}
|
||||||
|
// If we have reached the end, return the last token.
|
||||||
|
return 0, data, bufio.ErrFinalToken
|
||||||
|
}
|
||||||
|
// If the token is "STOP", stop the scanning and ignore the rest.
|
||||||
|
if string(data[:i]) == "STOP" {
|
||||||
|
return i + 1, nil, bufio.ErrFinalToken
|
||||||
|
}
|
||||||
|
// Otherwise, return the token before the comma.
|
||||||
|
return i + 1, data[:i], nil
|
||||||
|
}
|
||||||
|
const input = "1,2,STOP,4,"
|
||||||
|
scanner := bufio.NewScanner(strings.NewReader(input))
|
||||||
|
scanner.Split(onComma)
|
||||||
|
for scanner.Scan() {
|
||||||
|
fmt.Printf("Got a token %q\n", scanner.Text())
|
||||||
|
}
|
||||||
|
if err := scanner.Err(); err != nil {
|
||||||
|
fmt.Fprintln(os.Stderr, "reading input:", err)
|
||||||
|
}
|
||||||
|
// Output:
|
||||||
|
// Got a token "1"
|
||||||
|
// Got a token "2"
|
||||||
|
}
|
||||||
|
@ -13,19 +13,19 @@ import (
|
|||||||
|
|
||||||
// Scanner provides a convenient interface for reading data such as
|
// Scanner provides a convenient interface for reading data such as
|
||||||
// a file of newline-delimited lines of text. Successive calls to
|
// a file of newline-delimited lines of text. Successive calls to
|
||||||
// the Scan method will step through the 'tokens' of a file, skipping
|
// the [Scanner.Scan] method will step through the 'tokens' of a file, skipping
|
||||||
// the bytes between the tokens. The specification of a token is
|
// the bytes between the tokens. The specification of a token is
|
||||||
// defined by a split function of type SplitFunc; the default split
|
// defined by a split function of type [SplitFunc]; the default split
|
||||||
// function breaks the input into lines with line termination stripped. Split
|
// function breaks the input into lines with line termination stripped. [Scanner.Split]
|
||||||
// functions are defined in this package for scanning a file into
|
// functions are defined in this package for scanning a file into
|
||||||
// lines, bytes, UTF-8-encoded runes, and space-delimited words. The
|
// lines, bytes, UTF-8-encoded runes, and space-delimited words. The
|
||||||
// client may instead provide a custom split function.
|
// client may instead provide a custom split function.
|
||||||
//
|
//
|
||||||
// Scanning stops unrecoverably at EOF, the first I/O error, or a token too
|
// Scanning stops unrecoverably at EOF, the first I/O error, or a token too
|
||||||
// large to fit in the buffer. When a scan stops, the reader may have
|
// large to fit in the [Scanner.Buffer]. When a scan stops, the reader may have
|
||||||
// advanced arbitrarily far past the last token. Programs that need more
|
// advanced arbitrarily far past the last token. Programs that need more
|
||||||
// control over error handling or large tokens, or must run sequential scans
|
// control over error handling or large tokens, or must run sequential scans
|
||||||
// on a reader, should use bufio.Reader instead.
|
// on a reader, should use [bufio.Reader] instead.
|
||||||
type Scanner struct {
|
type Scanner struct {
|
||||||
r io.Reader // The reader provided by the client.
|
r io.Reader // The reader provided by the client.
|
||||||
split SplitFunc // The function to split the tokens.
|
split SplitFunc // The function to split the tokens.
|
||||||
@ -42,21 +42,23 @@ type Scanner struct {
|
|||||||
|
|
||||||
// SplitFunc is the signature of the split function used to tokenize the
|
// SplitFunc is the signature of the split function used to tokenize the
|
||||||
// input. The arguments are an initial substring of the remaining unprocessed
|
// input. The arguments are an initial substring of the remaining unprocessed
|
||||||
// data and a flag, atEOF, that reports whether the Reader has no more data
|
// data and a flag, atEOF, that reports whether the [Reader] has no more data
|
||||||
// to give. The return values are the number of bytes to advance the input
|
// to give. The return values are the number of bytes to advance the input
|
||||||
// and the next token to return to the user, if any, plus an error, if any.
|
// and the next token to return to the user, if any, plus an error, if any.
|
||||||
//
|
//
|
||||||
// Scanning stops if the function returns an error, in which case some of
|
// Scanning stops if the function returns an error, in which case some of
|
||||||
// the input may be discarded. If that error is ErrFinalToken, scanning
|
// the input may be discarded. If that error is [ErrFinalToken], scanning
|
||||||
// stops with no error.
|
// stops with no error. A non-nil token delivered with [ErrFinalToken]
|
||||||
|
// will be the last token, and a nil token with [ErrFinalToken]
|
||||||
|
// immediately stops the scanning.
|
||||||
//
|
//
|
||||||
// Otherwise, the Scanner advances the input. If the token is not nil,
|
// Otherwise, the [Scanner] advances the input. If the token is not nil,
|
||||||
// the Scanner returns it to the user. If the token is nil, the
|
// the [Scanner] returns it to the user. If the token is nil, the
|
||||||
// Scanner reads more data and continues scanning; if there is no more
|
// Scanner reads more data and continues scanning; if there is no more
|
||||||
// data--if atEOF was true--the Scanner returns. If the data does not
|
// data--if atEOF was true--the [Scanner] returns. If the data does not
|
||||||
// yet hold a complete token, for instance if it has no newline while
|
// yet hold a complete token, for instance if it has no newline while
|
||||||
// scanning lines, a SplitFunc can return (0, nil, nil) to signal the
|
// scanning lines, a [SplitFunc] can return (0, nil, nil) to signal the
|
||||||
// Scanner to read more data into the slice and try again with a
|
// [Scanner] to read more data into the slice and try again with a
|
||||||
// longer slice starting at the same point in the input.
|
// longer slice starting at the same point in the input.
|
||||||
//
|
//
|
||||||
// The function is never called with an empty data slice unless atEOF
|
// The function is never called with an empty data slice unless atEOF
|
||||||
@ -74,7 +76,7 @@ var (
|
|||||||
|
|
||||||
const (
|
const (
|
||||||
// MaxScanTokenSize is the maximum size used to buffer a token
|
// MaxScanTokenSize is the maximum size used to buffer a token
|
||||||
// unless the user provides an explicit buffer with Scanner.Buffer.
|
// unless the user provides an explicit buffer with [Scanner.Buffer].
|
||||||
// The actual maximum token size may be smaller as the buffer
|
// The actual maximum token size may be smaller as the buffer
|
||||||
// may need to include, for instance, a newline.
|
// may need to include, for instance, a newline.
|
||||||
MaxScanTokenSize = 64 * 1024
|
MaxScanTokenSize = 64 * 1024
|
||||||
@ -82,8 +84,8 @@ const (
|
|||||||
startBufSize = 4096 // Size of initial allocation for buffer.
|
startBufSize = 4096 // Size of initial allocation for buffer.
|
||||||
)
|
)
|
||||||
|
|
||||||
// NewScanner returns a new Scanner to read from r.
|
// NewScanner returns a new [Scanner] to read from r.
|
||||||
// The split function defaults to ScanLines.
|
// The split function defaults to [ScanLines].
|
||||||
func NewScanner(r io.Reader) *Scanner {
|
func NewScanner(r io.Reader) *Scanner {
|
||||||
return &Scanner{
|
return &Scanner{
|
||||||
r: r,
|
r: r,
|
||||||
@ -92,7 +94,7 @@ func NewScanner(r io.Reader) *Scanner {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Err returns the first non-EOF error that was encountered by the Scanner.
|
// Err returns the first non-EOF error that was encountered by the [Scanner].
|
||||||
func (s *Scanner) Err() error {
|
func (s *Scanner) Err() error {
|
||||||
if s.err == io.EOF {
|
if s.err == io.EOF {
|
||||||
return nil
|
return nil
|
||||||
@ -100,34 +102,36 @@ func (s *Scanner) Err() error {
|
|||||||
return s.err
|
return s.err
|
||||||
}
|
}
|
||||||
|
|
||||||
// Bytes returns the most recent token generated by a call to Scan.
|
// Bytes returns the most recent token generated by a call to [Scanner.Scan].
|
||||||
// The underlying array may point to data that will be overwritten
|
// The underlying array may point to data that will be overwritten
|
||||||
// by a subsequent call to Scan. It does no allocation.
|
// by a subsequent call to Scan. It does no allocation.
|
||||||
func (s *Scanner) Bytes() []byte {
|
func (s *Scanner) Bytes() []byte {
|
||||||
return s.token
|
return s.token
|
||||||
}
|
}
|
||||||
|
|
||||||
// Text returns the most recent token generated by a call to Scan
|
// Text returns the most recent token generated by a call to [Scanner.Scan]
|
||||||
// as a newly allocated string holding its bytes.
|
// as a newly allocated string holding its bytes.
|
||||||
func (s *Scanner) Text() string {
|
func (s *Scanner) Text() string {
|
||||||
return string(s.token)
|
return string(s.token)
|
||||||
}
|
}
|
||||||
|
|
||||||
// ErrFinalToken is a special sentinel error value. It is intended to be
|
// ErrFinalToken is a special sentinel error value. It is intended to be
|
||||||
// returned by a Split function to indicate that the token being delivered
|
// returned by a Split function to indicate that the scanning should stop
|
||||||
// with the error is the last token and scanning should stop after this one.
|
// with no error. If the token being delivered with this error is not nil,
|
||||||
// After ErrFinalToken is received by Scan, scanning stops with no error.
|
// the token is the last token.
|
||||||
|
//
|
||||||
// The value is useful to stop processing early or when it is necessary to
|
// The value is useful to stop processing early or when it is necessary to
|
||||||
// deliver a final empty token. One could achieve the same behavior
|
// deliver a final empty token (which is different from a nil token).
|
||||||
// with a custom error value but providing one here is tidier.
|
// One could achieve the same behavior with a custom error value but
|
||||||
|
// providing one here is tidier.
|
||||||
// See the emptyFinalToken example for a use of this value.
|
// See the emptyFinalToken example for a use of this value.
|
||||||
var ErrFinalToken = errors.New("final token")
|
var ErrFinalToken = errors.New("final token")
|
||||||
|
|
||||||
// Scan advances the Scanner to the next token, which will then be
|
// Scan advances the [Scanner] to the next token, which will then be
|
||||||
// available through the Bytes or Text method. It returns false when the
|
// available through the [Scanner.Bytes] or [Scanner.Text] method. It returns false when
|
||||||
// scan stops, either by reaching the end of the input or an error.
|
// there are no more tokens, either by reaching the end of the input or an error.
|
||||||
// After Scan returns false, the Err method will return any error that
|
// After Scan returns false, the [Scanner.Err] method will return any error that
|
||||||
// occurred during scanning, except that if it was io.EOF, Err
|
// occurred during scanning, except that if it was [io.EOF], [Scanner.Err]
|
||||||
// will return nil.
|
// will return nil.
|
||||||
// Scan panics if the split function returns too many empty
|
// Scan panics if the split function returns too many empty
|
||||||
// tokens without advancing the input. This is a common error mode for
|
// tokens without advancing the input. This is a common error mode for
|
||||||
@ -148,7 +152,10 @@ func (s *Scanner) Scan() bool {
|
|||||||
if err == ErrFinalToken {
|
if err == ErrFinalToken {
|
||||||
s.token = token
|
s.token = token
|
||||||
s.done = true
|
s.done = true
|
||||||
return true
|
// When token is not nil, it means the scanning stops
|
||||||
|
// with a trailing token, and thus the return value
|
||||||
|
// should be true to indicate the existence of the token.
|
||||||
|
return token != nil
|
||||||
}
|
}
|
||||||
s.setErr(err)
|
s.setErr(err)
|
||||||
return false
|
return false
|
||||||
@ -198,9 +205,7 @@ func (s *Scanner) Scan() bool {
|
|||||||
if newSize == 0 {
|
if newSize == 0 {
|
||||||
newSize = startBufSize
|
newSize = startBufSize
|
||||||
}
|
}
|
||||||
if newSize > s.maxTokenSize {
|
newSize = min(newSize, s.maxTokenSize)
|
||||||
newSize = s.maxTokenSize
|
|
||||||
}
|
|
||||||
newBuf := make([]byte, newSize)
|
newBuf := make([]byte, newSize)
|
||||||
copy(newBuf, s.buf[s.start:s.end])
|
copy(newBuf, s.buf[s.start:s.end])
|
||||||
s.buf = newBuf
|
s.buf = newBuf
|
||||||
@ -258,10 +263,10 @@ func (s *Scanner) setErr(err error) {
|
|||||||
// Buffer sets the initial buffer to use when scanning
|
// Buffer sets the initial buffer to use when scanning
|
||||||
// and the maximum size of buffer that may be allocated during scanning.
|
// and the maximum size of buffer that may be allocated during scanning.
|
||||||
// The maximum token size must be less than the larger of max and cap(buf).
|
// The maximum token size must be less than the larger of max and cap(buf).
|
||||||
// If max <= cap(buf), Scan will use this buffer only and do no allocation.
|
// If max <= cap(buf), [Scanner.Scan] will use this buffer only and do no allocation.
|
||||||
//
|
//
|
||||||
// By default, Scan uses an internal buffer and sets the
|
// By default, [Scanner.Scan] uses an internal buffer and sets the
|
||||||
// maximum token size to MaxScanTokenSize.
|
// maximum token size to [MaxScanTokenSize].
|
||||||
//
|
//
|
||||||
// Buffer panics if it is called after scanning has started.
|
// Buffer panics if it is called after scanning has started.
|
||||||
func (s *Scanner) Buffer(buf []byte, max int) {
|
func (s *Scanner) Buffer(buf []byte, max int) {
|
||||||
@ -272,8 +277,8 @@ func (s *Scanner) Buffer(buf []byte, max int) {
|
|||||||
s.maxTokenSize = max
|
s.maxTokenSize = max
|
||||||
}
|
}
|
||||||
|
|
||||||
// Split sets the split function for the Scanner.
|
// Split sets the split function for the [Scanner].
|
||||||
// The default split function is ScanLines.
|
// The default split function is [ScanLines].
|
||||||
//
|
//
|
||||||
// Split panics if it is called after scanning has started.
|
// Split panics if it is called after scanning has started.
|
||||||
func (s *Scanner) Split(split SplitFunc) {
|
func (s *Scanner) Split(split SplitFunc) {
|
||||||
@ -285,7 +290,7 @@ func (s *Scanner) Split(split SplitFunc) {
|
|||||||
|
|
||||||
// Split functions
|
// Split functions
|
||||||
|
|
||||||
// ScanBytes is a split function for a Scanner that returns each byte as a token.
|
// ScanBytes is a split function for a [Scanner] that returns each byte as a token.
|
||||||
func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
||||||
if atEOF && len(data) == 0 {
|
if atEOF && len(data) == 0 {
|
||||||
return 0, nil, nil
|
return 0, nil, nil
|
||||||
@ -295,7 +300,7 @@ func ScanBytes(data []byte, atEOF bool) (advance int, token []byte, err error) {
|
|||||||
|
|
||||||
var errorRune = []byte(string(utf8.RuneError))
|
var errorRune = []byte(string(utf8.RuneError))
|
||||||
|
|
||||||
// ScanRunes is a split function for a Scanner that returns each
|
// ScanRunes is a split function for a [Scanner] that returns each
|
||||||
// UTF-8-encoded rune as a token. The sequence of runes returned is
|
// UTF-8-encoded rune as a token. The sequence of runes returned is
|
||||||
// equivalent to that from a range loop over the input as a string, which
|
// equivalent to that from a range loop over the input as a string, which
|
||||||
// means that erroneous UTF-8 encodings translate to U+FFFD = "\xef\xbf\xbd".
|
// means that erroneous UTF-8 encodings translate to U+FFFD = "\xef\xbf\xbd".
|
||||||
@ -341,7 +346,7 @@ func dropCR(data []byte) []byte {
|
|||||||
return data
|
return data
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScanLines is a split function for a Scanner that returns each line of
|
// ScanLines is a split function for a [Scanner] that returns each line of
|
||||||
// text, stripped of any trailing end-of-line marker. The returned line may
|
// text, stripped of any trailing end-of-line marker. The returned line may
|
||||||
// be empty. The end-of-line marker is one optional carriage return followed
|
// be empty. The end-of-line marker is one optional carriage return followed
|
||||||
// by one mandatory newline. In regular expression notation, it is `\r?\n`.
|
// by one mandatory newline. In regular expression notation, it is `\r?\n`.
|
||||||
@ -388,7 +393,7 @@ func isSpace(r rune) bool {
|
|||||||
return false
|
return false
|
||||||
}
|
}
|
||||||
|
|
||||||
// ScanWords is a split function for a Scanner that returns each
|
// ScanWords is a split function for a [Scanner] that returns each
|
||||||
// space-separated word of text, with surrounding spaces deleted. It will
|
// space-separated word of text, with surrounding spaces deleted. It will
|
||||||
// never return an empty string. The definition of space is set by
|
// never return an empty string. The definition of space is set by
|
||||||
// unicode.IsSpace.
|
// unicode.IsSpace.
|
||||||
|
@ -284,9 +284,10 @@ func panic(v any)
|
|||||||
// by restoring normal execution and retrieves the error value passed to the
|
// by restoring normal execution and retrieves the error value passed to the
|
||||||
// call of panic. If recover is called outside the deferred function it will
|
// call of panic. If recover is called outside the deferred function it will
|
||||||
// not stop a panicking sequence. In this case, or when the goroutine is not
|
// not stop a panicking sequence. In this case, or when the goroutine is not
|
||||||
// panicking, or if the argument supplied to panic was nil, recover returns
|
// panicking, recover returns nil.
|
||||||
// nil. Thus the return value from recover reports whether the goroutine is
|
//
|
||||||
// panicking.
|
// Prior to Go 1.21, recover would also return nil if panic is called with
|
||||||
|
// a nil argument. See [panic] for details.
|
||||||
func recover() any
|
func recover() any
|
||||||
|
|
||||||
// The print built-in function formats its arguments in an
|
// The print built-in function formats its arguments in an
|
||||||
|
@ -98,3 +98,18 @@ func TestIndexNearPageBoundary(t *testing.T) {
|
|||||||
}
|
}
|
||||||
q[len(q)-1] = 0
|
q[len(q)-1] = 0
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestCountNearPageBoundary(t *testing.T) {
|
||||||
|
t.Parallel()
|
||||||
|
b := dangerousSlice(t)
|
||||||
|
for i := range b {
|
||||||
|
c := Count(b[i:], []byte{1})
|
||||||
|
if c != 0 {
|
||||||
|
t.Fatalf("Count(b[%d:], {1})=%d, want 0\n", i, c)
|
||||||
|
}
|
||||||
|
c = Count(b[:i], []byte{0})
|
||||||
|
if c != i {
|
||||||
|
t.Fatalf("Count(b[:%d], {0})=%d, want %d\n", i, c, i)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -15,7 +15,7 @@ import (
|
|||||||
// smallBufferSize is an initial allocation minimal capacity.
|
// smallBufferSize is an initial allocation minimal capacity.
|
||||||
const smallBufferSize = 64
|
const smallBufferSize = 64
|
||||||
|
|
||||||
// A Buffer is a variable-sized buffer of bytes with Read and Write methods.
|
// A Buffer is a variable-sized buffer of bytes with [Buffer.Read] and [Buffer.Write] methods.
|
||||||
// The zero value for Buffer is an empty buffer ready to use.
|
// The zero value for Buffer is an empty buffer ready to use.
|
||||||
type Buffer struct {
|
type Buffer struct {
|
||||||
buf []byte // contents are the bytes buf[off : len(buf)]
|
buf []byte // contents are the bytes buf[off : len(buf)]
|
||||||
@ -48,19 +48,19 @@ const maxInt = int(^uint(0) >> 1)
|
|||||||
|
|
||||||
// Bytes returns a slice of length b.Len() holding the unread portion of the buffer.
|
// Bytes returns a slice of length b.Len() holding the unread portion of the buffer.
|
||||||
// The slice is valid for use only until the next buffer modification (that is,
|
// The slice is valid for use only until the next buffer modification (that is,
|
||||||
// only until the next call to a method like Read, Write, Reset, or Truncate).
|
// only until the next call to a method like [Buffer.Read], [Buffer.Write], [Buffer.Reset], or [Buffer.Truncate]).
|
||||||
// The slice aliases the buffer content at least until the next buffer modification,
|
// The slice aliases the buffer content at least until the next buffer modification,
|
||||||
// so immediate changes to the slice will affect the result of future reads.
|
// so immediate changes to the slice will affect the result of future reads.
|
||||||
func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }
|
func (b *Buffer) Bytes() []byte { return b.buf[b.off:] }
|
||||||
|
|
||||||
// AvailableBuffer returns an empty buffer with b.Available() capacity.
|
// AvailableBuffer returns an empty buffer with b.Available() capacity.
|
||||||
// This buffer is intended to be appended to and
|
// This buffer is intended to be appended to and
|
||||||
// passed to an immediately succeeding Write call.
|
// passed to an immediately succeeding [Buffer.Write] call.
|
||||||
// The buffer is only valid until the next write operation on b.
|
// The buffer is only valid until the next write operation on b.
|
||||||
func (b *Buffer) AvailableBuffer() []byte { return b.buf[len(b.buf):] }
|
func (b *Buffer) AvailableBuffer() []byte { return b.buf[len(b.buf):] }
|
||||||
|
|
||||||
// String returns the contents of the unread portion of the buffer
|
// String returns the contents of the unread portion of the buffer
|
||||||
// as a string. If the Buffer is a nil pointer, it returns "<nil>".
|
// as a string. If the [Buffer] is a nil pointer, it returns "<nil>".
|
||||||
//
|
//
|
||||||
// To build strings more efficiently, see the strings.Builder type.
|
// To build strings more efficiently, see the strings.Builder type.
|
||||||
func (b *Buffer) String() string {
|
func (b *Buffer) String() string {
|
||||||
@ -102,7 +102,7 @@ func (b *Buffer) Truncate(n int) {
|
|||||||
|
|
||||||
// Reset resets the buffer to be empty,
|
// Reset resets the buffer to be empty,
|
||||||
// but it retains the underlying storage for use by future writes.
|
// but it retains the underlying storage for use by future writes.
|
||||||
// Reset is the same as Truncate(0).
|
// Reset is the same as [Buffer.Truncate](0).
|
||||||
func (b *Buffer) Reset() {
|
func (b *Buffer) Reset() {
|
||||||
b.buf = b.buf[:0]
|
b.buf = b.buf[:0]
|
||||||
b.off = 0
|
b.off = 0
|
||||||
@ -160,7 +160,7 @@ func (b *Buffer) grow(n int) int {
|
|||||||
// another n bytes. After Grow(n), at least n bytes can be written to the
|
// another n bytes. After Grow(n), at least n bytes can be written to the
|
||||||
// buffer without another allocation.
|
// buffer without another allocation.
|
||||||
// If n is negative, Grow will panic.
|
// If n is negative, Grow will panic.
|
||||||
// If the buffer can't grow it will panic with ErrTooLarge.
|
// If the buffer can't grow it will panic with [ErrTooLarge].
|
||||||
func (b *Buffer) Grow(n int) {
|
func (b *Buffer) Grow(n int) {
|
||||||
if n < 0 {
|
if n < 0 {
|
||||||
panic("bytes.Buffer.Grow: negative count")
|
panic("bytes.Buffer.Grow: negative count")
|
||||||
@ -171,7 +171,7 @@ func (b *Buffer) Grow(n int) {
|
|||||||
|
|
||||||
// Write appends the contents of p to the buffer, growing the buffer as
|
// Write appends the contents of p to the buffer, growing the buffer as
|
||||||
// needed. The return value n is the length of p; err is always nil. If the
|
// needed. The return value n is the length of p; err is always nil. If the
|
||||||
// buffer becomes too large, Write will panic with ErrTooLarge.
|
// buffer becomes too large, Write will panic with [ErrTooLarge].
|
||||||
func (b *Buffer) Write(p []byte) (n int, err error) {
|
func (b *Buffer) Write(p []byte) (n int, err error) {
|
||||||
b.lastRead = opInvalid
|
b.lastRead = opInvalid
|
||||||
m, ok := b.tryGrowByReslice(len(p))
|
m, ok := b.tryGrowByReslice(len(p))
|
||||||
@ -183,7 +183,7 @@ func (b *Buffer) Write(p []byte) (n int, err error) {
|
|||||||
|
|
||||||
// WriteString appends the contents of s to the buffer, growing the buffer as
|
// WriteString appends the contents of s to the buffer, growing the buffer as
|
||||||
// needed. The return value n is the length of s; err is always nil. If the
|
// needed. The return value n is the length of s; err is always nil. If the
|
||||||
// buffer becomes too large, WriteString will panic with ErrTooLarge.
|
// buffer becomes too large, WriteString will panic with [ErrTooLarge].
|
||||||
func (b *Buffer) WriteString(s string) (n int, err error) {
|
func (b *Buffer) WriteString(s string) (n int, err error) {
|
||||||
b.lastRead = opInvalid
|
b.lastRead = opInvalid
|
||||||
m, ok := b.tryGrowByReslice(len(s))
|
m, ok := b.tryGrowByReslice(len(s))
|
||||||
@ -194,7 +194,7 @@ func (b *Buffer) WriteString(s string) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// MinRead is the minimum slice size passed to a Read call by
|
// MinRead is the minimum slice size passed to a Read call by
|
||||||
// Buffer.ReadFrom. As long as the Buffer has at least MinRead bytes beyond
|
// [Buffer.ReadFrom]. As long as the [Buffer] has at least MinRead bytes beyond
|
||||||
// what is required to hold the contents of r, ReadFrom will not grow the
|
// what is required to hold the contents of r, ReadFrom will not grow the
|
||||||
// underlying buffer.
|
// underlying buffer.
|
||||||
const MinRead = 512
|
const MinRead = 512
|
||||||
@ -202,7 +202,7 @@ const MinRead = 512
|
|||||||
// ReadFrom reads data from r until EOF and appends it to the buffer, growing
|
// ReadFrom reads data from r until EOF and appends it to the buffer, growing
|
||||||
// the buffer as needed. The return value n is the number of bytes read. Any
|
// the buffer as needed. The return value n is the number of bytes read. Any
|
||||||
// error except io.EOF encountered during the read is also returned. If the
|
// error except io.EOF encountered during the read is also returned. If the
|
||||||
// buffer becomes too large, ReadFrom will panic with ErrTooLarge.
|
// buffer becomes too large, ReadFrom will panic with [ErrTooLarge].
|
||||||
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
|
func (b *Buffer) ReadFrom(r io.Reader) (n int64, err error) {
|
||||||
b.lastRead = opInvalid
|
b.lastRead = opInvalid
|
||||||
for {
|
for {
|
||||||
@ -279,9 +279,9 @@ func (b *Buffer) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// WriteByte appends the byte c to the buffer, growing the buffer as needed.
|
// WriteByte appends the byte c to the buffer, growing the buffer as needed.
|
||||||
// The returned error is always nil, but is included to match bufio.Writer's
|
// The returned error is always nil, but is included to match [bufio.Writer]'s
|
||||||
// WriteByte. If the buffer becomes too large, WriteByte will panic with
|
// WriteByte. If the buffer becomes too large, WriteByte will panic with
|
||||||
// ErrTooLarge.
|
// [ErrTooLarge].
|
||||||
func (b *Buffer) WriteByte(c byte) error {
|
func (b *Buffer) WriteByte(c byte) error {
|
||||||
b.lastRead = opInvalid
|
b.lastRead = opInvalid
|
||||||
m, ok := b.tryGrowByReslice(1)
|
m, ok := b.tryGrowByReslice(1)
|
||||||
@ -294,8 +294,8 @@ func (b *Buffer) WriteByte(c byte) error {
|
|||||||
|
|
||||||
// WriteRune appends the UTF-8 encoding of Unicode code point r to the
|
// WriteRune appends the UTF-8 encoding of Unicode code point r to the
|
||||||
// buffer, returning its length and an error, which is always nil but is
|
// buffer, returning its length and an error, which is always nil but is
|
||||||
// included to match bufio.Writer's WriteRune. The buffer is grown as needed;
|
// included to match [bufio.Writer]'s WriteRune. The buffer is grown as needed;
|
||||||
// if it becomes too large, WriteRune will panic with ErrTooLarge.
|
// if it becomes too large, WriteRune will panic with [ErrTooLarge].
|
||||||
func (b *Buffer) WriteRune(r rune) (n int, err error) {
|
func (b *Buffer) WriteRune(r rune) (n int, err error) {
|
||||||
// Compare as uint32 to correctly handle negative runes.
|
// Compare as uint32 to correctly handle negative runes.
|
||||||
if uint32(r) < utf8.RuneSelf {
|
if uint32(r) < utf8.RuneSelf {
|
||||||
@ -334,7 +334,7 @@ func (b *Buffer) Read(p []byte) (n int, err error) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Next returns a slice containing the next n bytes from the buffer,
|
// Next returns a slice containing the next n bytes from the buffer,
|
||||||
// advancing the buffer as if the bytes had been returned by Read.
|
// advancing the buffer as if the bytes had been returned by [Buffer.Read].
|
||||||
// If there are fewer than n bytes in the buffer, Next returns the entire buffer.
|
// If there are fewer than n bytes in the buffer, Next returns the entire buffer.
|
||||||
// The slice is only valid until the next call to a read or write method.
|
// The slice is only valid until the next call to a read or write method.
|
||||||
func (b *Buffer) Next(n int) []byte {
|
func (b *Buffer) Next(n int) []byte {
|
||||||
@ -388,10 +388,10 @@ func (b *Buffer) ReadRune() (r rune, size int, err error) {
|
|||||||
return r, n, nil
|
return r, n, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnreadRune unreads the last rune returned by ReadRune.
|
// UnreadRune unreads the last rune returned by [Buffer.ReadRune].
|
||||||
// If the most recent read or write operation on the buffer was
|
// If the most recent read or write operation on the buffer was
|
||||||
// not a successful ReadRune, UnreadRune returns an error. (In this regard
|
// not a successful [Buffer.ReadRune], UnreadRune returns an error. (In this regard
|
||||||
// it is stricter than UnreadByte, which will unread the last byte
|
// it is stricter than [Buffer.UnreadByte], which will unread the last byte
|
||||||
// from any read operation.)
|
// from any read operation.)
|
||||||
func (b *Buffer) UnreadRune() error {
|
func (b *Buffer) UnreadRune() error {
|
||||||
if b.lastRead <= opInvalid {
|
if b.lastRead <= opInvalid {
|
||||||
@ -460,23 +460,23 @@ func (b *Buffer) ReadString(delim byte) (line string, err error) {
|
|||||||
return string(slice), err
|
return string(slice), err
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewBuffer creates and initializes a new Buffer using buf as its
|
// NewBuffer creates and initializes a new [Buffer] using buf as its
|
||||||
// initial contents. The new Buffer takes ownership of buf, and the
|
// initial contents. The new [Buffer] takes ownership of buf, and the
|
||||||
// caller should not use buf after this call. NewBuffer is intended to
|
// caller should not use buf after this call. NewBuffer is intended to
|
||||||
// prepare a Buffer to read existing data. It can also be used to set
|
// prepare a [Buffer] to read existing data. It can also be used to set
|
||||||
// the initial size of the internal buffer for writing. To do that,
|
// the initial size of the internal buffer for writing. To do that,
|
||||||
// buf should have the desired capacity but a length of zero.
|
// buf should have the desired capacity but a length of zero.
|
||||||
//
|
//
|
||||||
// In most cases, new(Buffer) (or just declaring a Buffer variable) is
|
// In most cases, new([Buffer]) (or just declaring a [Buffer] variable) is
|
||||||
// sufficient to initialize a Buffer.
|
// sufficient to initialize a [Buffer].
|
||||||
func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }
|
func NewBuffer(buf []byte) *Buffer { return &Buffer{buf: buf} }
|
||||||
|
|
||||||
// NewBufferString creates and initializes a new Buffer using string s as its
|
// NewBufferString creates and initializes a new [Buffer] using string s as its
|
||||||
// initial contents. It is intended to prepare a buffer to read an existing
|
// initial contents. It is intended to prepare a buffer to read an existing
|
||||||
// string.
|
// string.
|
||||||
//
|
//
|
||||||
// In most cases, new(Buffer) (or just declaring a Buffer variable) is
|
// In most cases, new([Buffer]) (or just declaring a [Buffer] variable) is
|
||||||
// sufficient to initialize a Buffer.
|
// sufficient to initialize a [Buffer].
|
||||||
func NewBufferString(s string) *Buffer {
|
func NewBufferString(s string) *Buffer {
|
||||||
return &Buffer{buf: []byte(s)}
|
return &Buffer{buf: []byte(s)}
|
||||||
}
|
}
|
||||||
|
@ -121,25 +121,7 @@ func LastIndex(s, sep []byte) int {
|
|||||||
case n > len(s):
|
case n > len(s):
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
// Rabin-Karp search from the end of the string
|
return bytealg.LastIndexRabinKarp(s, sep)
|
||||||
hashss, pow := bytealg.HashStrRevBytes(sep)
|
|
||||||
last := len(s) - n
|
|
||||||
var h uint32
|
|
||||||
for i := len(s) - 1; i >= last; i-- {
|
|
||||||
h = h*bytealg.PrimeRK + uint32(s[i])
|
|
||||||
}
|
|
||||||
if h == hashss && Equal(s[last:], sep) {
|
|
||||||
return last
|
|
||||||
}
|
|
||||||
for i := last - 1; i >= 0; i-- {
|
|
||||||
h *= bytealg.PrimeRK
|
|
||||||
h += uint32(s[i])
|
|
||||||
h -= pow * uint32(s[i+n])
|
|
||||||
if h == hashss && Equal(s[i:i+n], sep) {
|
|
||||||
return i
|
|
||||||
}
|
|
||||||
}
|
|
||||||
return -1
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s.
|
// LastIndexByte returns the index of the last instance of c in s, or -1 if c is not present in s.
|
||||||
@ -1331,7 +1313,7 @@ func Index(s, sep []byte) int {
|
|||||||
// we should cutover at even larger average skips,
|
// we should cutover at even larger average skips,
|
||||||
// because Equal becomes that much more expensive.
|
// because Equal becomes that much more expensive.
|
||||||
// This code does not take that effect into account.
|
// This code does not take that effect into account.
|
||||||
j := bytealg.IndexRabinKarpBytes(s[i:], sep)
|
j := bytealg.IndexRabinKarp(s[i:], sep)
|
||||||
if j < 0 {
|
if j < 0 {
|
||||||
return -1
|
return -1
|
||||||
}
|
}
|
||||||
|
@ -212,6 +212,17 @@ func ExampleContainsRune() {
|
|||||||
// false
|
// false
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func ExampleContainsFunc() {
|
||||||
|
f := func(r rune) bool {
|
||||||
|
return r >= 'a' && r <= 'z'
|
||||||
|
}
|
||||||
|
fmt.Println(bytes.ContainsFunc([]byte("HELLO"), f))
|
||||||
|
fmt.Println(bytes.ContainsFunc([]byte("World"), f))
|
||||||
|
// Output:
|
||||||
|
// false
|
||||||
|
// true
|
||||||
|
}
|
||||||
|
|
||||||
func ExampleCount() {
|
func ExampleCount() {
|
||||||
fmt.Println(bytes.Count([]byte("cheese"), []byte("e")))
|
fmt.Println(bytes.Count([]byte("cheese"), []byte("e")))
|
||||||
fmt.Println(bytes.Count([]byte("five"), []byte(""))) // before & after each rune
|
fmt.Println(bytes.Count([]byte("five"), []byte(""))) // before & after each rune
|
||||||
|
@ -13,7 +13,7 @@ import (
|
|||||||
// A Reader implements the io.Reader, io.ReaderAt, io.WriterTo, io.Seeker,
|
// A Reader implements the io.Reader, io.ReaderAt, io.WriterTo, io.Seeker,
|
||||||
// io.ByteScanner, and io.RuneScanner interfaces by reading from
|
// io.ByteScanner, and io.RuneScanner interfaces by reading from
|
||||||
// a byte slice.
|
// a byte slice.
|
||||||
// Unlike a Buffer, a Reader is read-only and supports seeking.
|
// Unlike a [Buffer], a Reader is read-only and supports seeking.
|
||||||
// The zero value for Reader operates like a Reader of an empty slice.
|
// The zero value for Reader operates like a Reader of an empty slice.
|
||||||
type Reader struct {
|
type Reader struct {
|
||||||
s []byte
|
s []byte
|
||||||
@ -31,11 +31,11 @@ func (r *Reader) Len() int {
|
|||||||
}
|
}
|
||||||
|
|
||||||
// Size returns the original length of the underlying byte slice.
|
// Size returns the original length of the underlying byte slice.
|
||||||
// Size is the number of bytes available for reading via ReadAt.
|
// Size is the number of bytes available for reading via [Reader.ReadAt].
|
||||||
// The result is unaffected by any method calls except Reset.
|
// The result is unaffected by any method calls except [Reader.Reset].
|
||||||
func (r *Reader) Size() int64 { return int64(len(r.s)) }
|
func (r *Reader) Size() int64 { return int64(len(r.s)) }
|
||||||
|
|
||||||
// Read implements the io.Reader interface.
|
// Read implements the [io.Reader] interface.
|
||||||
func (r *Reader) Read(b []byte) (n int, err error) {
|
func (r *Reader) Read(b []byte) (n int, err error) {
|
||||||
if r.i >= int64(len(r.s)) {
|
if r.i >= int64(len(r.s)) {
|
||||||
return 0, io.EOF
|
return 0, io.EOF
|
||||||
@ -46,7 +46,7 @@ func (r *Reader) Read(b []byte) (n int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadAt implements the io.ReaderAt interface.
|
// ReadAt implements the [io.ReaderAt] interface.
|
||||||
func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
|
func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
|
||||||
// cannot modify state - see io.ReaderAt
|
// cannot modify state - see io.ReaderAt
|
||||||
if off < 0 {
|
if off < 0 {
|
||||||
@ -62,7 +62,7 @@ func (r *Reader) ReadAt(b []byte, off int64) (n int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadByte implements the io.ByteReader interface.
|
// ReadByte implements the [io.ByteReader] interface.
|
||||||
func (r *Reader) ReadByte() (byte, error) {
|
func (r *Reader) ReadByte() (byte, error) {
|
||||||
r.prevRune = -1
|
r.prevRune = -1
|
||||||
if r.i >= int64(len(r.s)) {
|
if r.i >= int64(len(r.s)) {
|
||||||
@ -73,7 +73,7 @@ func (r *Reader) ReadByte() (byte, error) {
|
|||||||
return b, nil
|
return b, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnreadByte complements ReadByte in implementing the io.ByteScanner interface.
|
// UnreadByte complements [Reader.ReadByte] in implementing the [io.ByteScanner] interface.
|
||||||
func (r *Reader) UnreadByte() error {
|
func (r *Reader) UnreadByte() error {
|
||||||
if r.i <= 0 {
|
if r.i <= 0 {
|
||||||
return errors.New("bytes.Reader.UnreadByte: at beginning of slice")
|
return errors.New("bytes.Reader.UnreadByte: at beginning of slice")
|
||||||
@ -83,7 +83,7 @@ func (r *Reader) UnreadByte() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// ReadRune implements the io.RuneReader interface.
|
// ReadRune implements the [io.RuneReader] interface.
|
||||||
func (r *Reader) ReadRune() (ch rune, size int, err error) {
|
func (r *Reader) ReadRune() (ch rune, size int, err error) {
|
||||||
if r.i >= int64(len(r.s)) {
|
if r.i >= int64(len(r.s)) {
|
||||||
r.prevRune = -1
|
r.prevRune = -1
|
||||||
@ -99,7 +99,7 @@ func (r *Reader) ReadRune() (ch rune, size int, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// UnreadRune complements ReadRune in implementing the io.RuneScanner interface.
|
// UnreadRune complements [Reader.ReadRune] in implementing the [io.RuneScanner] interface.
|
||||||
func (r *Reader) UnreadRune() error {
|
func (r *Reader) UnreadRune() error {
|
||||||
if r.i <= 0 {
|
if r.i <= 0 {
|
||||||
return errors.New("bytes.Reader.UnreadRune: at beginning of slice")
|
return errors.New("bytes.Reader.UnreadRune: at beginning of slice")
|
||||||
@ -112,7 +112,7 @@ func (r *Reader) UnreadRune() error {
|
|||||||
return nil
|
return nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// Seek implements the io.Seeker interface.
|
// Seek implements the [io.Seeker] interface.
|
||||||
func (r *Reader) Seek(offset int64, whence int) (int64, error) {
|
func (r *Reader) Seek(offset int64, whence int) (int64, error) {
|
||||||
r.prevRune = -1
|
r.prevRune = -1
|
||||||
var abs int64
|
var abs int64
|
||||||
@ -133,7 +133,7 @@ func (r *Reader) Seek(offset int64, whence int) (int64, error) {
|
|||||||
return abs, nil
|
return abs, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
// WriteTo implements the io.WriterTo interface.
|
// WriteTo implements the [io.WriterTo] interface.
|
||||||
func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
|
func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
|
||||||
r.prevRune = -1
|
r.prevRune = -1
|
||||||
if r.i >= int64(len(r.s)) {
|
if r.i >= int64(len(r.s)) {
|
||||||
@ -152,8 +152,8 @@ func (r *Reader) WriteTo(w io.Writer) (n int64, err error) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// Reset resets the Reader to be reading from b.
|
// Reset resets the [Reader.Reader] to be reading from b.
|
||||||
func (r *Reader) Reset(b []byte) { *r = Reader{b, 0, -1} }
|
func (r *Reader) Reset(b []byte) { *r = Reader{b, 0, -1} }
|
||||||
|
|
||||||
// NewReader returns a new Reader reading from b.
|
// NewReader returns a new [Reader.Reader] reading from b.
|
||||||
func NewReader(b []byte) *Reader { return &Reader{b, 0, -1} }
|
func NewReader(b []byte) *Reader { return &Reader{b, 0, -1} }
|
||||||
|
@ -285,6 +285,25 @@ func TestIssue41358(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestIssue64958(t *testing.T) {
|
||||||
|
defer func() {
|
||||||
|
if x := recover(); x != nil {
|
||||||
|
t.Errorf("expected no panic; recovered %v", x)
|
||||||
|
}
|
||||||
|
}()
|
||||||
|
|
||||||
|
testenv.MustHaveGoBuild(t)
|
||||||
|
|
||||||
|
for _, context := range contexts {
|
||||||
|
w := NewWalker(context, "testdata/src/issue64958")
|
||||||
|
pkg, err := w.importFrom("p", "", 0)
|
||||||
|
if err != nil {
|
||||||
|
t.Errorf("expected no error importing; got %T", err)
|
||||||
|
}
|
||||||
|
w.export(pkg)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
func TestCheck(t *testing.T) {
|
func TestCheck(t *testing.T) {
|
||||||
if !*flagCheck {
|
if !*flagCheck {
|
||||||
t.Skip("-check not specified")
|
t.Skip("-check not specified")
|
||||||
|
@ -106,7 +106,7 @@ func Check(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
var nextFiles []string
|
var nextFiles []string
|
||||||
if strings.Contains(runtime.Version(), "devel") {
|
if v := runtime.Version(); strings.Contains(v, "devel") || strings.Contains(v, "beta") {
|
||||||
next, err := filepath.Glob(filepath.Join(testenv.GOROOT(t), "api/next/*.txt"))
|
next, err := filepath.Glob(filepath.Join(testenv.GOROOT(t), "api/next/*.txt"))
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
@ -957,17 +957,17 @@ func (w *Walker) emitType(obj *types.TypeName) {
|
|||||||
if w.isDeprecated(obj) {
|
if w.isDeprecated(obj) {
|
||||||
w.emitf("type %s //deprecated", name)
|
w.emitf("type %s //deprecated", name)
|
||||||
}
|
}
|
||||||
|
typ := obj.Type()
|
||||||
|
if obj.IsAlias() {
|
||||||
|
w.emitf("type %s = %s", name, w.typeString(typ))
|
||||||
|
return
|
||||||
|
}
|
||||||
if tparams := obj.Type().(*types.Named).TypeParams(); tparams != nil {
|
if tparams := obj.Type().(*types.Named).TypeParams(); tparams != nil {
|
||||||
var buf bytes.Buffer
|
var buf bytes.Buffer
|
||||||
buf.WriteString(name)
|
buf.WriteString(name)
|
||||||
w.writeTypeParams(&buf, tparams, true)
|
w.writeTypeParams(&buf, tparams, true)
|
||||||
name = buf.String()
|
name = buf.String()
|
||||||
}
|
}
|
||||||
typ := obj.Type()
|
|
||||||
if obj.IsAlias() {
|
|
||||||
w.emitf("type %s = %s", name, w.typeString(typ))
|
|
||||||
return
|
|
||||||
}
|
|
||||||
switch typ := typ.Underlying().(type) {
|
switch typ := typ.Underlying().(type) {
|
||||||
case *types.Struct:
|
case *types.Struct:
|
||||||
w.emitStructType(name, typ)
|
w.emitStructType(name, typ)
|
||||||
|
3
src/cmd/api/testdata/src/issue64958/p/p.go
vendored
Normal file
3
src/cmd/api/testdata/src/issue64958/p/p.go
vendored
Normal file
@ -0,0 +1,3 @@
|
|||||||
|
package p
|
||||||
|
|
||||||
|
type BasicAlias = uint8
|
@ -141,11 +141,17 @@ Diff:
|
|||||||
// Turn relative (PC) into absolute (PC) automatically,
|
// Turn relative (PC) into absolute (PC) automatically,
|
||||||
// so that most branch instructions don't need comments
|
// so that most branch instructions don't need comments
|
||||||
// giving the absolute form.
|
// giving the absolute form.
|
||||||
if len(f) > 0 && strings.HasSuffix(printed, "(PC)") {
|
if len(f) > 0 && strings.Contains(printed, "(PC)") {
|
||||||
last := f[len(f)-1]
|
index := len(f) - 1
|
||||||
n, err := strconv.Atoi(last[:len(last)-len("(PC)")])
|
suf := "(PC)"
|
||||||
|
for !strings.HasSuffix(f[index], suf) {
|
||||||
|
index--
|
||||||
|
suf = "(PC),"
|
||||||
|
}
|
||||||
|
str := f[index]
|
||||||
|
n, err := strconv.Atoi(str[:len(str)-len(suf)])
|
||||||
if err == nil {
|
if err == nil {
|
||||||
f[len(f)-1] = fmt.Sprintf("%d(PC)", seq+n)
|
f[index] = fmt.Sprintf("%d%s", seq+n, suf)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -372,10 +378,10 @@ func Test386EndToEnd(t *testing.T) {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func TestARMEndToEnd(t *testing.T) {
|
func TestARMEndToEnd(t *testing.T) {
|
||||||
defer func(old int) { buildcfg.GOARM = old }(buildcfg.GOARM)
|
defer func(old int) { buildcfg.GOARM.Version = old }(buildcfg.GOARM.Version)
|
||||||
for _, goarm := range []int{5, 6, 7} {
|
for _, goarm := range []int{5, 6, 7} {
|
||||||
t.Logf("GOARM=%d", goarm)
|
t.Logf("GOARM=%d", goarm)
|
||||||
buildcfg.GOARM = goarm
|
buildcfg.GOARM.Version = goarm
|
||||||
testEndToEnd(t, "arm", "arm")
|
testEndToEnd(t, "arm", "arm")
|
||||||
if goarm == 6 {
|
if goarm == 6 {
|
||||||
testEndToEnd(t, "arm", "armv6")
|
testEndToEnd(t, "arm", "armv6")
|
||||||
|
22
src/cmd/asm/internal/asm/testdata/arm.s
vendored
22
src/cmd/asm/internal/asm/testdata/arm.s
vendored
@ -870,10 +870,13 @@ jmp_label_3:
|
|||||||
BIC.S R0@>R1, R2 // 7021d2e1
|
BIC.S R0@>R1, R2 // 7021d2e1
|
||||||
|
|
||||||
// SRL
|
// SRL
|
||||||
|
SRL $0, R5, R6 // 0560a0e1
|
||||||
|
SRL $1, R5, R6 // a560a0e1
|
||||||
SRL $14, R5, R6 // 2567a0e1
|
SRL $14, R5, R6 // 2567a0e1
|
||||||
SRL $15, R5, R6 // a567a0e1
|
SRL $15, R5, R6 // a567a0e1
|
||||||
SRL $30, R5, R6 // 256fa0e1
|
SRL $30, R5, R6 // 256fa0e1
|
||||||
SRL $31, R5, R6 // a56fa0e1
|
SRL $31, R5, R6 // a56fa0e1
|
||||||
|
SRL $32, R5, R6 // 2560a0e1
|
||||||
SRL.S $14, R5, R6 // 2567b0e1
|
SRL.S $14, R5, R6 // 2567b0e1
|
||||||
SRL.S $15, R5, R6 // a567b0e1
|
SRL.S $15, R5, R6 // a567b0e1
|
||||||
SRL.S $30, R5, R6 // 256fb0e1
|
SRL.S $30, R5, R6 // 256fb0e1
|
||||||
@ -892,10 +895,13 @@ jmp_label_3:
|
|||||||
SRL.S R5, R7 // 3775b0e1
|
SRL.S R5, R7 // 3775b0e1
|
||||||
|
|
||||||
// SRA
|
// SRA
|
||||||
|
SRA $0, R5, R6 // 0560a0e1
|
||||||
|
SRA $1, R5, R6 // c560a0e1
|
||||||
SRA $14, R5, R6 // 4567a0e1
|
SRA $14, R5, R6 // 4567a0e1
|
||||||
SRA $15, R5, R6 // c567a0e1
|
SRA $15, R5, R6 // c567a0e1
|
||||||
SRA $30, R5, R6 // 456fa0e1
|
SRA $30, R5, R6 // 456fa0e1
|
||||||
SRA $31, R5, R6 // c56fa0e1
|
SRA $31, R5, R6 // c56fa0e1
|
||||||
|
SRA $32, R5, R6 // 4560a0e1
|
||||||
SRA.S $14, R5, R6 // 4567b0e1
|
SRA.S $14, R5, R6 // 4567b0e1
|
||||||
SRA.S $15, R5, R6 // c567b0e1
|
SRA.S $15, R5, R6 // c567b0e1
|
||||||
SRA.S $30, R5, R6 // 456fb0e1
|
SRA.S $30, R5, R6 // 456fb0e1
|
||||||
@ -914,6 +920,8 @@ jmp_label_3:
|
|||||||
SRA.S R5, R7 // 5775b0e1
|
SRA.S R5, R7 // 5775b0e1
|
||||||
|
|
||||||
// SLL
|
// SLL
|
||||||
|
SLL $0, R5, R6 // 0560a0e1
|
||||||
|
SLL $1, R5, R6 // 8560a0e1
|
||||||
SLL $14, R5, R6 // 0567a0e1
|
SLL $14, R5, R6 // 0567a0e1
|
||||||
SLL $15, R5, R6 // 8567a0e1
|
SLL $15, R5, R6 // 8567a0e1
|
||||||
SLL $30, R5, R6 // 056fa0e1
|
SLL $30, R5, R6 // 056fa0e1
|
||||||
@ -935,6 +943,20 @@ jmp_label_3:
|
|||||||
SLL R5, R7 // 1775a0e1
|
SLL R5, R7 // 1775a0e1
|
||||||
SLL.S R5, R7 // 1775b0e1
|
SLL.S R5, R7 // 1775b0e1
|
||||||
|
|
||||||
|
// Ops with zero shifts should encode as left shifts
|
||||||
|
ADD R0<<0, R1, R2 // 002081e0
|
||||||
|
ADD R0>>0, R1, R2 // 002081e0
|
||||||
|
ADD R0->0, R1, R2 // 002081e0
|
||||||
|
ADD R0@>0, R1, R2 // 002081e0
|
||||||
|
MOVW R0<<0(R1), R2 // 002091e7
|
||||||
|
MOVW R0>>0(R1), R2 // 002091e7
|
||||||
|
MOVW R0->0(R1), R2 // 002091e7
|
||||||
|
MOVW R0@>0(R1), R2 // 002091e7
|
||||||
|
MOVW R0, R1<<0(R2) // 010082e7
|
||||||
|
MOVW R0, R1>>0(R2) // 010082e7
|
||||||
|
MOVW R0, R1->0(R2) // 010082e7
|
||||||
|
MOVW R0, R1@>0(R2) // 010082e7
|
||||||
|
|
||||||
// MULA / MULS
|
// MULA / MULS
|
||||||
MULAWT R1, R2, R3, R4 // c23124e1
|
MULAWT R1, R2, R3, R4 // c23124e1
|
||||||
MULAWB R1, R2, R3, R4 // 823124e1
|
MULAWB R1, R2, R3, R4 // 823124e1
|
||||||
|
11
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
11
src/cmd/asm/internal/asm/testdata/arm64.s
vendored
@ -981,6 +981,14 @@ again:
|
|||||||
ADR next, R11 // ADR R11 // 2b000010
|
ADR next, R11 // ADR R11 // 2b000010
|
||||||
next:
|
next:
|
||||||
NOP
|
NOP
|
||||||
|
ADR -2(PC), R10 // 0a000010
|
||||||
|
ADR 2(PC), R16 // 10000010
|
||||||
|
ADR -26(PC), R1 // 01000010
|
||||||
|
ADR 12(PC), R2 // 02000010
|
||||||
|
ADRP -2(PC), R10 // 0a000090
|
||||||
|
ADRP 2(PC), R16 // 10000090
|
||||||
|
ADRP -26(PC), R1 // 01000090
|
||||||
|
ADRP 12(PC), R2 // 02000090
|
||||||
|
|
||||||
// LDP/STP
|
// LDP/STP
|
||||||
LDP (R0), (R0, R1) // 000440a9
|
LDP (R0), (R0, R1) // 000440a9
|
||||||
@ -1003,6 +1011,7 @@ next:
|
|||||||
LDP -8(R0), (R1, R2) // 01887fa9
|
LDP -8(R0), (R1, R2) // 01887fa9
|
||||||
LDP x(SB), (R1, R2)
|
LDP x(SB), (R1, R2)
|
||||||
LDP x+8(SB), (R1, R2)
|
LDP x+8(SB), (R1, R2)
|
||||||
|
LDP 8(R1), (ZR, R2) // 3f8840a9
|
||||||
LDPW -5(R0), (R1, R2) // 1b1400d1610b4029
|
LDPW -5(R0), (R1, R2) // 1b1400d1610b4029
|
||||||
LDPW (R0), (R1, R2) // 01084029
|
LDPW (R0), (R1, R2) // 01084029
|
||||||
LDPW 4(R0), (R1, R2) // 01884029
|
LDPW 4(R0), (R1, R2) // 01884029
|
||||||
@ -1020,6 +1029,7 @@ next:
|
|||||||
LDPW 1024(RSP), (R1, R2) // fb031091610b4029
|
LDPW 1024(RSP), (R1, R2) // fb031091610b4029
|
||||||
LDPW x(SB), (R1, R2)
|
LDPW x(SB), (R1, R2)
|
||||||
LDPW x+8(SB), (R1, R2)
|
LDPW x+8(SB), (R1, R2)
|
||||||
|
LDPW 8(R1), (ZR, R2) // 3f084129
|
||||||
LDPSW (R0), (R1, R2) // 01084069
|
LDPSW (R0), (R1, R2) // 01084069
|
||||||
LDPSW 4(R0), (R1, R2) // 01884069
|
LDPSW 4(R0), (R1, R2) // 01884069
|
||||||
LDPSW -4(R0), (R1, R2) // 01887f69
|
LDPSW -4(R0), (R1, R2) // 01887f69
|
||||||
@ -1036,6 +1046,7 @@ next:
|
|||||||
LDPSW 1024(RSP), (R1, R2) // fb031091610b4069
|
LDPSW 1024(RSP), (R1, R2) // fb031091610b4069
|
||||||
LDPSW x(SB), (R1, R2)
|
LDPSW x(SB), (R1, R2)
|
||||||
LDPSW x+8(SB), (R1, R2)
|
LDPSW x+8(SB), (R1, R2)
|
||||||
|
LDPSW 8(R1), (ZR, R2) // 3f084169
|
||||||
STP (R3, R4), (R5) // a31000a9
|
STP (R3, R4), (R5) // a31000a9
|
||||||
STP (R3, R4), 8(R5) // a39000a9
|
STP (R3, R4), 8(R5) // a39000a9
|
||||||
STP.W (R3, R4), 8(R5) // a39080a9
|
STP.W (R3, R4), 8(R5) // a39080a9
|
||||||
|
@ -66,7 +66,6 @@ TEXT errors(SB),$0
|
|||||||
LDP.W 8(R3), (R2, R3) // ERROR "constrained unpredictable behavior"
|
LDP.W 8(R3), (R2, R3) // ERROR "constrained unpredictable behavior"
|
||||||
LDP (R1), (R2, R2) // ERROR "constrained unpredictable behavior"
|
LDP (R1), (R2, R2) // ERROR "constrained unpredictable behavior"
|
||||||
LDP (R0), (F0, F1) // ERROR "invalid register pair"
|
LDP (R0), (F0, F1) // ERROR "invalid register pair"
|
||||||
LDP (R0), (R3, ZR) // ERROR "invalid register pair"
|
|
||||||
LDXPW (RSP), (R2, R2) // ERROR "constrained unpredictable behavior"
|
LDXPW (RSP), (R2, R2) // ERROR "constrained unpredictable behavior"
|
||||||
LDAXPW (R5), (R2, R2) // ERROR "constrained unpredictable behavior"
|
LDAXPW (R5), (R2, R2) // ERROR "constrained unpredictable behavior"
|
||||||
MOVD.P 300(R2), R3 // ERROR "offset out of range [-256,255]"
|
MOVD.P 300(R2), R3 // ERROR "offset out of range [-256,255]"
|
||||||
|
49
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
49
src/cmd/asm/internal/asm/testdata/ppc64.s
vendored
@ -17,14 +17,14 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
|||||||
MOVD $1, R3 // 38600001
|
MOVD $1, R3 // 38600001
|
||||||
MOVD $-1, R4 // 3880ffff
|
MOVD $-1, R4 // 3880ffff
|
||||||
MOVD $65535, R5 // 6005ffff
|
MOVD $65535, R5 // 6005ffff
|
||||||
MOVD $65536, R6 // 64060001
|
MOVD $65536, R6 // 3cc00001
|
||||||
MOVD $-32767, R5 // 38a08001
|
MOVD $-32767, R5 // 38a08001
|
||||||
MOVD $-32768, R6 // 38c08000
|
MOVD $-32768, R6 // 38c08000
|
||||||
MOVD $1234567, R5 // 6405001260a5d687 or 0600001238a0d687
|
MOVD $1234567, R5 // 6405001260a5d687 or 0600001238a0d687
|
||||||
MOVW $1, R3 // 38600001
|
MOVW $1, R3 // 38600001
|
||||||
MOVW $-1, R4 // 3880ffff
|
MOVW $-1, R4 // 3880ffff
|
||||||
MOVW $65535, R5 // 6005ffff
|
MOVW $65535, R5 // 6005ffff
|
||||||
MOVW $65536, R6 // 64060001
|
MOVW $65536, R6 // 3cc00001
|
||||||
MOVW $-32767, R5 // 38a08001
|
MOVW $-32767, R5 // 38a08001
|
||||||
MOVW $-32768, R6 // 38c08000
|
MOVW $-32768, R6 // 38c08000
|
||||||
MOVW $1234567, R5 // 6405001260a5d687 or 0600001238a0d687
|
MOVW $1234567, R5 // 6405001260a5d687 or 0600001238a0d687
|
||||||
@ -33,6 +33,25 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
|||||||
MOVD $2147483649, R5 // 6405800060a50001 or 0600800038a00001
|
MOVD $2147483649, R5 // 6405800060a50001 or 0600800038a00001
|
||||||
// Hex constant 0xFFFFFFFF80000001
|
// Hex constant 0xFFFFFFFF80000001
|
||||||
MOVD $-2147483647, R5 // 3ca0800060a50001 or 0603800038a00001
|
MOVD $-2147483647, R5 // 3ca0800060a50001 or 0603800038a00001
|
||||||
|
// Hex constant 0xFFFFFFFE00000002 (load of constant on < power10, pli on >= power10
|
||||||
|
MOVD $-8589934590, R5 // 3ca00000e8a50000 or 0602000038a00002
|
||||||
|
|
||||||
|
// For backwards compatibility, MOVW $const,Rx and MOVWZ $const,Rx assemble identically
|
||||||
|
// and accept the same constants.
|
||||||
|
MOVW $2147483648, R5 // 64058000
|
||||||
|
MOVWZ $-2147483648, R5 // 3ca08000
|
||||||
|
|
||||||
|
// TODO: These are preprocessed by the assembler into MOVD $const>>shift, R5; SLD $shift, R5.
|
||||||
|
// This only captures the MOVD. Should the SLD be appended to the encoding by the test?
|
||||||
|
// Hex constant 0x20004000000
|
||||||
|
MOVD $2199090364416, R5 // 60058001
|
||||||
|
// Hex constant 0xFFFFFE0004000000
|
||||||
|
MOVD $-2198956146688, R5 // 38a08001
|
||||||
|
// TODO: On GOPPC64={power8,power9}, this is preprocessed into MOVD $-1, R5; RLDC R5, $33, $63, R5.
|
||||||
|
// This only captures the MOVD. Should the RLDC be appended to the encoding by the test?
|
||||||
|
// Hex constant 0xFFFFFFFE00000001
|
||||||
|
MOVD $-8589934591, R5 // 38a0ffff or 0602000038a00001
|
||||||
|
|
||||||
MOVD 8(R3), R4 // e8830008
|
MOVD 8(R3), R4 // e8830008
|
||||||
MOVD (R3)(R4), R5 // 7ca4182a
|
MOVD (R3)(R4), R5 // 7ca4182a
|
||||||
MOVD (R3)(R0), R5 // 7ca0182a
|
MOVD (R3)(R0), R5 // 7ca0182a
|
||||||
@ -164,6 +183,10 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
|||||||
ADD $-32767, R5, R4 // 38858001
|
ADD $-32767, R5, R4 // 38858001
|
||||||
ADD $-32768, R6 // 38c68000
|
ADD $-32768, R6 // 38c68000
|
||||||
ADD $-32768, R6, R5 // 38a68000
|
ADD $-32768, R6, R5 // 38a68000
|
||||||
|
// Hex constant 0xFFFFFFFE00000000
|
||||||
|
ADD $-8589934592, R5 // 3fe0fffe600000007bff83e4600000007cbf2a14 or 0602000038a50000
|
||||||
|
// Hex constant 0xFFFFFFFE00010001
|
||||||
|
ADD $-8589869055, R5 // 3fe0fffe63ff00017bff83e463ff00017cbf2a14 or 0602000138a50001
|
||||||
|
|
||||||
//TODO: this compiles to add r5,r6,r0. It should be addi r5,r6,0.
|
//TODO: this compiles to add r5,r6,r0. It should be addi r5,r6,0.
|
||||||
// this is OK since r0 == $0, but the latter is preferred.
|
// this is OK since r0 == $0, but the latter is preferred.
|
||||||
@ -174,6 +197,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
|||||||
ADDEX R3, R5, $3, R6 // 7cc32f54
|
ADDEX R3, R5, $3, R6 // 7cc32f54
|
||||||
ADDEX R3, $3, R5, R6 // 7cc32f54
|
ADDEX R3, $3, R5, R6 // 7cc32f54
|
||||||
ADDIS $8, R3 // 3c630008
|
ADDIS $8, R3 // 3c630008
|
||||||
|
ADD $524288, R3 // 3c630008
|
||||||
ADDIS $1000, R3, R4 // 3c8303e8
|
ADDIS $1000, R3, R4 // 3c8303e8
|
||||||
|
|
||||||
ANDCC $1, R3 // 70630001
|
ANDCC $1, R3 // 70630001
|
||||||
@ -192,6 +216,7 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
|||||||
ANDCC $1234567, R5, R6 // 641f001263ffd6877fe62839
|
ANDCC $1234567, R5, R6 // 641f001263ffd6877fe62839
|
||||||
ANDISCC $1, R3 // 74630001
|
ANDISCC $1, R3 // 74630001
|
||||||
ANDISCC $1000, R3, R4 // 746403e8
|
ANDISCC $1000, R3, R4 // 746403e8
|
||||||
|
ANDCC $65536000, R3, R4 // 746403e8
|
||||||
|
|
||||||
OR $1, R3 // 60630001
|
OR $1, R3 // 60630001
|
||||||
OR $1, R3, R4 // 60640001
|
OR $1, R3, R4 // 60640001
|
||||||
@ -207,7 +232,10 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
|||||||
OR $-32768, R6, R7 // 3be080007fe73378
|
OR $-32768, R6, R7 // 3be080007fe73378
|
||||||
OR $1234567, R5 // 641f001263ffd6877fe52b78
|
OR $1234567, R5 // 641f001263ffd6877fe52b78
|
||||||
OR $1234567, R5, R3 // 641f001263ffd6877fe32b78
|
OR $1234567, R5, R3 // 641f001263ffd6877fe32b78
|
||||||
ORIS $255, R3, R4
|
OR $2147483648, R5, R3 // 64a38000
|
||||||
|
OR $2147483649, R5, R3 // 641f800063ff00017fe32b78
|
||||||
|
ORIS $255, R3, R4 // 646400ff
|
||||||
|
OR $16711680, R3, R4 // 646400ff
|
||||||
|
|
||||||
XOR $1, R3 // 68630001
|
XOR $1, R3 // 68630001
|
||||||
XOR $1, R3, R4 // 68640001
|
XOR $1, R3, R4 // 68640001
|
||||||
@ -223,7 +251,8 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
|||||||
XOR $-32768, R6, R7 // 3be080007fe73278
|
XOR $-32768, R6, R7 // 3be080007fe73278
|
||||||
XOR $1234567, R5 // 641f001263ffd6877fe52a78
|
XOR $1234567, R5 // 641f001263ffd6877fe52a78
|
||||||
XOR $1234567, R5, R3 // 641f001263ffd6877fe32a78
|
XOR $1234567, R5, R3 // 641f001263ffd6877fe32a78
|
||||||
XORIS $15, R3, R4
|
XORIS $15, R3, R4 // 6c64000f
|
||||||
|
XOR $983040, R3, R4 // 6c64000f
|
||||||
|
|
||||||
// TODO: the order of CR operands don't match
|
// TODO: the order of CR operands don't match
|
||||||
CMP R3, R4 // 7c232000
|
CMP R3, R4 // 7c232000
|
||||||
@ -233,7 +262,6 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
|||||||
CMPB R3,R4,R4 // 7c6423f8
|
CMPB R3,R4,R4 // 7c6423f8
|
||||||
CMPEQB R3,R4,CR6 // 7f0321c0
|
CMPEQB R3,R4,CR6 // 7f0321c0
|
||||||
|
|
||||||
// TODO: constants for ADDC?
|
|
||||||
ADD R3, R4 // 7c841a14
|
ADD R3, R4 // 7c841a14
|
||||||
ADD R3, R4, R5 // 7ca41a14
|
ADD R3, R4, R5 // 7ca41a14
|
||||||
ADDC R3, R4 // 7c841814
|
ADDC R3, R4 // 7c841814
|
||||||
@ -246,6 +274,8 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
|||||||
ADDV R3, R4 // 7c841e14
|
ADDV R3, R4 // 7c841e14
|
||||||
ADDVCC R3, R4 // 7c841e15
|
ADDVCC R3, R4 // 7c841e15
|
||||||
ADDCCC R3, R4, R5 // 7ca41815
|
ADDCCC R3, R4, R5 // 7ca41815
|
||||||
|
ADDCCC $65536, R4, R5 // 641f0001600000007cbf2015
|
||||||
|
ADDCCC $65537, R4, R5 // 641f000163ff00017cbf2015
|
||||||
ADDME R3, R4 // 7c8301d4
|
ADDME R3, R4 // 7c8301d4
|
||||||
ADDMECC R3, R4 // 7c8301d5
|
ADDMECC R3, R4 // 7c8301d5
|
||||||
ADDMEV R3, R4 // 7c8305d4
|
ADDMEV R3, R4 // 7c8305d4
|
||||||
@ -299,6 +329,8 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
|||||||
SUBECC R3, R4, R5 // 7ca32111
|
SUBECC R3, R4, R5 // 7ca32111
|
||||||
SUBEV R3, R4, R5 // 7ca32510
|
SUBEV R3, R4, R5 // 7ca32510
|
||||||
SUBEVCC R3, R4, R5 // 7ca32511
|
SUBEVCC R3, R4, R5 // 7ca32511
|
||||||
|
SUBC R3, $65536, R4 // 3fe00001600000007c83f810
|
||||||
|
SUBC R3, $65537, R4 // 3fe0000163ff00017c83f810
|
||||||
|
|
||||||
MULLW R3, R4 // 7c8419d6
|
MULLW R3, R4 // 7c8419d6
|
||||||
MULLW R3, R4, R5 // 7ca419d6
|
MULLW R3, R4, R5 // 7ca419d6
|
||||||
@ -393,6 +425,9 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
|||||||
EXTSHCC R3, R4 // 7c640735
|
EXTSHCC R3, R4 // 7c640735
|
||||||
EXTSW R3, R4 // 7c6407b4
|
EXTSW R3, R4 // 7c6407b4
|
||||||
EXTSWCC R3, R4 // 7c6407b5
|
EXTSWCC R3, R4 // 7c6407b5
|
||||||
|
RLWMI $7, R3, $4026531855, R6 // 50663f06
|
||||||
|
RLWMI $7, R3, $1, R6 // 50663ffe
|
||||||
|
RLWMI $7, R3, $2147483648, R6 // 50663800
|
||||||
RLWMI $7, R3, $65535, R6 // 50663c3e
|
RLWMI $7, R3, $65535, R6 // 50663c3e
|
||||||
RLWMI $7, R3, $16, $31, R6 // 50663c3e
|
RLWMI $7, R3, $16, $31, R6 // 50663c3e
|
||||||
RLWMICC $7, R3, $65535, R6 // 50663c3f
|
RLWMICC $7, R3, $65535, R6 // 50663c3f
|
||||||
@ -414,6 +449,10 @@ TEXT asmtest(SB),DUPOK|NOSPLIT,$0
|
|||||||
RLDIMI $0, R4, $7, R6 // 788601cc
|
RLDIMI $0, R4, $7, R6 // 788601cc
|
||||||
RLDIMICC $0, R4, $7, R6 // 788601cd
|
RLDIMICC $0, R4, $7, R6 // 788601cd
|
||||||
RLDC $0, R4, $15, R6 // 78860728
|
RLDC $0, R4, $15, R6 // 78860728
|
||||||
|
RLDC R3, $32, $12, R4 // 7864030a
|
||||||
|
RLDC R3, $8, $32, R4 // 78644028
|
||||||
|
RLDCCC R3, $32, $12, R4 // 7864030b
|
||||||
|
RLDCCC R3, $8, $32, R4 // 78644029
|
||||||
RLDCCC $0, R4, $15, R6 // 78860729
|
RLDCCC $0, R4, $15, R6 // 78860729
|
||||||
RLDCL $0, R4, $7, R6 // 78860770
|
RLDCL $0, R4, $7, R6 // 78860770
|
||||||
RLDCLCC $0, R4, $15, R6 // 78860721
|
RLDCLCC $0, R4, $15, R6 // 78860721
|
||||||
|
5
src/cmd/asm/internal/asm/testdata/riscv64.s
vendored
5
src/cmd/asm/internal/asm/testdata/riscv64.s
vendored
@ -94,6 +94,10 @@ start:
|
|||||||
|
|
||||||
SUB X6, X5, X7 // b3836240
|
SUB X6, X5, X7 // b3836240
|
||||||
SUB X5, X6 // 33035340
|
SUB X5, X6 // 33035340
|
||||||
|
SUB $-2047, X5, X6 // 1383f27f
|
||||||
|
SUB $2048, X5, X6 // 13830280
|
||||||
|
SUB $-2047, X5 // 9382f27f
|
||||||
|
SUB $2048, X5 // 93820280
|
||||||
|
|
||||||
SRA X6, X5, X7 // b3d36240
|
SRA X6, X5, X7 // b3d36240
|
||||||
SRA X5, X6 // 33535340
|
SRA X5, X6 // 33535340
|
||||||
@ -157,6 +161,7 @@ start:
|
|||||||
ADDW $1, X6 // 1b031300
|
ADDW $1, X6 // 1b031300
|
||||||
SLLW $1, X6 // 1b131300
|
SLLW $1, X6 // 1b131300
|
||||||
SRLW $1, X6 // 1b531300
|
SRLW $1, X6 // 1b531300
|
||||||
|
SUBW $1, X6 // 1b03f3ff
|
||||||
SRAW $1, X6 // 1b531340
|
SRAW $1, X6 // 1b531340
|
||||||
|
|
||||||
// 5.3: Load and Store Instructions (RV64I)
|
// 5.3: Load and Store Instructions (RV64I)
|
||||||
|
@ -38,5 +38,8 @@ TEXT errors(SB),$0
|
|||||||
SLLIW $-1, X5, X6 // ERROR "shift amount out of range 0 to 31"
|
SLLIW $-1, X5, X6 // ERROR "shift amount out of range 0 to 31"
|
||||||
SRLIW $-1, X5, X6 // ERROR "shift amount out of range 0 to 31"
|
SRLIW $-1, X5, X6 // ERROR "shift amount out of range 0 to 31"
|
||||||
SRAIW $-1, X5, X6 // ERROR "shift amount out of range 0 to 31"
|
SRAIW $-1, X5, X6 // ERROR "shift amount out of range 0 to 31"
|
||||||
|
SD X5, 4294967296(X6) // ERROR "constant 4294967296 too large"
|
||||||
|
SRLI $1, X5, F1 // ERROR "expected integer register in rd position but got non-integer register F1"
|
||||||
|
SRLI $1, F1, X5 // ERROR "expected integer register in rs1 position but got non-integer register F1"
|
||||||
|
FNES F1, (X5) // ERROR "needs an integer register output"
|
||||||
RET
|
RET
|
||||||
|
4
src/cmd/asm/internal/asm/testdata/s390x.s
vendored
4
src/cmd/asm/internal/asm/testdata/s390x.s
vendored
@ -420,8 +420,8 @@ TEXT main·foo(SB),DUPOK|NOSPLIT,$16-0 // TEXT main.foo(SB), DUPOK|NOSPLIT, $16-
|
|||||||
KLMD R2, R8 // b93f0028
|
KLMD R2, R8 // b93f0028
|
||||||
KIMD R0, R4 // b93e0004
|
KIMD R0, R4 // b93e0004
|
||||||
KDSA R0, R8 // b93a0008
|
KDSA R0, R8 // b93a0008
|
||||||
KMA R6, R2, R4 // b9296024
|
KMA R2, R6, R4 // b9296024
|
||||||
KMCTR R6, R2, R4 // b92d6024
|
KMCTR R2, R6, R4 // b92d6024
|
||||||
|
|
||||||
// vector add and sub instructions
|
// vector add and sub instructions
|
||||||
VAB V3, V4, V4 // e743400000f3
|
VAB V3, V4, V4 // e743400000f3
|
||||||
|
@ -420,30 +420,6 @@ passing uninitialized C memory to Go code if the Go code is going to
|
|||||||
store pointer values in it. Zero out the memory in C before passing it
|
store pointer values in it. Zero out the memory in C before passing it
|
||||||
to Go.
|
to Go.
|
||||||
|
|
||||||
# Optimizing calls of C code
|
|
||||||
|
|
||||||
When passing a Go pointer to a C function the compiler normally ensures
|
|
||||||
that the Go object lives on the heap. If the C function does not keep
|
|
||||||
a copy of the Go pointer, and never passes the Go pointer back to Go code,
|
|
||||||
then this is unnecessary. The #cgo noescape directive may be used to tell
|
|
||||||
the compiler that no Go pointers escape via the named C function.
|
|
||||||
If the noescape directive is used and the C function does not handle the
|
|
||||||
pointer safely, the program may crash or see memory corruption.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
// #cgo noescape cFunctionName
|
|
||||||
|
|
||||||
When a Go function calls a C function, it prepares for the C function to
|
|
||||||
call back to a Go function. the #cgo nocallback directive may be used to
|
|
||||||
tell the compiler that these preparations are not necessary.
|
|
||||||
If the nocallback directive is used and the C function does call back into
|
|
||||||
Go code, the program will panic.
|
|
||||||
|
|
||||||
For example:
|
|
||||||
|
|
||||||
// #cgo nocallback cFunctionName
|
|
||||||
|
|
||||||
# Special cases
|
# Special cases
|
||||||
|
|
||||||
A few special C types which would normally be represented by a pointer
|
A few special C types which would normally be represented by a pointer
|
||||||
|
@ -94,8 +94,10 @@ func (f *File) ProcessCgoDirectives() {
|
|||||||
directive := fields[1]
|
directive := fields[1]
|
||||||
funcName := fields[2]
|
funcName := fields[2]
|
||||||
if directive == "nocallback" {
|
if directive == "nocallback" {
|
||||||
|
fatalf("#cgo nocallback disabled until Go 1.23")
|
||||||
f.NoCallbacks[funcName] = true
|
f.NoCallbacks[funcName] = true
|
||||||
} else if directive == "noescape" {
|
} else if directive == "noescape" {
|
||||||
|
fatalf("#cgo noescape disabled until Go 1.23")
|
||||||
f.NoEscapes[funcName] = true
|
f.NoEscapes[funcName] = true
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
109
src/cmd/cgo/internal/test/callback_windows.go
Normal file
109
src/cmd/cgo/internal/test/callback_windows.go
Normal file
@ -0,0 +1,109 @@
|
|||||||
|
// Copyright 2023 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 cgotest
|
||||||
|
|
||||||
|
/*
|
||||||
|
#include <windows.h>
|
||||||
|
USHORT backtrace(ULONG FramesToCapture, PVOID *BackTrace) {
|
||||||
|
#ifdef _AMD64_
|
||||||
|
CONTEXT context;
|
||||||
|
RtlCaptureContext(&context);
|
||||||
|
ULONG64 ControlPc;
|
||||||
|
ControlPc = context.Rip;
|
||||||
|
int i;
|
||||||
|
for (i = 0; i < FramesToCapture; i++) {
|
||||||
|
PRUNTIME_FUNCTION FunctionEntry;
|
||||||
|
ULONG64 ImageBase;
|
||||||
|
VOID *HandlerData;
|
||||||
|
ULONG64 EstablisherFrame;
|
||||||
|
|
||||||
|
FunctionEntry = RtlLookupFunctionEntry(ControlPc, &ImageBase, NULL);
|
||||||
|
|
||||||
|
if (!FunctionEntry) {
|
||||||
|
// For simplicity, don't unwind leaf entries, which are not used in this test.
|
||||||
|
break;
|
||||||
|
} else {
|
||||||
|
RtlVirtualUnwind(0, ImageBase, ControlPc, FunctionEntry, &context, &HandlerData, &EstablisherFrame, NULL);
|
||||||
|
}
|
||||||
|
|
||||||
|
ControlPc = context.Rip;
|
||||||
|
// Check if we left the user range.
|
||||||
|
if (ControlPc < 0x10000) {
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
BackTrace[i] = (PVOID)(ControlPc);
|
||||||
|
}
|
||||||
|
return i;
|
||||||
|
#else
|
||||||
|
return 0;
|
||||||
|
#endif
|
||||||
|
}
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import (
|
||||||
|
"internal/testenv"
|
||||||
|
"reflect"
|
||||||
|
"runtime"
|
||||||
|
"strings"
|
||||||
|
"testing"
|
||||||
|
"unsafe"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Test that the stack can be unwound through a call out and call back
|
||||||
|
// into Go.
|
||||||
|
func testCallbackCallersSEH(t *testing.T) {
|
||||||
|
testenv.SkipIfOptimizationOff(t) // This test requires inlining.
|
||||||
|
if runtime.Compiler != "gc" {
|
||||||
|
// The exact function names are not going to be the same.
|
||||||
|
t.Skip("skipping for non-gc toolchain")
|
||||||
|
}
|
||||||
|
if runtime.GOARCH != "amd64" {
|
||||||
|
// TODO: support SEH on other architectures.
|
||||||
|
t.Skip("skipping on non-amd64")
|
||||||
|
}
|
||||||
|
// Only frames in the test package are checked.
|
||||||
|
want := []string{
|
||||||
|
"test._Cfunc_backtrace",
|
||||||
|
"test.testCallbackCallersSEH.func1.1",
|
||||||
|
"test.testCallbackCallersSEH.func1",
|
||||||
|
"test.goCallback",
|
||||||
|
"test._Cfunc_callback",
|
||||||
|
"test.nestedCall.func1",
|
||||||
|
"test.nestedCall",
|
||||||
|
"test.testCallbackCallersSEH",
|
||||||
|
"test.TestCallbackCallersSEH",
|
||||||
|
}
|
||||||
|
pc := make([]uintptr, 100)
|
||||||
|
n := 0
|
||||||
|
nestedCall(func() {
|
||||||
|
n = int(C.backtrace(C.DWORD(len(pc)), (*C.PVOID)(unsafe.Pointer(&pc[0]))))
|
||||||
|
})
|
||||||
|
got := make([]string, 0, n)
|
||||||
|
for i := 0; i < n; i++ {
|
||||||
|
f := runtime.FuncForPC(pc[i] - 1)
|
||||||
|
if f == nil {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
fname := f.Name()
|
||||||
|
switch fname {
|
||||||
|
case "goCallback":
|
||||||
|
// TODO(qmuntal): investigate why this function doesn't appear
|
||||||
|
// when using the external linker.
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
// In module mode, this package has a fully-qualified import path.
|
||||||
|
// Remove it if present.
|
||||||
|
fname = strings.TrimPrefix(fname, "cmd/cgo/internal/")
|
||||||
|
if !strings.HasPrefix(fname, "test.") {
|
||||||
|
continue
|
||||||
|
}
|
||||||
|
got = append(got, fname)
|
||||||
|
}
|
||||||
|
if !reflect.DeepEqual(want, got) {
|
||||||
|
t.Errorf("incorrect backtrace:\nwant:\t%v\ngot:\t%v", want, got)
|
||||||
|
}
|
||||||
|
}
|
11
src/cmd/cgo/internal/test/cgo_windows_test.go
Normal file
11
src/cmd/cgo/internal/test/cgo_windows_test.go
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2023 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 cgo && windows
|
||||||
|
|
||||||
|
package cgotest
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func TestCallbackCallersSEH(t *testing.T) { testCallbackCallersSEH(t) }
|
@ -1,3 +1,7 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
#include <stdio.h>
|
#include <stdio.h>
|
||||||
#include "issue4339.h"
|
#include "issue4339.h"
|
||||||
|
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
// 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.
|
||||||
|
|
||||||
typedef struct Issue4339 Issue4339;
|
typedef struct Issue4339 Issue4339;
|
||||||
|
|
||||||
struct Issue4339 {
|
struct Issue4339 {
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
// Copyright 2016 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 cgotest
|
package cgotest
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
// Copyright 2016 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 issue8756
|
package issue8756
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
// 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 issue8828
|
package issue8828
|
||||||
|
|
||||||
//void foo();
|
//void foo();
|
||||||
|
@ -1,3 +1,7 @@
|
|||||||
|
// 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 issue9026
|
package issue9026
|
||||||
|
|
||||||
// This file appears in its own package since the assertion tests the
|
// This file appears in its own package since the assertion tests the
|
||||||
|
@ -1,3 +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 issue9510a
|
package issue9510a
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -1,3 +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 issue9510b
|
package issue9510b
|
||||||
|
|
||||||
/*
|
/*
|
||||||
|
@ -117,7 +117,8 @@ int add(int x, int y) {
|
|||||||
|
|
||||||
// escape vs noescape
|
// escape vs noescape
|
||||||
|
|
||||||
#cgo noescape handleGoStringPointerNoescape
|
// TODO(#56378): enable in Go 1.23:
|
||||||
|
// #cgo noescape handleGoStringPointerNoescape
|
||||||
void handleGoStringPointerNoescape(void *s) {}
|
void handleGoStringPointerNoescape(void *s) {}
|
||||||
|
|
||||||
void handleGoStringPointerEscape(void *s) {}
|
void handleGoStringPointerEscape(void *s) {}
|
||||||
|
@ -1365,3 +1365,35 @@ func TestDeepStack(t *testing.T) {
|
|||||||
t.Error(err)
|
t.Error(err)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestSharedObject(t *testing.T) {
|
||||||
|
// Test that we can put a Go c-archive into a C shared object.
|
||||||
|
globalSkip(t)
|
||||||
|
testenv.MustHaveGoBuild(t)
|
||||||
|
testenv.MustHaveCGO(t)
|
||||||
|
testenv.MustHaveBuildMode(t, "c-archive")
|
||||||
|
|
||||||
|
t.Parallel()
|
||||||
|
|
||||||
|
if !testWork {
|
||||||
|
defer func() {
|
||||||
|
os.Remove("libgo_s.a")
|
||||||
|
os.Remove("libgo_s.h")
|
||||||
|
os.Remove("libgo_s.so")
|
||||||
|
}()
|
||||||
|
}
|
||||||
|
|
||||||
|
cmd := exec.Command("go", "build", "-buildmode=c-archive", "-o", "libgo_s.a", "./libgo")
|
||||||
|
out, err := cmd.CombinedOutput()
|
||||||
|
t.Logf("%v\n%s", cmd.Args, out)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
|
||||||
|
ccArgs := append(cc, "-shared", "-o", "libgo_s.so", "libgo_s.a")
|
||||||
|
out, err = exec.Command(ccArgs[0], ccArgs[1:]...).CombinedOutput()
|
||||||
|
t.Logf("%v\n%s", ccArgs, out)
|
||||||
|
if err != nil {
|
||||||
|
t.Fatal(err)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
@ -118,6 +118,7 @@ func TestReportsTypeErrors(t *testing.T) {
|
|||||||
for _, file := range []string{
|
for _, file := range []string{
|
||||||
"err1.go",
|
"err1.go",
|
||||||
"err2.go",
|
"err2.go",
|
||||||
|
"err5.go",
|
||||||
"issue11097a.go",
|
"issue11097a.go",
|
||||||
"issue11097b.go",
|
"issue11097b.go",
|
||||||
"issue18452.go",
|
"issue18452.go",
|
||||||
|
11
src/cmd/cgo/internal/testerrors/testdata/err5.go
vendored
Normal file
11
src/cmd/cgo/internal/testerrors/testdata/err5.go
vendored
Normal file
@ -0,0 +1,11 @@
|
|||||||
|
// Copyright 2023 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
|
||||||
|
|
||||||
|
//line /tmp/_cgo_.go:1
|
||||||
|
//go:cgo_dynamic_linker "/elf/interp"
|
||||||
|
// ERROR MESSAGE: only allowed in cgo-generated code
|
||||||
|
|
||||||
|
func main() {}
|
@ -5,7 +5,8 @@
|
|||||||
package main
|
package main
|
||||||
|
|
||||||
/*
|
/*
|
||||||
// ERROR MESSAGE: #cgo noescape noMatchedCFunction: no matched C function
|
// TODO(#56378): change back to "#cgo noescape noMatchedCFunction: no matched C function" in Go 1.23
|
||||||
|
// ERROR MESSAGE: #cgo noescape disabled until Go 1.23
|
||||||
#cgo noescape noMatchedCFunction
|
#cgo noescape noMatchedCFunction
|
||||||
*/
|
*/
|
||||||
import "C"
|
import "C"
|
||||||
|
@ -5,7 +5,6 @@
|
|||||||
package fortran
|
package fortran
|
||||||
|
|
||||||
import (
|
import (
|
||||||
"fmt"
|
|
||||||
"internal/testenv"
|
"internal/testenv"
|
||||||
"os"
|
"os"
|
||||||
"os/exec"
|
"os/exec"
|
||||||
@ -75,11 +74,18 @@ func TestFortran(t *testing.T) {
|
|||||||
|
|
||||||
// Finally, run the actual test.
|
// Finally, run the actual test.
|
||||||
t.Log("go", "run", "./testdata/testprog")
|
t.Log("go", "run", "./testdata/testprog")
|
||||||
out, err := exec.Command("go", "run", "./testdata/testprog").CombinedOutput()
|
var stdout, stderr strings.Builder
|
||||||
if err == nil && string(out) != "ok\n" {
|
cmd := exec.Command("go", "run", "./testdata/testprog")
|
||||||
err = fmt.Errorf("expected ok")
|
cmd.Stdout = &stdout
|
||||||
|
cmd.Stderr = &stderr
|
||||||
|
err := cmd.Run()
|
||||||
|
t.Logf("%v", cmd)
|
||||||
|
if stderr.Len() != 0 {
|
||||||
|
t.Logf("stderr:\n%s", stderr.String())
|
||||||
}
|
}
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Errorf("%s\nOutput:\n%s", err, string(out))
|
t.Errorf("%v\n%s", err, stdout.String())
|
||||||
|
} else if stdout.String() != "ok\n" {
|
||||||
|
t.Errorf("stdout:\n%s\nwant \"ok\"", stdout.String())
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -6,7 +6,10 @@ package main
|
|||||||
|
|
||||||
// int the_answer();
|
// int the_answer();
|
||||||
import "C"
|
import "C"
|
||||||
import "os"
|
import (
|
||||||
|
"fmt"
|
||||||
|
"os"
|
||||||
|
)
|
||||||
|
|
||||||
func TheAnswer() int {
|
func TheAnswer() int {
|
||||||
return int(C.the_answer())
|
return int(C.the_answer())
|
||||||
@ -14,8 +17,8 @@ func TheAnswer() int {
|
|||||||
|
|
||||||
func main() {
|
func main() {
|
||||||
if a := TheAnswer(); a != 42 {
|
if a := TheAnswer(); a != 42 {
|
||||||
println("Unexpected result for The Answer. Got:", a, " Want: 42")
|
fmt.Fprintln(os.Stderr, "Unexpected result for The Answer. Got:", a, " Want: 42")
|
||||||
os.Exit(1)
|
os.Exit(1)
|
||||||
}
|
}
|
||||||
println("ok")
|
fmt.Fprintln(os.Stdout, "ok")
|
||||||
}
|
}
|
||||||
|
@ -7,11 +7,14 @@
|
|||||||
package sanitizers_test
|
package sanitizers_test
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"internal/testenv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestLibFuzzer(t *testing.T) {
|
func TestLibFuzzer(t *testing.T) {
|
||||||
|
testenv.MustHaveGoBuild(t)
|
||||||
|
testenv.MustHaveCGO(t)
|
||||||
goos, err := goEnv("GOOS")
|
goos, err := goEnv("GOOS")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -8,11 +8,14 @@ package sanitizers_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"internal/platform"
|
"internal/platform"
|
||||||
|
"internal/testenv"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
)
|
)
|
||||||
|
|
||||||
func TestMSAN(t *testing.T) {
|
func TestMSAN(t *testing.T) {
|
||||||
|
testenv.MustHaveGoBuild(t)
|
||||||
|
testenv.MustHaveCGO(t)
|
||||||
goos, err := goEnv("GOOS")
|
goos, err := goEnv("GOOS")
|
||||||
if err != nil {
|
if err != nil {
|
||||||
t.Fatal(err)
|
t.Fatal(err)
|
||||||
|
@ -633,6 +633,56 @@ modifying or saving the FPCR.
|
|||||||
Functions are allowed to modify it between calls (as long as they
|
Functions are allowed to modify it between calls (as long as they
|
||||||
restore it), but as of this writing Go code never does.
|
restore it), but as of this writing Go code never does.
|
||||||
|
|
||||||
|
### loong64 architecture
|
||||||
|
|
||||||
|
The loong64 architecture uses R4 – R19 for integer arguments and integer results.
|
||||||
|
|
||||||
|
It uses F0 – F15 for floating-point arguments and results.
|
||||||
|
|
||||||
|
Registers R20 - R21, R23 – R28, R30 - R31, F16 – F31 are permanent scratch registers.
|
||||||
|
|
||||||
|
Register R2 is reserved and never used.
|
||||||
|
|
||||||
|
Register R20, R21 is Used by runtime.duffcopy, runtime.duffzero.
|
||||||
|
|
||||||
|
Special-purpose registers used within Go generated code and Go assembly code
|
||||||
|
are as follows:
|
||||||
|
|
||||||
|
| Register | Call meaning | Return meaning | Body meaning |
|
||||||
|
| --- | --- | --- | --- |
|
||||||
|
| R0 | Zero value | Same | Same |
|
||||||
|
| R1 | Link register | Link register | Scratch |
|
||||||
|
| R3 | Stack pointer | Same | Same |
|
||||||
|
| R20,R21 | Scratch | Scratch | Used by duffcopy, duffzero |
|
||||||
|
| R22 | Current goroutine | Same | Same |
|
||||||
|
| R29 | Closure context pointer | Same | Same |
|
||||||
|
| R30, R31 | used by the assembler | Same | Same |
|
||||||
|
|
||||||
|
*Rationale*: These register meanings are compatible with Go’s stack-based
|
||||||
|
calling convention.
|
||||||
|
|
||||||
|
#### Stack layout
|
||||||
|
|
||||||
|
The stack pointer, R3, 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 | ← R3 points to
|
||||||
|
+------------------------------+ ↓ lower addresses
|
||||||
|
|
||||||
|
This stack layout is used by both register-based (ABIInternal) and
|
||||||
|
stack-based (ABI0) calling conventions.
|
||||||
|
|
||||||
|
The "return PC" is loaded to the link register, R1, as part of the
|
||||||
|
loong64 `JAL` operation.
|
||||||
|
|
||||||
|
#### Flags
|
||||||
|
All bits in CSR are system flags and are not modified by Go.
|
||||||
|
|
||||||
### ppc64 architecture
|
### ppc64 architecture
|
||||||
|
|
||||||
The ppc64 architecture uses R3 – R10 and R14 – R17 for integer arguments
|
The ppc64 architecture uses R3 – R10 and R14 – R17 for integer arguments
|
||||||
|
Binary file not shown.
@ -8,6 +8,7 @@ import (
|
|||||||
"cmd/compile/internal/base"
|
"cmd/compile/internal/base"
|
||||||
"cmd/compile/internal/ir"
|
"cmd/compile/internal/ir"
|
||||||
"cmd/compile/internal/types"
|
"cmd/compile/internal/types"
|
||||||
|
"cmd/internal/obj"
|
||||||
"cmd/internal/src"
|
"cmd/internal/src"
|
||||||
"fmt"
|
"fmt"
|
||||||
"math"
|
"math"
|
||||||
@ -261,12 +262,13 @@ type ABIConfig struct {
|
|||||||
// Do we need anything more than this?
|
// Do we need anything more than this?
|
||||||
offsetForLocals int64 // e.g., obj.(*Link).Arch.FixedFrameSize -- extra linkage information on some architectures.
|
offsetForLocals int64 // e.g., obj.(*Link).Arch.FixedFrameSize -- extra linkage information on some architectures.
|
||||||
regAmounts RegAmounts
|
regAmounts RegAmounts
|
||||||
|
which obj.ABI
|
||||||
}
|
}
|
||||||
|
|
||||||
// NewABIConfig returns a new ABI configuration for an architecture with
|
// NewABIConfig returns a new ABI configuration for an architecture with
|
||||||
// iRegsCount integer/pointer registers and fRegsCount floating point registers.
|
// iRegsCount integer/pointer registers and fRegsCount floating point registers.
|
||||||
func NewABIConfig(iRegsCount, fRegsCount int, offsetForLocals int64) *ABIConfig {
|
func NewABIConfig(iRegsCount, fRegsCount int, offsetForLocals int64, which uint8) *ABIConfig {
|
||||||
return &ABIConfig{offsetForLocals: offsetForLocals, regAmounts: RegAmounts{iRegsCount, fRegsCount}}
|
return &ABIConfig{offsetForLocals: offsetForLocals, regAmounts: RegAmounts{iRegsCount, fRegsCount}, which: obj.ABI(which)}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Copy returns config.
|
// Copy returns config.
|
||||||
@ -276,6 +278,11 @@ func (config *ABIConfig) Copy() *ABIConfig {
|
|||||||
return config
|
return config
|
||||||
}
|
}
|
||||||
|
|
||||||
|
// Which returns the ABI number
|
||||||
|
func (config *ABIConfig) Which() obj.ABI {
|
||||||
|
return config.which
|
||||||
|
}
|
||||||
|
|
||||||
// LocalsOffset returns the architecture-dependent offset from SP for args and results.
|
// LocalsOffset returns the architecture-dependent offset from SP for args and results.
|
||||||
// In theory this is only used for debugging; it ought to already be incorporated into
|
// In theory this is only used for debugging; it ought to already be incorporated into
|
||||||
// results from the ABI-related methods
|
// results from the ABI-related methods
|
||||||
|
@ -15,7 +15,7 @@ func Init(arch *ssagen.ArchInfo) {
|
|||||||
arch.LinkArch = &arm.Linkarm
|
arch.LinkArch = &arm.Linkarm
|
||||||
arch.REGSP = arm.REGSP
|
arch.REGSP = arm.REGSP
|
||||||
arch.MAXWIDTH = (1 << 32) - 1
|
arch.MAXWIDTH = (1 << 32) - 1
|
||||||
arch.SoftFloat = buildcfg.GOARM == 5
|
arch.SoftFloat = buildcfg.GOARM.SoftFloat
|
||||||
arch.ZeroRange = zerorange
|
arch.ZeroRange = zerorange
|
||||||
arch.Ginsnop = ginsnop
|
arch.Ginsnop = ginsnop
|
||||||
|
|
||||||
|
@ -289,7 +289,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||||||
case ssa.OpARMANDconst, ssa.OpARMBICconst:
|
case ssa.OpARMANDconst, ssa.OpARMBICconst:
|
||||||
// try to optimize ANDconst and BICconst to BFC, which saves bytes and ticks
|
// try to optimize ANDconst and BICconst to BFC, which saves bytes and ticks
|
||||||
// BFC is only available on ARMv7, and its result and source are in the same register
|
// BFC is only available on ARMv7, and its result and source are in the same register
|
||||||
if buildcfg.GOARM == 7 && v.Reg() == v.Args[0].Reg() {
|
if buildcfg.GOARM.Version == 7 && v.Reg() == v.Args[0].Reg() {
|
||||||
var val uint32
|
var val uint32
|
||||||
if v.Op == ssa.OpARMANDconst {
|
if v.Op == ssa.OpARMANDconst {
|
||||||
val = ^uint32(v.AuxInt)
|
val = ^uint32(v.AuxInt)
|
||||||
@ -646,7 +646,7 @@ func ssaGenValue(s *ssagen.State, v *ssa.Value) {
|
|||||||
default:
|
default:
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
if buildcfg.GOARM >= 6 {
|
if buildcfg.GOARM.Version >= 6 {
|
||||||
// generate more efficient "MOVB/MOVBU/MOVH/MOVHU Reg@>0, Reg" on ARMv6 & ARMv7
|
// generate more efficient "MOVB/MOVBU/MOVH/MOVHU Reg@>0, Reg" on ARMv6 & ARMv7
|
||||||
genshift(s, v, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_RR, 0)
|
genshift(s, v, v.Op.Asm(), 0, v.Args[0].Reg(), v.Reg(), arm.SHIFT_RR, 0)
|
||||||
return
|
return
|
||||||
|
@ -23,6 +23,8 @@ type DebugFlags struct {
|
|||||||
DisableNil int `help:"disable nil checks" concurrent:"ok"`
|
DisableNil int `help:"disable nil checks" concurrent:"ok"`
|
||||||
DumpInlFuncProps string `help:"dump function properties from inl heuristics to specified file"`
|
DumpInlFuncProps string `help:"dump function properties from inl heuristics to specified file"`
|
||||||
DumpInlCallSiteScores int `help:"dump scored callsites during inlining"`
|
DumpInlCallSiteScores int `help:"dump scored callsites during inlining"`
|
||||||
|
InlScoreAdj string `help:"set inliner score adjustments (ex: -d=inlscoreadj=panicPathAdj:10/passConstToNestedIfAdj:-90)"`
|
||||||
|
InlBudgetSlack int `help:"amount to expand the initial inline budget when new inliner enabled. Defaults to 80 if option not set." concurrent:"ok"`
|
||||||
DumpPtrs int `help:"show Node pointers values in dump output"`
|
DumpPtrs int `help:"show Node pointers values in dump output"`
|
||||||
DwarfInl int `help:"print information about DWARF inlined function creation"`
|
DwarfInl int `help:"print information about DWARF inlined function creation"`
|
||||||
EscapeMutationsCalls int `help:"print extra escape analysis diagnostics about mutations and calls" concurrent:"ok"`
|
EscapeMutationsCalls int `help:"print extra escape analysis diagnostics about mutations and calls" concurrent:"ok"`
|
||||||
@ -34,7 +36,6 @@ type DebugFlags struct {
|
|||||||
Gossahash string `help:"hash value for use in debugging the compiler"`
|
Gossahash string `help:"hash value for use in debugging the compiler"`
|
||||||
InlFuncsWithClosures int `help:"allow functions with closures to be inlined" concurrent:"ok"`
|
InlFuncsWithClosures int `help:"allow functions with closures to be inlined" concurrent:"ok"`
|
||||||
InlStaticInit int `help:"allow static initialization of inlined calls" concurrent:"ok"`
|
InlStaticInit int `help:"allow static initialization of inlined calls" concurrent:"ok"`
|
||||||
InterfaceCycles int `help:"allow anonymous interface cycles"`
|
|
||||||
Libfuzzer int `help:"enable coverage instrumentation for libfuzzer"`
|
Libfuzzer int `help:"enable coverage instrumentation for libfuzzer"`
|
||||||
LoopVar int `help:"shared (0, default), 1 (private loop variables), 2, private + log"`
|
LoopVar int `help:"shared (0, default), 1 (private loop variables), 2, private + log"`
|
||||||
LoopVarHash string `help:"for debugging changes in loop behavior. Overrides experiment and loopvar flag."`
|
LoopVarHash string `help:"for debugging changes in loop behavior. Overrides experiment and loopvar flag."`
|
||||||
@ -59,7 +60,8 @@ type DebugFlags struct {
|
|||||||
PGOInline int `help:"enable profile-guided inlining" concurrent:"ok"`
|
PGOInline int `help:"enable profile-guided inlining" concurrent:"ok"`
|
||||||
PGOInlineCDFThreshold string `help:"cumulative threshold percentage for determining call sites as hot candidates for inlining" concurrent:"ok"`
|
PGOInlineCDFThreshold string `help:"cumulative threshold percentage for determining call sites as hot candidates for inlining" concurrent:"ok"`
|
||||||
PGOInlineBudget int `help:"inline budget for hot functions" concurrent:"ok"`
|
PGOInlineBudget int `help:"inline budget for hot functions" concurrent:"ok"`
|
||||||
PGODevirtualize int `help:"enable profile-guided devirtualization" concurrent:"ok"`
|
PGODevirtualize int `help:"enable profile-guided devirtualization; 0 to disable, 1 to enable interface devirtualization, 2 to enable function devirtualization" concurrent:"ok"`
|
||||||
|
RangeFuncCheck int `help:"insert code to check behavior of range iterator functions" concurrent:"ok"`
|
||||||
WrapGlobalMapDbg int `help:"debug trace output for global map init wrapping"`
|
WrapGlobalMapDbg int `help:"debug trace output for global map init wrapping"`
|
||||||
WrapGlobalMapCtl int `help:"global map init wrap control (0 => default, 1 => off, 2 => stress mode, no size cutoff)"`
|
WrapGlobalMapCtl int `help:"global map init wrap control (0 => default, 1 => off, 2 => stress mode, no size cutoff)"`
|
||||||
ZeroCopy int `help:"enable zero-copy string->[]byte conversions" concurrent:"ok"`
|
ZeroCopy int `help:"enable zero-copy string->[]byte conversions" concurrent:"ok"`
|
||||||
|
@ -5,11 +5,11 @@
|
|||||||
package base
|
package base
|
||||||
|
|
||||||
import (
|
import (
|
||||||
|
"cmd/internal/cov/covcmd"
|
||||||
"encoding/json"
|
"encoding/json"
|
||||||
"flag"
|
"flag"
|
||||||
"fmt"
|
"fmt"
|
||||||
"internal/buildcfg"
|
"internal/buildcfg"
|
||||||
"internal/coverage/covcmd"
|
|
||||||
"internal/platform"
|
"internal/platform"
|
||||||
"log"
|
"log"
|
||||||
"os"
|
"os"
|
||||||
@ -179,9 +179,10 @@ func ParseFlags() {
|
|||||||
Debug.InlFuncsWithClosures = 1
|
Debug.InlFuncsWithClosures = 1
|
||||||
Debug.InlStaticInit = 1
|
Debug.InlStaticInit = 1
|
||||||
Debug.PGOInline = 1
|
Debug.PGOInline = 1
|
||||||
Debug.PGODevirtualize = 1
|
Debug.PGODevirtualize = 2
|
||||||
Debug.SyncFrames = -1 // disable sync markers by default
|
Debug.SyncFrames = -1 // disable sync markers by default
|
||||||
Debug.ZeroCopy = 1
|
Debug.ZeroCopy = 1
|
||||||
|
Debug.RangeFuncCheck = 1
|
||||||
|
|
||||||
Debug.Checkptr = -1 // so we can tell whether it is set explicitly
|
Debug.Checkptr = -1 // so we can tell whether it is set explicitly
|
||||||
|
|
||||||
|
@ -204,7 +204,6 @@ func NewHashDebug(ev, s string, file io.Writer) *HashDebug {
|
|||||||
i++
|
i++
|
||||||
}
|
}
|
||||||
return hd
|
return hd
|
||||||
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// TODO: Delete when we switch to bisect-only.
|
// TODO: Delete when we switch to bisect-only.
|
||||||
|
@ -18,40 +18,28 @@ import (
|
|||||||
"cmd/compile/internal/types"
|
"cmd/compile/internal/types"
|
||||||
)
|
)
|
||||||
|
|
||||||
// Static devirtualizes calls within fn where possible when the concrete callee
|
// StaticCall devirtualizes the given call if possible when the concrete callee
|
||||||
// is available statically.
|
// is available statically.
|
||||||
func Static(fn *ir.Func) {
|
func StaticCall(call *ir.CallExpr) {
|
||||||
ir.CurFunc = fn
|
// For promoted methods (including value-receiver methods promoted
|
||||||
|
// to pointer-receivers), the interface method wrapper may contain
|
||||||
// For promoted methods (including value-receiver methods promoted to pointer-receivers),
|
// expressions that can panic (e.g., ODEREF, ODOTPTR,
|
||||||
// the interface method wrapper may contain expressions that can panic (e.g., ODEREF, ODOTPTR, ODOTINTER).
|
// ODOTINTER). Devirtualization involves inlining these expressions
|
||||||
// Devirtualization involves inlining these expressions (and possible panics) to the call site.
|
// (and possible panics) to the call site. This normally isn't a
|
||||||
// This normally isn't a problem, but for go/defer statements it can move the panic from when/where
|
// problem, but for go/defer statements it can move the panic from
|
||||||
// the call executes to the go/defer statement itself, which is a visible change in semantics (e.g., #52072).
|
// when/where the call executes to the go/defer statement itself,
|
||||||
// To prevent this, we skip devirtualizing calls within go/defer statements altogether.
|
// which is a visible change in semantics (e.g., #52072). To prevent
|
||||||
goDeferCall := make(map[*ir.CallExpr]bool)
|
// this, we skip devirtualizing calls within go/defer statements
|
||||||
ir.VisitList(fn.Body, func(n ir.Node) {
|
// altogether.
|
||||||
switch n := n.(type) {
|
if call.GoDefer {
|
||||||
case *ir.GoDeferStmt:
|
|
||||||
if call, ok := n.Call.(*ir.CallExpr); ok {
|
|
||||||
goDeferCall[call] = true
|
|
||||||
}
|
|
||||||
return
|
return
|
||||||
case *ir.CallExpr:
|
|
||||||
if !goDeferCall[n] {
|
|
||||||
staticCall(n)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
})
|
|
||||||
}
|
}
|
||||||
|
|
||||||
// staticCall devirtualizes the given call if possible when the concrete callee
|
|
||||||
// is available statically.
|
|
||||||
func staticCall(call *ir.CallExpr) {
|
|
||||||
if call.Op() != ir.OCALLINTER {
|
if call.Op() != ir.OCALLINTER {
|
||||||
return
|
return
|
||||||
}
|
}
|
||||||
sel := call.X.(*ir.SelectorExpr)
|
|
||||||
|
sel := call.Fun.(*ir.SelectorExpr)
|
||||||
r := ir.StaticValue(sel.X)
|
r := ir.StaticValue(sel.X)
|
||||||
if r.Op() != ir.OCONVIFACE {
|
if r.Op() != ir.OCONVIFACE {
|
||||||
return
|
return
|
||||||
@ -70,7 +58,7 @@ func staticCall(call *ir.CallExpr) {
|
|||||||
return
|
return
|
||||||
}
|
}
|
||||||
|
|
||||||
// If typ *has* a shape type, then it's an shaped, instantiated
|
// If typ *has* a shape type, then it's a shaped, instantiated
|
||||||
// type like T[go.shape.int], and its methods (may) have an extra
|
// type like T[go.shape.int], and its methods (may) have an extra
|
||||||
// dictionary parameter. We could devirtualize this call if we
|
// dictionary parameter. We could devirtualize this call if we
|
||||||
// could derive an appropriate dictionary argument.
|
// could derive an appropriate dictionary argument.
|
||||||
@ -120,14 +108,14 @@ func staticCall(call *ir.CallExpr) {
|
|||||||
base.WarnfAt(call.Pos(), "devirtualizing %v to %v", sel, typ)
|
base.WarnfAt(call.Pos(), "devirtualizing %v to %v", sel, typ)
|
||||||
}
|
}
|
||||||
call.SetOp(ir.OCALLMETH)
|
call.SetOp(ir.OCALLMETH)
|
||||||
call.X = x
|
call.Fun = x
|
||||||
case ir.ODOTINTER:
|
case ir.ODOTINTER:
|
||||||
// Promoted method from embedded interface-typed field (#42279).
|
// Promoted method from embedded interface-typed field (#42279).
|
||||||
if base.Flag.LowerM != 0 {
|
if base.Flag.LowerM != 0 {
|
||||||
base.WarnfAt(call.Pos(), "partially devirtualizing %v to %v", sel, typ)
|
base.WarnfAt(call.Pos(), "partially devirtualizing %v to %v", sel, typ)
|
||||||
}
|
}
|
||||||
call.SetOp(ir.OCALLINTER)
|
call.SetOp(ir.OCALLINTER)
|
||||||
call.X = x
|
call.Fun = x
|
||||||
default:
|
default:
|
||||||
base.FatalfAt(call.Pos(), "failed to devirtualize %v (%v)", x, x.Op())
|
base.FatalfAt(call.Pos(), "failed to devirtualize %v (%v)", x, x.Op())
|
||||||
}
|
}
|
||||||
|
Some files were not shown because too many files have changed in this diff Show More
Loading…
Reference in New Issue
Block a user