mirror of
https://github.com/golang/go
synced 2024-10-14 03:43:28 +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 Test17537(t *testing.T) { test17537(t) }
|
||||
func Test18126(t *testing.T) { test18126(t) }
|
||||
func Test20369(t *testing.T) { test20369(t) }
|
||||
|
||||
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); }
|
||||
// #line xxx "not-str-lit"
|
||||
// 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-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-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-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
|
||||
// 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"+
|
||||
"void __cgo_f_%d_4(void) { static const double x = (%s); }\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, n.C, i+1,
|
||||
)
|
||||
}
|
||||
fmt.Fprintf(&b, "#line 1 \"completed\"\n"+
|
||||
"int __cgo__1 = __cgo__2;\n")
|
||||
|
@ -352,6 +365,7 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
notNumConst
|
||||
notStrLiteral
|
||||
notDeclared
|
||||
notSignedIntConst
|
||||
)
|
||||
for _, line := range strings.Split(stderr, "\n") {
|
||||
if !strings.Contains(line, ": error:") {
|
||||
|
@ -395,6 +409,8 @@ func (p *Package) guessKinds(f *File) []*Name {
|
|||
sniff[i] |= notNumConst
|
||||
case "not-str-lit":
|
||||
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 {
|
||||
switch sniff[i] {
|
||||
switch sniff[i] &^ notSignedIntConst {
|
||||
default:
|
||||
error_(token.NoPos, "could not determine kind of name for C.%s", fixGo(n.Go))
|
||||
case notStrLiteral | notType:
|
||||
n.Kind = "iconst"
|
||||
if sniff[i]¬SignedIntConst != 0 {
|
||||
n.Kind = "uconst"
|
||||
} else {
|
||||
n.Kind = "iconst"
|
||||
}
|
||||
case notIntConst | notStrLiteral | notType:
|
||||
n.Kind = "fconst"
|
||||
case notIntConst | notNumConst | notType:
|
||||
|
@ -452,7 +472,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
|
|||
b.WriteString("#line 1 \"cgo-dwarf-inference\"\n")
|
||||
for i, n := range names {
|
||||
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)
|
||||
}
|
||||
}
|
||||
|
@ -461,7 +481,7 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
|
|||
// so we can read them out of the object file.
|
||||
fmt.Fprintf(&b, "long long __cgodebug_ints[] = {\n")
|
||||
for _, n := range names {
|
||||
if n.Kind == "iconst" {
|
||||
if n.Kind == "iconst" || n.Kind == "uconst" {
|
||||
fmt.Fprintf(&b, "\t%s,\n", n.C)
|
||||
} else {
|
||||
fmt.Fprintf(&b, "\t0,\n")
|
||||
|
@ -564,6 +584,10 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
|
|||
if i < len(ints) {
|
||||
n.Const = fmt.Sprintf("%#x", ints[i])
|
||||
}
|
||||
case "uconst":
|
||||
if i < len(ints) {
|
||||
n.Const = fmt.Sprintf("%#x", uint64(ints[i]))
|
||||
}
|
||||
case "fconst":
|
||||
if i < len(floats) {
|
||||
n.Const = fmt.Sprintf("%f", floats[i])
|
||||
|
|
|
@ -88,7 +88,7 @@ type Name struct {
|
|||
Mangle string // name used in generated Go
|
||||
C string // name used in C
|
||||
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
|
||||
FuncType *FuncType
|
||||
AddError bool
|
||||
|
@ -100,9 +100,9 @@ func (n *Name) IsVar() bool {
|
|||
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 {
|
||||
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.
|
||||
|
|
Loading…
Reference in a new issue