mirror of
https://github.com/golang/go
synced 2024-09-05 16:04:50 +00:00
cmd/cgo: support large unsigned macros
Currently, cgo converts integer macros into int64 if it's possible. As a result, some macros which satisfy math.MaxInt64 < x <= math.MaxUint64 will lose their original values. This CL introduces the new probe to check signs, so we can handle signed ints and unsigned ints separately. Fixes #20369 Change-Id: I002ba452a82514b3a87440960473676f842cc9ee Reviewed-on: https://go-review.googlesource.com/43476 Reviewed-by: Ian Lance Taylor <iant@golang.org> Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org>
This commit is contained in:
parent
c20e54533e
commit
7555a45dc2
|
@ -76,5 +76,6 @@ func TestThreadLock(t *testing.T) { testThreadLockFunc(t) }
|
||||||
func TestCheckConst(t *testing.T) { testCheckConst(t) }
|
func TestCheckConst(t *testing.T) { testCheckConst(t) }
|
||||||
func Test17537(t *testing.T) { test17537(t) }
|
func Test17537(t *testing.T) { test17537(t) }
|
||||||
func Test18126(t *testing.T) { test18126(t) }
|
func Test18126(t *testing.T) { test18126(t) }
|
||||||
|
func Test20369(t *testing.T) { test20369(t) }
|
||||||
|
|
||||||
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
|
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
|
||||||
|
|
20
misc/cgo/test/issue20369.go
Normal file
20
misc/cgo/test/issue20369.go
Normal file
|
@ -0,0 +1,20 @@
|
||||||
|
// Copyright 2017 The Go Authors. All rights reserved.
|
||||||
|
// Use of this source code is governed by a BSD-style
|
||||||
|
// license that can be found in the LICENSE file.
|
||||||
|
|
||||||
|
package cgotest
|
||||||
|
|
||||||
|
/*
|
||||||
|
#define UINT64_MAX 18446744073709551615ULL
|
||||||
|
*/
|
||||||
|
import "C"
|
||||||
|
import (
|
||||||
|
"math"
|
||||||
|
"testing"
|
||||||
|
)
|
||||||
|
|
||||||
|
func test20369(t *testing.T) {
|
||||||
|
if C.UINT64_MAX != math.MaxUint64 {
|
||||||
|
t.Fatalf("got %v, want %v", uint64(C.UINT64_MAX), uint64(math.MaxUint64))
|
||||||
|
}
|
||||||
|
}
|
|
@ -305,12 +305,18 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||||
// void __cgo_f_xxx_4(void) { static const double x = (name); }
|
// void __cgo_f_xxx_4(void) { static const double x = (name); }
|
||||||
// #line xxx "not-str-lit"
|
// #line xxx "not-str-lit"
|
||||||
// void __cgo_f_xxx_5(void) { static const char x[] = (name); }
|
// void __cgo_f_xxx_5(void) { static const char x[] = (name); }
|
||||||
|
// #line xxx "not-signed-int-const"
|
||||||
|
// #if 0 < -(name)
|
||||||
|
// #line xxx "not-signed-int-const"
|
||||||
|
// #error found unsigned int
|
||||||
|
// #endif
|
||||||
//
|
//
|
||||||
// If we see an error at not-declared:xxx, the corresponding name is not declared.
|
// If we see an error at not-declared:xxx, the corresponding name is not declared.
|
||||||
// If we see an error at not-type:xxx, the corresponding name is a type.
|
// If we see an error at not-type:xxx, the corresponding name is a type.
|
||||||
// If we see an error at not-int-const:xxx, the corresponding name is not an integer constant.
|
// If we see an error at not-int-const:xxx, the corresponding name is not an integer constant.
|
||||||
// If we see an error at not-num-const:xxx, the corresponding name is not a number constant.
|
// If we see an error at not-num-const:xxx, the corresponding name is not a number constant.
|
||||||
// If we see an error at not-str-lit:xxx, the corresponding name is not a string literal.
|
// If we see an error at not-str-lit:xxx, the corresponding name is not a string literal.
|
||||||
|
// If we see an error at not-signed-int-const:xxx, the corresponding name is not a signed integer literal.
|
||||||
//
|
//
|
||||||
// The specific input forms are chosen so that they are valid C syntax regardless of
|
// The specific input forms are chosen so that they are valid C syntax regardless of
|
||||||
// whether name denotes a type or an expression.
|
// whether name denotes a type or an expression.
|
||||||
|
@ -329,12 +335,19 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||||
"#line %d \"not-num-const\"\n"+
|
"#line %d \"not-num-const\"\n"+
|
||||||
"void __cgo_f_%d_4(void) { static const double x = (%s); }\n"+
|
"void __cgo_f_%d_4(void) { static const double x = (%s); }\n"+
|
||||||
"#line %d \"not-str-lit\"\n"+
|
"#line %d \"not-str-lit\"\n"+
|
||||||
"void __cgo_f_%d_5(void) { static const char s[] = (%s); }\n",
|
"void __cgo_f_%d_5(void) { static const char s[] = (%s); }\n"+
|
||||||
|
"#line %d \"not-signed-int-const\"\n"+
|
||||||
|
"#if 0 < (%s)\n"+
|
||||||
|
"#line %d \"not-signed-int-const\"\n"+
|
||||||
|
"#error found unsigned int\n"+
|
||||||
|
"#endif\n",
|
||||||
i+1, i+1, n.C,
|
i+1, i+1, n.C,
|
||||||
i+1, i+1, n.C,
|
i+1, i+1, n.C,
|
||||||
i+1, i+1, n.C,
|
i+1, i+1, n.C,
|
||||||
i+1, i+1, n.C,
|
i+1, i+1, n.C,
|
||||||
i+1, i+1, n.C)
|
i+1, i+1, n.C,
|
||||||
|
i+1, n.C, i+1,
|
||||||
|
)
|
||||||
}
|
}
|
||||||
fmt.Fprintf(&b, "#line 1 \"completed\"\n"+
|
fmt.Fprintf(&b, "#line 1 \"completed\"\n"+
|
||||||
"int __cgo__1 = __cgo__2;\n")
|
"int __cgo__1 = __cgo__2;\n")
|
||||||
|
@ -352,6 +365,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||||
notNumConst
|
notNumConst
|
||||||
notStrLiteral
|
notStrLiteral
|
||||||
notDeclared
|
notDeclared
|
||||||
|
notSignedIntConst
|
||||||
)
|
)
|
||||||
for _, line := range strings.Split(stderr, "\n") {
|
for _, line := range strings.Split(stderr, "\n") {
|
||||||
if !strings.Contains(line, ": error:") {
|
if !strings.Contains(line, ": error:") {
|
||||||
|
@ -395,6 +409,8 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||||
sniff[i] |= notNumConst
|
sniff[i] |= notNumConst
|
||||||
case "not-str-lit":
|
case "not-str-lit":
|
||||||
sniff[i] |= notStrLiteral
|
sniff[i] |= notStrLiteral
|
||||||
|
case "not-signed-int-const":
|
||||||
|
sniff[i] |= notSignedIntConst
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
@ -403,11 +419,15 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, n := range names {
|
for i, n := range names {
|
||||||
switch sniff[i] {
|
switch sniff[i] &^ notSignedIntConst {
|
||||||
default:
|
default:
|
||||||
error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
|
error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
|
||||||
case notStrLiteral | notType:
|
case notStrLiteral | notType:
|
||||||
n.Kind = "iconst"
|
if sniff[i]¬SignedIntConst != 0 {
|
||||||
|
n.Kind = "uconst"
|
||||||
|
} else {
|
||||||
|
n.Kind = "iconst"
|
||||||
|
}
|
||||||
case notIntConst | notStrLiteral | notType:
|
case notIntConst | notStrLiteral | notType:
|
||||||
n.Kind = "fconst"
|
n.Kind = "fconst"
|
||||||
case notIntConst | notNumConst | notType:
|
case notIntConst | notNumConst | notType:
|
||||||
|
@ -452,7 +472,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
|
||||||
b.WriteString("#line 1 \"cgo-dwarf-inference\"\n")
|
b.WriteString("#line 1 \"cgo-dwarf-inference\"\n")
|
||||||
for i, n := range names {
|
for i, n := range names {
|
||||||
fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i)
|
fmt.Fprintf(&b, "__typeof__(%s) *__cgo__%d;\n", n.C, i)
|
||||||
if n.Kind == "iconst" {
|
if n.Kind == "iconst" || n.Kind == "uconst" {
|
||||||
fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
|
fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
@ -461,7 +481,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
|
||||||
// so we can read them out of the object file.
|
// so we can read them out of the object file.
|
||||||
fmt.Fprintf(&b, "long long __cgodebug_ints[] = {\n")
|
fmt.Fprintf(&b, "long long __cgodebug_ints[] = {\n")
|
||||||
for _, n := range names {
|
for _, n := range names {
|
||||||
if n.Kind == "iconst" {
|
if n.Kind == "iconst" || n.Kind == "uconst" {
|
||||||
fmt.Fprintf(&b, "\t%s,\n", n.C)
|
fmt.Fprintf(&b, "\t%s,\n", n.C)
|
||||||
} else {
|
} else {
|
||||||
fmt.Fprintf(&b, "\t0,\n")
|
fmt.Fprintf(&b, "\t0,\n")
|
||||||
|
@ -564,6 +584,10 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
|
||||||
if i < len(ints) {
|
if i < len(ints) {
|
||||||
n.Const = fmt.Sprintf("%#x", ints[i])
|
n.Const = fmt.Sprintf("%#x", ints[i])
|
||||||
}
|
}
|
||||||
|
case "uconst":
|
||||||
|
if i < len(ints) {
|
||||||
|
n.Const = fmt.Sprintf("%#x", uint64(ints[i]))
|
||||||
|
}
|
||||||
case "fconst":
|
case "fconst":
|
||||||
if i < len(floats) {
|
if i < len(floats) {
|
||||||
n.Const = fmt.Sprintf("%f", floats[i])
|
n.Const = fmt.Sprintf("%f", floats[i])
|
||||||
|
|
|
@ -88,7 +88,7 @@ type Name struct {
|
||||||
Mangle string // name used in generated Go
|
Mangle string // name used in generated Go
|
||||||
C string // name used in C
|
C string // name used in C
|
||||||
Define string // #define expansion
|
Define string // #define expansion
|
||||||
Kind string // "iconst", "fconst", "sconst", "type", "var", "fpvar", "func", "not-type"
|
Kind string // "iconst", "uconst", "fconst", "sconst", "type", "var", "fpvar", "func", "not-type"
|
||||||
Type *Type // the type of xxx
|
Type *Type // the type of xxx
|
||||||
FuncType *FuncType
|
FuncType *FuncType
|
||||||
AddError bool
|
AddError bool
|
||||||
|
@ -100,9 +100,9 @@ func (n *Name) IsVar() bool {
|
||||||
return n.Kind == "var" || n.Kind == "fpvar"
|
return n.Kind == "var" || n.Kind == "fpvar"
|
||||||
}
|
}
|
||||||
|
|
||||||
// IsConst reports whether Kind is either "iconst", "fconst" or "sconst"
|
// IsConst reports whether Kind is either "iconst", "uconst", "fconst" or "sconst"
|
||||||
func (n *Name) IsConst() bool {
|
func (n *Name) IsConst() bool {
|
||||||
return n.Kind == "iconst" || n.Kind == "fconst" || n.Kind == "sconst"
|
return strings.HasSuffix(n.Kind, "const")
|
||||||
}
|
}
|
||||||
|
|
||||||
// A ExpFunc is an exported function, callable from C.
|
// A ExpFunc is an exported function, callable from C.
|
||||||
|
|
Loading…
Reference in a new issue