diff --git a/cgo/cgo_test.go b/cgo/cgo_test.go index 410e7108..a2dbbd52 100644 --- a/cgo/cgo_test.go +++ b/cgo/cgo_test.go @@ -11,6 +11,7 @@ import ( "go/types" "io/ioutil" "path/filepath" + "runtime" "strings" "testing" ) @@ -21,7 +22,7 @@ var flagUpdate = flag.Bool("update", false, "Update images based on test output. func TestCGo(t *testing.T) { var cflags = []string{"--target=armv6m-none-eabi"} - for _, name := range []string{"basic", "types"} { + for _, name := range []string{"basic", "errors", "types"} { name := name // avoid a race condition t.Run(name, func(t *testing.T) { t.Parallel() @@ -35,23 +36,19 @@ func TestCGo(t *testing.T) { } // Process the AST with CGo. - cgoAST, errs := Process([]*ast.File{f}, "testdata", fset, cflags) - for _, err := range errs { - t.Errorf("error during CGo processing: %v", err) - } + cgoAST, cgoErrors := Process([]*ast.File{f}, "testdata", fset, cflags) // Check the AST for type errors. - hasTypeError := false + var typecheckErrors []error config := types.Config{ Error: func(err error) { - t.Error("typecheck error:", err) - hasTypeError = true + typecheckErrors = append(typecheckErrors, err) }, Importer: simpleImporter{}, Sizes: types.SizesFor("gccgo", "arm"), } _, err = config.Check("", fset, []*ast.File{f, cgoAST}, nil) - if err != nil && !hasTypeError { + if err != nil && len(typecheckErrors) == 0 { // Only report errors when no type errors are found (an // unexpected condition). t.Error(err) @@ -61,6 +58,20 @@ func TestCGo(t *testing.T) { // becomes easier to read (and will hopefully change less with CGo // changes). buf := &bytes.Buffer{} + if len(cgoErrors) != 0 { + buf.WriteString("// CGo errors:\n") + for _, err := range cgoErrors { + buf.WriteString(formatDiagnostic(err)) + } + buf.WriteString("\n") + } + if len(typecheckErrors) != 0 { + buf.WriteString("// Type checking errors after CGo processing:\n") + for _, err := range typecheckErrors { + buf.WriteString(formatDiagnostic(err)) + } + buf.WriteString("\n") + } err = format.Node(buf, fset, cgoAST) if err != nil { t.Errorf("could not write out CGo AST: %v", err) @@ -107,3 +118,14 @@ func (i simpleImporter) Import(path string) (*types.Package, error) { return nil, fmt.Errorf("importer not implemented for package %s", path) } } + +// formatDiagnostics formats the error message to be an indented comment. It +// also fixes Windows path name issues (backward slashes). +func formatDiagnostic(err error) string { + msg := err.Error() + if runtime.GOOS == "windows" { + // Fix Windows path slashes. + msg = strings.Replace(msg, "testdata\\", "testdata/", -1) + } + return "// " + msg + "\n" +} diff --git a/cgo/libclang.go b/cgo/libclang.go index 336122a7..2e918a49 100644 --- a/cgo/libclang.go +++ b/cgo/libclang.go @@ -132,7 +132,6 @@ func (p *cgoPackage) parseFragment(fragment string, cflags []string, posFilename addDiagnostic(C.clang_getDiagnosticInSet(diagnostics, C.uint(j))) } } - return } ref := storedRefs.Put(p) diff --git a/cgo/testdata/errors.go b/cgo/testdata/errors.go new file mode 100644 index 00000000..cdb28cf3 --- /dev/null +++ b/cgo/testdata/errors.go @@ -0,0 +1,33 @@ +package main + +/* +#warning some warning + +typedef struct { + int x; + int y; +} point_t; + +typedef someType noType; // undefined type + +#define SOME_CONST_1 5) // invalid const syntax +#define SOME_CONST_2 6) // const not used (so no error) +#define SOME_CONST_3 1234 // const too large for byte +*/ +import "C" + +// Make sure that errors for the following lines won't change with future +// additions to the CGo preamble. +//line errors.go:100 +var ( + // constant too large + _ C.uint8_t = 2 << 10 + + // z member does not exist + _ C.point_t = C.point_t{z: 3} + + // constant has syntax error + _ = C.SOME_CONST_1 + + _ byte = C.SOME_CONST_3 +) diff --git a/cgo/testdata/errors.out.go b/cgo/testdata/errors.out.go new file mode 100644 index 00000000..ace2390d --- /dev/null +++ b/cgo/testdata/errors.out.go @@ -0,0 +1,43 @@ +// CGo errors: +// testdata/errors.go:4:2: warning: some warning +// testdata/errors.go:11:9: error: unknown type name 'someType' +// testdata/errors.go:13:23: unexpected token ) + +// Type checking errors after CGo processing: +// testdata/errors.go:102: 2 << 10 (untyped int constant 2048) overflows uint8 +// testdata/errors.go:105: unknown field z in struct literal +// testdata/errors.go:108: undeclared name: C.SOME_CONST_1 +// testdata/errors.go:110: C.SOME_CONST_3 (untyped int constant 1234) overflows byte + +package main + +import "unsafe" + +var _ unsafe.Pointer + +const C.SOME_CONST_3 = 1234 + +type C.int16_t = int16 +type C.int32_t = int32 +type C.int64_t = int64 +type C.int8_t = int8 +type C.uint16_t = uint16 +type C.uint32_t = uint32 +type C.uint64_t = uint64 +type C.uint8_t = uint8 +type C.uintptr_t = uintptr +type C.char uint8 +type C.int int32 +type C.long int32 +type C.longlong int64 +type C.schar int8 +type C.short int16 +type C.uchar uint8 +type C.uint uint32 +type C.ulong uint32 +type C.ulonglong uint64 +type C.ushort uint16 +type C.point_t = struct { + x C.int + y C.int +}