mirror of
https://github.com/golang/go
synced 2024-09-28 18:14:29 -06:00
cmd/go: cgo export header to be compatible with MSVC complex types
After CL 379474 has landed, the only remaining cgo export header incompatibility with MSVC is the use of the _Complex macro, which is not supported in MSVC even when it is part of the ISO C99 standard (1). Since MSVC 2015 (2), complex math are supported via _Fcomplex and _Dcomplex, which are equivalent to float _Complex and double _Complex. As MSVC and C complex types have the same memory layout, we should be able to typedef GoComplex64 and GoComplex128 to the appropriate type in MSVC. It is important to note that this CL is not adding MSVC support to cgo. C compilers should still be GCC-compatible. This CL is about allowing to include, without further modifications, a DLL export header generated by cgo, normally using Mingw-W64 compiler, into a MSVC project. This was already possible if the export header changes introduced in this CL were done outside cgo, either manually or in a post-build script. Fixes #36233 1: https://docs.microsoft.com/en-us/cpp/c-runtime-library/complex-math-support 2: https://docs.microsoft.com/en-us/cpp/overview/visual-cpp-language-conformance?c-standard-library-features-1 Change-Id: Iad8f26984b115c728e3b73f3a8334ade7a11cfa1 Reviewed-on: https://go-review.googlesource.com/c/go/+/397134 Reviewed-by: Ian Lance Taylor <iant@golang.org> Trust: Cherry Mui <cherryyz@google.com> Run-TryBot: Cherry Mui <cherryyz@google.com> Auto-Submit: Cherry Mui <cherryyz@google.com> TryBot-Result: Gopher Robot <gobot@golang.org>
This commit is contained in:
parent
3e7ffb862f
commit
3e387528e5
@ -5,6 +5,7 @@
|
||||
package cshared_test
|
||||
|
||||
import (
|
||||
"bufio"
|
||||
"bytes"
|
||||
"debug/elf"
|
||||
"debug/pe"
|
||||
@ -838,3 +839,51 @@ func TestGo2C2Go(t *testing.T) {
|
||||
run(t, goenv, "go", "build", "-o", bin, "./go2c2go/m2")
|
||||
runExe(t, runenv, bin)
|
||||
}
|
||||
|
||||
func TestIssue36233(t *testing.T) {
|
||||
t.Parallel()
|
||||
|
||||
// Test that the export header uses GoComplex64 and GoComplex128
|
||||
// for complex types.
|
||||
|
||||
tmpdir, err := os.MkdirTemp("", "cshared-TestIssue36233")
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
defer os.RemoveAll(tmpdir)
|
||||
|
||||
const exportHeader = "issue36233.h"
|
||||
|
||||
run(t, nil, "go", "tool", "cgo", "-exportheader", exportHeader, "-objdir", tmpdir, "./issue36233/issue36233.go")
|
||||
data, err := os.ReadFile(exportHeader)
|
||||
if err != nil {
|
||||
t.Fatal(err)
|
||||
}
|
||||
|
||||
funcs := []struct{ name, signature string }{
|
||||
{"exportComplex64", "GoComplex64 exportComplex64(GoComplex64 v)"},
|
||||
{"exportComplex128", "GoComplex128 exportComplex128(GoComplex128 v)"},
|
||||
{"exportComplexfloat", "GoComplex64 exportComplexfloat(GoComplex64 v)"},
|
||||
{"exportComplexdouble", "GoComplex128 exportComplexdouble(GoComplex128 v)"},
|
||||
}
|
||||
|
||||
scanner := bufio.NewScanner(bytes.NewReader(data))
|
||||
var found int
|
||||
for scanner.Scan() {
|
||||
b := scanner.Bytes()
|
||||
for _, fn := range funcs {
|
||||
if bytes.Contains(b, []byte(fn.name)) {
|
||||
found++
|
||||
if !bytes.Contains(b, []byte(fn.signature)) {
|
||||
t.Errorf("function signature mismatch; got %q, want %q", b, fn.signature)
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
if err = scanner.Err(); err != nil {
|
||||
t.Errorf("scanner encountered error: %v", err)
|
||||
}
|
||||
if found != len(funcs) {
|
||||
t.Error("missing functions")
|
||||
}
|
||||
}
|
||||
|
29
misc/cgo/testcshared/testdata/issue36233/issue36233.go
vendored
Normal file
29
misc/cgo/testcshared/testdata/issue36233/issue36233.go
vendored
Normal file
@ -0,0 +1,29 @@
|
||||
// Copyright 2022 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 main
|
||||
|
||||
// #include <complex.h>
|
||||
import "C"
|
||||
|
||||
//export exportComplex64
|
||||
func exportComplex64(v complex64) complex64 {
|
||||
return v
|
||||
}
|
||||
|
||||
//export exportComplex128
|
||||
func exportComplex128(v complex128) complex128 {
|
||||
return v
|
||||
}
|
||||
|
||||
//export exportComplexfloat
|
||||
func exportComplexfloat(v C.complexfloat) C.complexfloat {
|
||||
return v
|
||||
}
|
||||
|
||||
//export exportComplexdouble
|
||||
func exportComplexdouble(v C.complexdouble) C.complexdouble {
|
||||
return v
|
||||
}
|
||||
|
||||
func main() {}
|
@ -1399,6 +1399,19 @@ func (p *Package) cgoType(e ast.Expr) *Type {
|
||||
case *ast.ChanType:
|
||||
return &Type{Size: p.PtrSize, Align: p.PtrSize, C: c("GoChan")}
|
||||
case *ast.Ident:
|
||||
goTypesFixup := func(r *Type) *Type {
|
||||
if r.Size == 0 { // int or uint
|
||||
rr := new(Type)
|
||||
*rr = *r
|
||||
rr.Size = p.IntSize
|
||||
rr.Align = p.IntSize
|
||||
r = rr
|
||||
}
|
||||
if r.Align > p.PtrSize {
|
||||
r.Align = p.PtrSize
|
||||
}
|
||||
return r
|
||||
}
|
||||
// Look up the type in the top level declarations.
|
||||
// TODO: Handle types defined within a function.
|
||||
for _, d := range p.Decl {
|
||||
@ -1417,6 +1430,17 @@ func (p *Package) cgoType(e ast.Expr) *Type {
|
||||
}
|
||||
}
|
||||
if def := typedef[t.Name]; def != nil {
|
||||
if defgo, ok := def.Go.(*ast.Ident); ok {
|
||||
switch defgo.Name {
|
||||
case "complex64", "complex128":
|
||||
// MSVC does not support the _Complex keyword
|
||||
// nor the complex macro.
|
||||
// Use GoComplex64 and GoComplex128 instead,
|
||||
// which are typedef-ed to a compatible type.
|
||||
// See go.dev/issues/36233.
|
||||
return goTypesFixup(goTypes[defgo.Name])
|
||||
}
|
||||
}
|
||||
return def
|
||||
}
|
||||
if t.Name == "uintptr" {
|
||||
@ -1430,17 +1454,7 @@ func (p *Package) cgoType(e ast.Expr) *Type {
|
||||
return &Type{Size: 2 * p.PtrSize, Align: p.PtrSize, C: c("GoInterface")}
|
||||
}
|
||||
if r, ok := goTypes[t.Name]; ok {
|
||||
if r.Size == 0 { // int or uint
|
||||
rr := new(Type)
|
||||
*rr = *r
|
||||
rr.Size = p.IntSize
|
||||
rr.Align = p.IntSize
|
||||
r = rr
|
||||
}
|
||||
if r.Align > p.PtrSize {
|
||||
r.Align = p.PtrSize
|
||||
}
|
||||
return r
|
||||
return goTypesFixup(r)
|
||||
}
|
||||
error_(e.Pos(), "unrecognized Go type %s", t.Name)
|
||||
return &Type{Size: 4, Align: 4, C: c("int")}
|
||||
@ -1895,8 +1909,14 @@ typedef GoUintGOINTBITS GoUint;
|
||||
typedef size_t GoUintptr;
|
||||
typedef float GoFloat32;
|
||||
typedef double GoFloat64;
|
||||
#ifdef _MSC_VER
|
||||
#include <complex.h>
|
||||
typedef _Fcomplex GoComplex64;
|
||||
typedef _Dcomplex GoComplex128;
|
||||
#else
|
||||
typedef float _Complex GoComplex64;
|
||||
typedef double _Complex GoComplex128;
|
||||
#endif
|
||||
|
||||
/*
|
||||
static assertion to make sure the file is being used on architecture
|
||||
|
Loading…
Reference in New Issue
Block a user