mirror of
https://github.com/golang/go
synced 2024-11-26 03:27:58 -07:00
cmd/cgo: use C exact-width integer types to represent Go types
The exact-width integer types are required to use two’s complement representation and may not have padding bits, cf. §7.20.1.1/1 in the C11 standard or https://en.cppreference.com/w/c/types/integer. This ensures that they have the same domain and representation as the corresponding Go types. Fixes #29878
This commit is contained in:
parent
0a04c0430e
commit
546a2cc3f1
@ -56,6 +56,7 @@ func Test25143(t *testing.T) { test25143(t) }
|
|||||||
func Test26066(t *testing.T) { test26066(t) }
|
func Test26066(t *testing.T) { test26066(t) }
|
||||||
func Test27660(t *testing.T) { test27660(t) }
|
func Test27660(t *testing.T) { test27660(t) }
|
||||||
func Test28896(t *testing.T) { test28896(t) }
|
func Test28896(t *testing.T) { test28896(t) }
|
||||||
|
func Test29878(t *testing.T) { test29878(t) }
|
||||||
func Test30065(t *testing.T) { test30065(t) }
|
func Test30065(t *testing.T) { test30065(t) }
|
||||||
func TestAlign(t *testing.T) { testAlign(t) }
|
func TestAlign(t *testing.T) { testAlign(t) }
|
||||||
func TestAtol(t *testing.T) { testAtol(t) }
|
func TestAtol(t *testing.T) { testAtol(t) }
|
||||||
|
20
misc/cgo/test/issue29878.go
Normal file
20
misc/cgo/test/issue29878.go
Normal file
@ -0,0 +1,20 @@
|
|||||||
|
// Copyright 2019 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>
|
||||||
|
// uint64_t issue29878exported(int8_t); // prototype must match
|
||||||
|
// int16_t issue29878function(uint32_t arg) { return issue29878exported(arg); }
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
import "testing"
|
||||||
|
|
||||||
|
func test29878(t *testing.T) {
|
||||||
|
const arg uint32 = 123 // fits into all integer types
|
||||||
|
var ret int16 = C.issue29878function(arg) // no conversions needed
|
||||||
|
if int64(ret) != int64(arg) {
|
||||||
|
t.Errorf("return value unexpected: got %d, want %d", ret, arg)
|
||||||
|
}
|
||||||
|
}
|
12
misc/cgo/test/issue29878export.go
Normal file
12
misc/cgo/test/issue29878export.go
Normal file
@ -0,0 +1,12 @@
|
|||||||
|
// Copyright 2019 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
|
||||||
|
|
||||||
|
import "C"
|
||||||
|
|
||||||
|
//export issue29878exported
|
||||||
|
func issue29878exported(arg int8) uint64 {
|
||||||
|
return uint64(arg)
|
||||||
|
}
|
@ -148,6 +148,8 @@ C.long, C.ulong (unsigned long), C.longlong (long long),
|
|||||||
C.ulonglong (unsigned long long), C.float, C.double,
|
C.ulonglong (unsigned long long), C.float, C.double,
|
||||||
C.complexfloat (complex float), and C.complexdouble (complex double).
|
C.complexfloat (complex float), and C.complexdouble (complex double).
|
||||||
The C type void* is represented by Go's unsafe.Pointer.
|
The C type void* is represented by Go's unsafe.Pointer.
|
||||||
|
The C sized integer types (int8_t, uint8_t, …) are represented by their Go
|
||||||
|
counterparts (int8, uint8, …).
|
||||||
The C types __int128_t and __uint128_t are represented by [16]byte.
|
The C types __int128_t and __uint128_t are represented by [16]byte.
|
||||||
|
|
||||||
A few special C types which would normally be represented by a pointer
|
A few special C types which would normally be represented by a pointer
|
||||||
@ -296,7 +298,7 @@ Go functions can be exported for use by C code in the following way:
|
|||||||
|
|
||||||
They will be available in the C code as:
|
They will be available in the C code as:
|
||||||
|
|
||||||
extern int64 MyFunction(int arg1, int arg2, GoString arg3);
|
extern int64_t MyFunction(int arg1, int arg2, GoString arg3);
|
||||||
extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3);
|
extern struct MyFunction2_return MyFunction2(int arg1, int arg2, GoString arg3);
|
||||||
|
|
||||||
found in the _cgo_export.h generated header, after any preambles
|
found in the _cgo_export.h generated header, after any preambles
|
||||||
|
@ -23,6 +23,7 @@ import (
|
|||||||
"internal/xcoff"
|
"internal/xcoff"
|
||||||
"math"
|
"math"
|
||||||
"os"
|
"os"
|
||||||
|
"regexp"
|
||||||
"strconv"
|
"strconv"
|
||||||
"strings"
|
"strings"
|
||||||
"unicode"
|
"unicode"
|
||||||
@ -2046,6 +2047,8 @@ type typeConv struct {
|
|||||||
|
|
||||||
ptrSize int64
|
ptrSize int64
|
||||||
intSize int64
|
intSize int64
|
||||||
|
|
||||||
|
exactWidthIntegerTypes map[string]*Type
|
||||||
}
|
}
|
||||||
|
|
||||||
var tagGen int
|
var tagGen int
|
||||||
@ -2088,6 +2091,21 @@ func (c *typeConv) Init(ptrSize, intSize int64) {
|
|||||||
} else {
|
} else {
|
||||||
c.goVoidPtr = c.Ident("unsafe.Pointer")
|
c.goVoidPtr = c.Ident("unsafe.Pointer")
|
||||||
}
|
}
|
||||||
|
|
||||||
|
c.exactWidthIntegerTypes = make(map[string]*Type)
|
||||||
|
for _, t := range []ast.Expr{
|
||||||
|
c.int8, c.int16, c.int32, c.int64,
|
||||||
|
c.uint8, c.uint16, c.uint32, c.uint64,
|
||||||
|
} {
|
||||||
|
name := t.(*ast.Ident).Name
|
||||||
|
u := new(Type)
|
||||||
|
*u = *goTypes[name]
|
||||||
|
if u.Align > ptrSize {
|
||||||
|
u.Align = ptrSize
|
||||||
|
}
|
||||||
|
u.Go = t
|
||||||
|
c.exactWidthIntegerTypes[name] = u
|
||||||
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
// base strips away qualifiers and typedefs to get the underlying type
|
// base strips away qualifiers and typedefs to get the underlying type
|
||||||
@ -2459,6 +2477,24 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||||||
t.Align = c.ptrSize
|
t.Align = c.ptrSize
|
||||||
break
|
break
|
||||||
}
|
}
|
||||||
|
// Exact-width integer types. These are always compatible with
|
||||||
|
// the corresponding Go types since the C standard requires
|
||||||
|
// them to have no padding bit and use the two’s complement
|
||||||
|
// representation.
|
||||||
|
if exactWidthIntegerType.MatchString(dt.Name) {
|
||||||
|
sub := c.Type(dt.Type, pos)
|
||||||
|
u := c.exactWidthIntegerTypes[strings.TrimSuffix(dt.Name, "_t")]
|
||||||
|
if sub.Size != u.Size {
|
||||||
|
fatalf("%s: unexpected size: %d vs. %d – %s", lineno(pos), sub.Size, u.Size, dtype)
|
||||||
|
}
|
||||||
|
if sub.Align != u.Align {
|
||||||
|
fatalf("%s: unexpected alignment: %d vs. %d – %s", lineno(pos), sub.Align, u.Align, dtype)
|
||||||
|
}
|
||||||
|
t.Size = u.Size
|
||||||
|
t.Align = u.Align
|
||||||
|
t.Go = u.Go
|
||||||
|
break
|
||||||
|
}
|
||||||
name := c.Ident("_Ctype_" + dt.Name)
|
name := c.Ident("_Ctype_" + dt.Name)
|
||||||
goIdent[name.Name] = name
|
goIdent[name.Name] = name
|
||||||
sub := c.Type(dt.Type, pos)
|
sub := c.Type(dt.Type, pos)
|
||||||
@ -2594,6 +2630,8 @@ func (c *typeConv) Type(dtype dwarf.Type, pos token.Pos) *Type {
|
|||||||
return t
|
return t
|
||||||
}
|
}
|
||||||
|
|
||||||
|
var exactWidthIntegerType = regexp.MustCompile(`^u?int(8|16|32|64)_t$`)
|
||||||
|
|
||||||
// isStructUnionClass reports whether the type described by the Go syntax x
|
// isStructUnionClass reports whether the type described by the Go syntax x
|
||||||
// is a struct, union, or class with a tag.
|
// is a struct, union, or class with a tag.
|
||||||
func isStructUnionClass(x ast.Expr) bool {
|
func isStructUnionClass(x ast.Expr) bool {
|
||||||
|
@ -1361,19 +1361,19 @@ func c(repr string, args ...interface{}) *TypeRepr {
|
|||||||
|
|
||||||
// Map predeclared Go types to Type.
|
// Map predeclared Go types to Type.
|
||||||
var goTypes = map[string]*Type{
|
var goTypes = map[string]*Type{
|
||||||
"bool": {Size: 1, Align: 1, C: c("GoUint8")},
|
"bool": {Size: 1, Align: 1, C: c("uint8_t")},
|
||||||
"byte": {Size: 1, Align: 1, C: c("GoUint8")},
|
"byte": {Size: 1, Align: 1, C: c("uint8_t")},
|
||||||
"int": {Size: 0, Align: 0, C: c("GoInt")},
|
"int": {Size: 0, Align: 0, C: c("GoInt")},
|
||||||
"uint": {Size: 0, Align: 0, C: c("GoUint")},
|
"uint": {Size: 0, Align: 0, C: c("GoUint")},
|
||||||
"rune": {Size: 4, Align: 4, C: c("GoInt32")},
|
"rune": {Size: 4, Align: 4, C: c("int32_t")},
|
||||||
"int8": {Size: 1, Align: 1, C: c("GoInt8")},
|
"int8": {Size: 1, Align: 1, C: c("int8_t")},
|
||||||
"uint8": {Size: 1, Align: 1, C: c("GoUint8")},
|
"uint8": {Size: 1, Align: 1, C: c("uint8_t")},
|
||||||
"int16": {Size: 2, Align: 2, C: c("GoInt16")},
|
"int16": {Size: 2, Align: 2, C: c("int16_t")},
|
||||||
"uint16": {Size: 2, Align: 2, C: c("GoUint16")},
|
"uint16": {Size: 2, Align: 2, C: c("uint16_t")},
|
||||||
"int32": {Size: 4, Align: 4, C: c("GoInt32")},
|
"int32": {Size: 4, Align: 4, C: c("int32_t")},
|
||||||
"uint32": {Size: 4, Align: 4, C: c("GoUint32")},
|
"uint32": {Size: 4, Align: 4, C: c("uint32_t")},
|
||||||
"int64": {Size: 8, Align: 8, C: c("GoInt64")},
|
"int64": {Size: 8, Align: 8, C: c("int64_t")},
|
||||||
"uint64": {Size: 8, Align: 8, C: c("GoUint64")},
|
"uint64": {Size: 8, Align: 8, C: c("uint64_t")},
|
||||||
"float32": {Size: 4, Align: 4, C: c("GoFloat32")},
|
"float32": {Size: 4, Align: 4, C: c("GoFloat32")},
|
||||||
"float64": {Size: 8, Align: 8, C: c("GoFloat64")},
|
"float64": {Size: 8, Align: 8, C: c("GoFloat64")},
|
||||||
"complex64": {Size: 8, Align: 4, C: c("GoComplex64")},
|
"complex64": {Size: 8, Align: 4, C: c("GoComplex64")},
|
||||||
@ -1865,16 +1865,10 @@ const gccExportHeaderProlog = `
|
|||||||
#ifndef GO_CGO_PROLOGUE_H
|
#ifndef GO_CGO_PROLOGUE_H
|
||||||
#define GO_CGO_PROLOGUE_H
|
#define GO_CGO_PROLOGUE_H
|
||||||
|
|
||||||
typedef signed char GoInt8;
|
#include <stdint.h>
|
||||||
typedef unsigned char GoUint8;
|
|
||||||
typedef short GoInt16;
|
typedef intGOINTBITS_t GoInt;
|
||||||
typedef unsigned short GoUint16;
|
typedef uintGOINTBITS_t GoUint;
|
||||||
typedef int GoInt32;
|
|
||||||
typedef unsigned int GoUint32;
|
|
||||||
typedef long long GoInt64;
|
|
||||||
typedef unsigned long long GoUint64;
|
|
||||||
typedef GoIntGOINTBITS GoInt;
|
|
||||||
typedef GoUintGOINTBITS GoUint;
|
|
||||||
typedef __SIZE_TYPE__ GoUintptr;
|
typedef __SIZE_TYPE__ GoUintptr;
|
||||||
typedef float GoFloat32;
|
typedef float GoFloat32;
|
||||||
typedef double GoFloat64;
|
typedef double GoFloat64;
|
||||||
|
Loading…
Reference in New Issue
Block a user