mirror of
https://github.com/golang/go.git
synced 2025-12-08 06:10:04 +00:00
cmd/cgo: support large unsigned macro again
The approach of https://golang.org/cl/43476 turned out incorrect. The problem is that the sniff introduced by the CL only work for simple expression. And when it fails it fallback to uint64, not int64, which breaks backward compatibility. In this CL, we use DWARF for guessing kind instead. That should be more reliable than previous approach. And importanly, it fallbacks to int64 even if it fails to guess kind. Fixes #21708 Change-Id: I39a18cb2efbe4faa9becdcf53d5ac68dba180d46 Reviewed-on: https://go-review.googlesource.com/60510 Run-TryBot: Ian Lance Taylor <iant@golang.org> TryBot-Result: Gobot Gobot <gobot@golang.org> Reviewed-by: Ian Lance Taylor <iant@golang.org>
This commit is contained in:
parent
51e92d7261
commit
f74b52cf50
5 changed files with 29 additions and 36 deletions
|
|
@ -81,5 +81,6 @@ func Test18720(t *testing.T) { test18720(t) }
|
||||||
func Test20266(t *testing.T) { test20266(t) }
|
func Test20266(t *testing.T) { test20266(t) }
|
||||||
func Test20129(t *testing.T) { test20129(t) }
|
func Test20129(t *testing.T) { test20129(t) }
|
||||||
func Test20910(t *testing.T) { test20910(t) }
|
func Test20910(t *testing.T) { test20910(t) }
|
||||||
|
func Test21708(t *testing.T) { test21708(t) }
|
||||||
|
|
||||||
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
|
func BenchmarkCgoCall(b *testing.B) { benchCgoCall(b) }
|
||||||
|
|
|
||||||
16
misc/cgo/test/issue21708.go
Normal file
16
misc/cgo/test/issue21708.go
Normal file
|
|
@ -0,0 +1,16 @@
|
||||||
|
// 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
|
||||||
|
|
||||||
|
// #include <stdint.h>
|
||||||
|
// #define CAST_TO_INT64 (int64_t)(-1)
|
||||||
|
import "C"
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func test21708(t *testing.T) {
|
||||||
|
if got, want := C.CAST_TO_INT64, -1; got != want {
|
||||||
|
t.Errorf("C.CAST_TO_INT64 == %v, expected %v", got, want)
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
@ -419,11 +419,6 @@ identifiers C.foo, cgo generates this C program:
|
||||||
void __cgo_f_1_4(void) { static const double __cgo_undefined__4 = (foo); }
|
void __cgo_f_1_4(void) { static const double __cgo_undefined__4 = (foo); }
|
||||||
#line 1 "not-str-lit"
|
#line 1 "not-str-lit"
|
||||||
void __cgo_f_1_5(void) { static const char __cgo_undefined__5[] = (foo); }
|
void __cgo_f_1_5(void) { static const char __cgo_undefined__5[] = (foo); }
|
||||||
#line 1 "not-signed-int-const"
|
|
||||||
#if 0 < -(foo)
|
|
||||||
#line 1 "not-signed-int-const"
|
|
||||||
#error found unsigned int
|
|
||||||
#endif
|
|
||||||
|
|
||||||
This program will not compile, but cgo can use the presence or absence
|
This program will not compile, but cgo can use the presence or absence
|
||||||
of an error message on a given line to deduce the information it
|
of an error message on a given line to deduce the information it
|
||||||
|
|
|
||||||
|
|
@ -301,18 +301,12 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||||
// void __cgo_f_xxx_4(void) { static const double __cgo_undefined__4 = (name); }
|
// void __cgo_f_xxx_4(void) { static const double __cgo_undefined__4 = (name); }
|
||||||
// #line xxx "not-str-lit"
|
// #line xxx "not-str-lit"
|
||||||
// void __cgo_f_xxx_5(void) { static const char __cgo_undefined__5[] = (name); }
|
// void __cgo_f_xxx_5(void) { static const char __cgo_undefined__5[] = (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.
|
||||||
|
|
@ -331,18 +325,12 @@ 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 __cgo_undefined__4 = (%s); }\n"+
|
"void __cgo_f_%d_4(void) { static const double __cgo_undefined__4 = (%s); }\n"+
|
||||||
"#line %d \"not-str-lit\"\n"+
|
"#line %d \"not-str-lit\"\n"+
|
||||||
"void __cgo_f_%d_5(void) { static const char __cgo_undefined__5[] = (%s); }\n"+
|
"void __cgo_f_%d_5(void) { static const char __cgo_undefined__5[] = (%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"+
|
||||||
|
|
@ -361,7 +349,6 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||||
notNumConst
|
notNumConst
|
||||||
notStrLiteral
|
notStrLiteral
|
||||||
notDeclared
|
notDeclared
|
||||||
notSignedIntConst
|
|
||||||
)
|
)
|
||||||
sawUnmatchedErrors := false
|
sawUnmatchedErrors := false
|
||||||
for _, line := range strings.Split(stderr, "\n") {
|
for _, line := range strings.Split(stderr, "\n") {
|
||||||
|
|
@ -415,8 +402,6 @@ 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
|
|
||||||
default:
|
default:
|
||||||
if isError {
|
if isError {
|
||||||
sawUnmatchedErrors = true
|
sawUnmatchedErrors = true
|
||||||
|
|
@ -432,15 +417,11 @@ func (p *Package) guessKinds(f *File) []*Name {
|
||||||
}
|
}
|
||||||
|
|
||||||
for i, n := range names {
|
for i, n := range names {
|
||||||
switch sniff[i] &^ notSignedIntConst {
|
switch sniff[i] {
|
||||||
default:
|
default:
|
||||||
error_(f.NamePos[n], "could not determine kind of name for C.%s", fixGo(n.Go))
|
error_(f.NamePos[n], "could not determine kind of name for C.%s", fixGo(n.Go))
|
||||||
case notStrLiteral | notType:
|
case notStrLiteral | notType:
|
||||||
if sniff[i]¬SignedIntConst != 0 {
|
|
||||||
n.Kind = "uconst"
|
|
||||||
} else {
|
|
||||||
n.Kind = "iconst"
|
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:
|
||||||
|
|
@ -485,7 +466,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" || n.Kind == "uconst" {
|
if n.Kind == "iconst" {
|
||||||
fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
|
fmt.Fprintf(&b, "enum { __cgo_enum__%d = %s };\n", i, n.C)
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
@ -494,7 +475,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" || n.Kind == "uconst" {
|
if n.Kind == "iconst" {
|
||||||
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")
|
||||||
|
|
@ -592,11 +573,11 @@ func (p *Package) loadDWARF(f *File, names []*Name) {
|
||||||
switch n.Kind {
|
switch n.Kind {
|
||||||
case "iconst":
|
case "iconst":
|
||||||
if i < len(ints) {
|
if i < len(ints) {
|
||||||
|
if _, ok := types[i].(*dwarf.UintType); ok {
|
||||||
|
n.Const = fmt.Sprintf("%#x", uint64(ints[i]))
|
||||||
|
} else {
|
||||||
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) {
|
||||||
|
|
|
||||||
|
|
@ -89,7 +89,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", "uconst", "fconst", "sconst", "type", "var", "fpvar", "func", "macro", "not-type"
|
Kind string // "iconst", "fconst", "sconst", "type", "var", "fpvar", "func", "macro", "not-type"
|
||||||
Type *Type // the type of xxx
|
Type *Type // the type of xxx
|
||||||
FuncType *FuncType
|
FuncType *FuncType
|
||||||
AddError bool
|
AddError bool
|
||||||
|
|
@ -101,7 +101,7 @@ 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", "uconst", "fconst" or "sconst"
|
// IsConst reports whether Kind is either "iconst", "fconst" or "sconst"
|
||||||
func (n *Name) IsConst() bool {
|
func (n *Name) IsConst() bool {
|
||||||
return strings.HasSuffix(n.Kind, "const")
|
return strings.HasSuffix(n.Kind, "const")
|
||||||
}
|
}
|
||||||
|
|
|
||||||
Loading…
Add table
Add a link
Reference in a new issue