mirror of
https://github.com/golang/go.git
synced 2025-05-07 08:32:59 +00:00
Compare commits
19 Commits
Author | SHA1 | Date | |
---|---|---|---|
|
3901409b5d | ||
|
35c0ea22a9 | ||
|
6d399e9da6 | ||
|
b7b4c60585 | ||
|
18068cb96a | ||
|
c43ac38b3b | ||
|
4241f582fc | ||
|
8a4c24f9bb | ||
|
3de5aca7d0 | ||
|
8336dfde70 | ||
|
6b60550504 | ||
|
468fad45a2 | ||
|
e06b6fc58d | ||
|
b3799ba634 | ||
|
16afa6a740 | ||
|
817d7bdc0a | ||
|
14bb1e11b9 | ||
|
2297c34cdf | ||
|
26682773ca |
@ -1 +1,2 @@
|
|||||||
branch: master
|
branch: release-branch.go1.24
|
||||||
|
parent-branch: master
|
||||||
|
@ -67,26 +67,26 @@ func splitSeq(s, sep []byte, sepSave int) iter.Seq[[]byte] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// SplitSeq returns an iterator over all substrings of s separated by sep.
|
// SplitSeq returns an iterator over all subslices of s separated by sep.
|
||||||
// The iterator yields the same strings that would be returned by [Split](s, sep),
|
// The iterator yields the same subslices that would be returned by [Split](s, sep),
|
||||||
// but without constructing the slice.
|
// but without constructing a new slice containing the subslices.
|
||||||
// It returns a single-use iterator.
|
// It returns a single-use iterator.
|
||||||
func SplitSeq(s, sep []byte) iter.Seq[[]byte] {
|
func SplitSeq(s, sep []byte) iter.Seq[[]byte] {
|
||||||
return splitSeq(s, sep, 0)
|
return splitSeq(s, sep, 0)
|
||||||
}
|
}
|
||||||
|
|
||||||
// SplitAfterSeq returns an iterator over substrings of s split after each instance of sep.
|
// SplitAfterSeq returns an iterator over subslices of s split after each instance of sep.
|
||||||
// The iterator yields the same strings that would be returned by [SplitAfter](s, sep),
|
// The iterator yields the same subslices that would be returned by [SplitAfter](s, sep),
|
||||||
// but without constructing the slice.
|
// but without constructing a new slice containing the subslices.
|
||||||
// It returns a single-use iterator.
|
// It returns a single-use iterator.
|
||||||
func SplitAfterSeq(s, sep []byte) iter.Seq[[]byte] {
|
func SplitAfterSeq(s, sep []byte) iter.Seq[[]byte] {
|
||||||
return splitSeq(s, sep, len(sep))
|
return splitSeq(s, sep, len(sep))
|
||||||
}
|
}
|
||||||
|
|
||||||
// FieldsSeq returns an iterator over substrings of s split around runs of
|
// FieldsSeq returns an iterator over subslices of s split around runs of
|
||||||
// whitespace characters, as defined by [unicode.IsSpace].
|
// whitespace characters, as defined by [unicode.IsSpace].
|
||||||
// The iterator yields the same strings that would be returned by [Fields](s),
|
// The iterator yields the same subslices that would be returned by [Fields](s),
|
||||||
// but without constructing the slice.
|
// but without constructing a new slice containing the subslices.
|
||||||
func FieldsSeq(s []byte) iter.Seq[[]byte] {
|
func FieldsSeq(s []byte) iter.Seq[[]byte] {
|
||||||
return func(yield func([]byte) bool) {
|
return func(yield func([]byte) bool) {
|
||||||
start := -1
|
start := -1
|
||||||
@ -116,10 +116,10 @@ func FieldsSeq(s []byte) iter.Seq[[]byte] {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// FieldsFuncSeq returns an iterator over substrings of s split around runs of
|
// FieldsFuncSeq returns an iterator over subslices of s split around runs of
|
||||||
// Unicode code points satisfying f(c).
|
// Unicode code points satisfying f(c).
|
||||||
// The iterator yields the same strings that would be returned by [FieldsFunc](s),
|
// The iterator yields the same subslices that would be returned by [FieldsFunc](s),
|
||||||
// but without constructing the slice.
|
// but without constructing a new slice containing the subslices.
|
||||||
func FieldsFuncSeq(s []byte, f func(rune) bool) iter.Seq[[]byte] {
|
func FieldsFuncSeq(s []byte, f func(rune) bool) iter.Seq[[]byte] {
|
||||||
return func(yield func([]byte) bool) {
|
return func(yield func([]byte) bool) {
|
||||||
start := -1
|
start := -1
|
||||||
|
@ -227,21 +227,6 @@ var validLinkerFlags = []*lazyregexp.Regexp{
|
|||||||
re(`\./.*\.(a|o|obj|dll|dylib|so|tbd)`),
|
re(`\./.*\.(a|o|obj|dll|dylib|so|tbd)`),
|
||||||
}
|
}
|
||||||
|
|
||||||
var validLinkerFlagsOnDarwin = []*lazyregexp.Regexp{
|
|
||||||
// The GNU linker interprets `@file` as "read command-line options from
|
|
||||||
// file". Thus, we forbid values starting with `@` on linker flags.
|
|
||||||
// However, this causes a problem when targeting Darwin.
|
|
||||||
// `@executable_path`, `@loader_path`, and `@rpath` are special values
|
|
||||||
// used in Mach-O to change the library search path and can be used in
|
|
||||||
// conjunction with the `-install_name` and `-rpath` linker flags.
|
|
||||||
// Since the GNU linker does not support Mach-O, targeting Darwin
|
|
||||||
// implies not using the GNU linker. Therefore, we allow @ in the linker
|
|
||||||
// flags if and only if cfg.Goos == "darwin" || cfg.Goos == "ios".
|
|
||||||
re(`-Wl,-dylib_install_name,@rpath(/[^,]*)?`),
|
|
||||||
re(`-Wl,-install_name,@rpath(/[^,]*)?`),
|
|
||||||
re(`-Wl,-rpath,@(executable_path|loader_path)(/[^,]*)?`),
|
|
||||||
}
|
|
||||||
|
|
||||||
var validLinkerFlagsWithNextArg = []string{
|
var validLinkerFlagsWithNextArg = []string{
|
||||||
"-arch",
|
"-arch",
|
||||||
"-F",
|
"-F",
|
||||||
@ -264,13 +249,8 @@ func checkCompilerFlags(name, source string, list []string) error {
|
|||||||
}
|
}
|
||||||
|
|
||||||
func checkLinkerFlags(name, source string, list []string) error {
|
func checkLinkerFlags(name, source string, list []string) error {
|
||||||
validLinkerFlagsForPlatform := validLinkerFlags
|
|
||||||
if cfg.Goos == "darwin" || cfg.Goos == "ios" {
|
|
||||||
validLinkerFlagsForPlatform = append(validLinkerFlags, validLinkerFlagsOnDarwin...)
|
|
||||||
}
|
|
||||||
|
|
||||||
checkOverrides := true
|
checkOverrides := true
|
||||||
return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlagsForPlatform, validLinkerFlagsWithNextArg, checkOverrides)
|
return checkFlags(name, source, list, invalidLinkerFlags, validLinkerFlags, validLinkerFlagsWithNextArg, checkOverrides)
|
||||||
}
|
}
|
||||||
|
|
||||||
// checkCompilerFlagsForInternalLink returns an error if 'list'
|
// checkCompilerFlagsForInternalLink returns an error if 'list'
|
||||||
|
@ -8,8 +8,6 @@ import (
|
|||||||
"os"
|
"os"
|
||||||
"strings"
|
"strings"
|
||||||
"testing"
|
"testing"
|
||||||
|
|
||||||
"cmd/go/internal/cfg"
|
|
||||||
)
|
)
|
||||||
|
|
||||||
var goodCompilerFlags = [][]string{
|
var goodCompilerFlags = [][]string{
|
||||||
@ -247,8 +245,6 @@ var badLinkerFlags = [][]string{
|
|||||||
{"-Wl,--hash-style=foo"},
|
{"-Wl,--hash-style=foo"},
|
||||||
{"-x", "--c"},
|
{"-x", "--c"},
|
||||||
{"-x", "@obj"},
|
{"-x", "@obj"},
|
||||||
{"-Wl,-dylib_install_name,@foo"},
|
|
||||||
{"-Wl,-install_name,@foo"},
|
|
||||||
{"-Wl,-rpath,@foo"},
|
{"-Wl,-rpath,@foo"},
|
||||||
{"-Wl,-R,foo,bar"},
|
{"-Wl,-R,foo,bar"},
|
||||||
{"-Wl,-R,@foo"},
|
{"-Wl,-R,@foo"},
|
||||||
@ -265,21 +261,6 @@ var badLinkerFlags = [][]string{
|
|||||||
{"./-Wl,--push-state,-R.c"},
|
{"./-Wl,--push-state,-R.c"},
|
||||||
}
|
}
|
||||||
|
|
||||||
var goodLinkerFlagsOnDarwin = [][]string{
|
|
||||||
{"-Wl,-dylib_install_name,@rpath"},
|
|
||||||
{"-Wl,-dylib_install_name,@rpath/"},
|
|
||||||
{"-Wl,-dylib_install_name,@rpath/foo"},
|
|
||||||
{"-Wl,-install_name,@rpath"},
|
|
||||||
{"-Wl,-install_name,@rpath/"},
|
|
||||||
{"-Wl,-install_name,@rpath/foo"},
|
|
||||||
{"-Wl,-rpath,@executable_path"},
|
|
||||||
{"-Wl,-rpath,@executable_path/"},
|
|
||||||
{"-Wl,-rpath,@executable_path/foo"},
|
|
||||||
{"-Wl,-rpath,@loader_path"},
|
|
||||||
{"-Wl,-rpath,@loader_path/"},
|
|
||||||
{"-Wl,-rpath,@loader_path/foo"},
|
|
||||||
}
|
|
||||||
|
|
||||||
func TestCheckLinkerFlags(t *testing.T) {
|
func TestCheckLinkerFlags(t *testing.T) {
|
||||||
for _, f := range goodLinkerFlags {
|
for _, f := range goodLinkerFlags {
|
||||||
if err := checkLinkerFlags("test", "test", f); err != nil {
|
if err := checkLinkerFlags("test", "test", f); err != nil {
|
||||||
@ -291,31 +272,6 @@ func TestCheckLinkerFlags(t *testing.T) {
|
|||||||
t.Errorf("missing error for %q", f)
|
t.Errorf("missing error for %q", f)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
goos := cfg.Goos
|
|
||||||
|
|
||||||
cfg.Goos = "darwin"
|
|
||||||
for _, f := range goodLinkerFlagsOnDarwin {
|
|
||||||
if err := checkLinkerFlags("test", "test", f); err != nil {
|
|
||||||
t.Errorf("unexpected error for %q: %v", f, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.Goos = "ios"
|
|
||||||
for _, f := range goodLinkerFlagsOnDarwin {
|
|
||||||
if err := checkLinkerFlags("test", "test", f); err != nil {
|
|
||||||
t.Errorf("unexpected error for %q: %v", f, err)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.Goos = "linux"
|
|
||||||
for _, f := range goodLinkerFlagsOnDarwin {
|
|
||||||
if err := checkLinkerFlags("test", "test", f); err == nil {
|
|
||||||
t.Errorf("missing error for %q", f)
|
|
||||||
}
|
|
||||||
}
|
|
||||||
|
|
||||||
cfg.Goos = goos
|
|
||||||
}
|
}
|
||||||
|
|
||||||
func TestCheckFlagAllowDisallow(t *testing.T) {
|
func TestCheckFlagAllowDisallow(t *testing.T) {
|
||||||
|
@ -60,7 +60,7 @@ func OpenInRoot(dir, name string) (*File, error) {
|
|||||||
// - When GOOS=plan9 or GOOS=js, Root does not track directories across renames.
|
// - When GOOS=plan9 or GOOS=js, Root does not track directories across renames.
|
||||||
// On these platforms, a Root references a directory name, not a file descriptor.
|
// On these platforms, a Root references a directory name, not a file descriptor.
|
||||||
type Root struct {
|
type Root struct {
|
||||||
root root
|
root *root
|
||||||
}
|
}
|
||||||
|
|
||||||
const (
|
const (
|
||||||
|
@ -49,7 +49,7 @@ func newRoot(name string) (*Root, error) {
|
|||||||
if !fi.IsDir() {
|
if !fi.IsDir() {
|
||||||
return nil, errors.New("not a directory")
|
return nil, errors.New("not a directory")
|
||||||
}
|
}
|
||||||
return &Root{root{name: name}}, nil
|
return &Root{&root{name: name}}, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
func (r *root) Close() error {
|
func (r *root) Close() error {
|
||||||
|
@ -48,11 +48,11 @@ func newRoot(fd int, name string) (*Root, error) {
|
|||||||
syscall.CloseOnExec(fd)
|
syscall.CloseOnExec(fd)
|
||||||
}
|
}
|
||||||
|
|
||||||
r := &Root{root{
|
r := &Root{&root{
|
||||||
fd: fd,
|
fd: fd,
|
||||||
name: name,
|
name: name,
|
||||||
}}
|
}}
|
||||||
runtime.SetFinalizer(&r.root, (*root).Close)
|
runtime.SetFinalizer(r.root, (*root).Close)
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -105,11 +105,11 @@ func newRoot(fd syscall.Handle, name string) (*Root, error) {
|
|||||||
return nil, &PathError{Op: "open", Path: name, Err: errors.New("not a directory")}
|
return nil, &PathError{Op: "open", Path: name, Err: errors.New("not a directory")}
|
||||||
}
|
}
|
||||||
|
|
||||||
r := &Root{root{
|
r := &Root{&root{
|
||||||
fd: fd,
|
fd: fd,
|
||||||
name: name,
|
name: name,
|
||||||
}}
|
}}
|
||||||
runtime.SetFinalizer(&r.root, (*root).Close)
|
runtime.SetFinalizer(r.root, (*root).Close)
|
||||||
return r, nil
|
return r, nil
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -56,6 +56,9 @@ import (
|
|||||||
// referenced object. Typically, this batching only happens for tiny
|
// referenced object. Typically, this batching only happens for tiny
|
||||||
// (on the order of 16 bytes or less) and pointer-free objects.
|
// (on the order of 16 bytes or less) and pointer-free objects.
|
||||||
type Pointer[T any] struct {
|
type Pointer[T any] struct {
|
||||||
|
// Mention T in the type definition to prevent conversions
|
||||||
|
// between Pointer types, like we do for sync/atomic.Pointer.
|
||||||
|
_ [0]*T
|
||||||
u unsafe.Pointer
|
u unsafe.Pointer
|
||||||
}
|
}
|
||||||
|
|
||||||
@ -69,7 +72,7 @@ func Make[T any](ptr *T) Pointer[T] {
|
|||||||
u = runtime_registerWeakPointer(unsafe.Pointer(ptr))
|
u = runtime_registerWeakPointer(unsafe.Pointer(ptr))
|
||||||
}
|
}
|
||||||
runtime.KeepAlive(ptr)
|
runtime.KeepAlive(ptr)
|
||||||
return Pointer[T]{u}
|
return Pointer[T]{u: u}
|
||||||
}
|
}
|
||||||
|
|
||||||
// Value returns the original pointer used to create the weak pointer.
|
// Value returns the original pointer used to create the weak pointer.
|
||||||
|
@ -6,10 +6,12 @@ package weak_test
|
|||||||
|
|
||||||
import (
|
import (
|
||||||
"context"
|
"context"
|
||||||
|
"internal/goarch"
|
||||||
"runtime"
|
"runtime"
|
||||||
"sync"
|
"sync"
|
||||||
"testing"
|
"testing"
|
||||||
"time"
|
"time"
|
||||||
|
"unsafe"
|
||||||
"weak"
|
"weak"
|
||||||
)
|
)
|
||||||
|
|
||||||
@ -155,6 +157,14 @@ func TestPointerFinalizer(t *testing.T) {
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
func TestPointerSize(t *testing.T) {
|
||||||
|
var p weak.Pointer[T]
|
||||||
|
size := unsafe.Sizeof(p)
|
||||||
|
if size != goarch.PtrSize {
|
||||||
|
t.Errorf("weak.Pointer[T] size = %d, want %d", size, goarch.PtrSize)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
// Regression test for issue 69210.
|
// Regression test for issue 69210.
|
||||||
//
|
//
|
||||||
// Weak-to-strong conversions must shade the new strong pointer, otherwise
|
// Weak-to-strong conversions must shade the new strong pointer, otherwise
|
||||||
|
24
test/weak.go
Normal file
24
test/weak.go
Normal file
@ -0,0 +1,24 @@
|
|||||||
|
// errorcheck
|
||||||
|
|
||||||
|
// Copyright 2025 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.
|
||||||
|
|
||||||
|
// Test weak pointers.
|
||||||
|
|
||||||
|
package p
|
||||||
|
|
||||||
|
import (
|
||||||
|
"runtime"
|
||||||
|
"weak"
|
||||||
|
)
|
||||||
|
|
||||||
|
// Adapted from example in https://github.com/golang/go/issues/67552#issuecomment-2639661220
|
||||||
|
func conversion() {
|
||||||
|
p := "hello"
|
||||||
|
a := weak.Make(&p)
|
||||||
|
b := (weak.Pointer[*byte])(a) // ERROR "cannot convert a \(variable of struct type weak\.Pointer\[string\]\) to type weak.Pointer\[\*byte\]"
|
||||||
|
c := b.Value()
|
||||||
|
println(**c)
|
||||||
|
runtime.KeepAlive(p)
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user