]> Cypherpunks repositories - gostls13.git/commitdiff
cmd/cgo: support large unsigned macros
authorHiroshi Ioka <hirochachacha@gmail.com>
Tue, 16 May 2017 12:52:41 +0000 (21:52 +0900)
committerIan Lance Taylor <iant@golang.org>
Wed, 17 May 2017 14:42:29 +0000 (14:42 +0000)
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>

misc/cgo/test/cgo_test.go
misc/cgo/test/issue20369.go [new file with mode: 0644]
src/cmd/cgo/gcc.go
src/cmd/cgo/main.go

index a6de999752b4ff0d6cf14da4ff5caf0f5e61b55c..b0afb076339e571e81e11e9702d6b5515dd17fd7 100644 (file)
@@ -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) }
diff --git a/misc/cgo/test/issue20369.go b/misc/cgo/test/issue20369.go
new file mode 100644 (file)
index 0000000..37b4b78
--- /dev/null
@@ -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))
+       }
+}
index 3b6d4580de3eabcdc3f864cb0969b6d761b6c4c5..2e570bb5b05496504f7dab807e6a328815f99115 100644 (file)
@@ -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]&notSignedIntConst != 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])
index 4a60ac5f6e0de95cd8403632610c52e4297ae9b4..3dc3d141b74d1c7a71732b841dc98e30cafc0b50 100644 (file)
@@ -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.