This reverts CL 33677.
Reason for revert: NetBSD is broken
Updates #38649
Change-Id: Id60e3c97d3cb4fb0053dea03b95dbbb0b850c883
Reviewed-on: https://go-review.googlesource.com/c/go/+/230038
Run-TryBot: Andrew Bonventre <andybons@golang.org>
Reviewed-by: Robert Griesemer <gri@golang.org>
Reviewed-by: Matthew Dempsky <mdempsky@google.com>
"go/token"
"go/types"
"io"
- "io/ioutil"
"os"
- "os/exec"
"path/filepath"
- "strings"
"sync"
)
var firstHardErr error
conf := types.Config{
IgnoreFuncBodies: true,
+ FakeImportC: true,
// continue type-checking after the first error
Error: func(err error) {
if firstHardErr == nil && !err.(types.Error).Soft {
Importer: p,
Sizes: p.sizes,
}
- if len(bp.CgoFiles) > 0 {
- if p.ctxt.OpenFile != nil {
- // cgo, gcc, pkg-config, etc. do not support
- // build.Context's VFS.
- conf.FakeImportC = true
- } else {
- conf.UsesCgo = true
- file, err := p.cgo(bp)
- if err != nil {
- return nil, err
- }
- files = append(files, file)
- }
- }
-
pkg, err = conf.Check(bp.ImportPath, p.fset, files, nil)
if err != nil {
// If there was a hard error it is possibly unsafe
return files, nil
}
-func (p *Importer) cgo(bp *build.Package) (*ast.File, error) {
- tmpdir, err := ioutil.TempDir("", "srcimporter")
- if err != nil {
- return nil, err
- }
- defer os.RemoveAll(tmpdir)
-
- args := []string{"go", "tool", "cgo", "-objdir", tmpdir}
- if bp.Goroot {
- switch bp.ImportPath {
- case "runtime/cgo":
- args = append(args, "-import_runtime_cgo=false", "-import_syscall=false")
- case "runtime/race":
- args = append(args, "-import_syscall=false")
- }
- }
- args = append(args, "--")
- args = append(args, strings.Fields(os.Getenv("CGO_CPPFLAGS"))...)
- args = append(args, bp.CgoCPPFLAGS...)
- if len(bp.CgoPkgConfig) > 0 {
- cmd := exec.Command("pkg-config", append([]string{"--cflags"}, bp.CgoPkgConfig...)...)
- out, err := cmd.CombinedOutput()
- if err != nil {
- return nil, err
- }
- args = append(args, strings.Fields(string(out))...)
- }
- args = append(args, "-I", tmpdir)
- args = append(args, strings.Fields(os.Getenv("CGO_CFLAGS"))...)
- args = append(args, bp.CgoCFLAGS...)
- args = append(args, bp.CgoFiles...)
-
- cmd := exec.Command(args[0], args[1:]...)
- cmd.Dir = bp.Dir
- if err := cmd.Run(); err != nil {
- return nil, err
- }
-
- return parser.ParseFile(p.fset, filepath.Join(tmpdir, "_cgo_gotypes.go"), nil, 0)
-}
-
// context-controlled file system operations
func (p *Importer) absPath(path string) (string, error) {
func TestIssue24392(t *testing.T) {
testImportPath(t, "go/internal/srcimporter/testdata/issue24392")
}
-
-func TestCgo(t *testing.T) {
- testenv.MustHaveGoBuild(t)
- testenv.MustHaveCGO(t)
-
- importer := New(&build.Default, token.NewFileSet(), make(map[string]*types.Package))
- _, err := importer.ImportFrom("./misc/cgo/test", runtime.GOROOT(), 0)
- if err != nil {
- t.Fatalf("Import failed: %v", err)
- }
-}
// Do not use casually!
FakeImportC bool
- // If UsesCgo is set, the type checker expects the
- // _cgo_gotypes.go file generated by running cmd/cgo to be
- // provided as a package source file. Qualified identifiers
- // referring to package C will be resolved to cgo-provided
- // declarations within _cgo_gotypes.go.
- //
- // It is an error to set both FakeImportC and UsesCgo.
- UsesCgo bool
-
// If Error != nil, it is called with each error found
// during type checking; err has dynamic type Error.
// Secondary errors (for instance, to enumerate all types
// nil Value.
func (tv TypeAndValue) IsValue() bool {
switch tv.mode {
- case constant_, variable, mapindex, value, commaok, commaerr:
+ case constant_, variable, mapindex, value, commaok:
return true
}
return false
switch x.mode {
case invalid:
return // error reported before
- case constant_, variable, mapindex, value, commaok, commaerr:
+ case constant_, variable, mapindex, value, commaok:
// ok
default:
unreachable()
import (
"go/ast"
"go/token"
- "strings"
)
func (check *Checker) call(x *operand, e *ast.CallExpr) exprKind {
default:
// function/method call
- cgocall := x.mode == cgofunc
-
sig, _ := x.typ.Underlying().(*Signature)
if sig == nil {
check.invalidOp(x.pos(), "cannot call non-function %s", x)
case 0:
x.mode = novalue
case 1:
- if cgocall {
- x.mode = commaerr
- } else {
- x.mode = value
- }
+ x.mode = value
x.typ = sig.results.vars[0].typ // unpack tuple
default:
x.mode = value
}, t.Len(), false
}
- if x0.mode == mapindex || x0.mode == commaok || x0.mode == commaerr {
+ if x0.mode == mapindex || x0.mode == commaok {
// comma-ok value
if allowCommaOk {
a := [2]Type{x0.typ, Typ[UntypedBool]}
- if x0.mode == commaerr {
- a[1] = universeError
- }
return func(x *operand, i int) {
x.mode = value
x.expr = x0.expr
check.assignment(x, typ, context)
}
-var cgoPrefixes = [...]string{
- "_Ciconst_",
- "_Cfconst_",
- "_Csconst_",
- "_Ctype_",
- "_Cvar_", // actually a pointer to the var
- "_Cfpvar_fp_",
- "_Cfunc_",
- "_Cmacro_", // function to evaluate the expanded expression
-}
-
func (check *Checker) selector(x *operand, e *ast.SelectorExpr) {
// these must be declared before the "goto Error" statements
var (
check.recordUse(ident, pname)
pname.used = true
pkg := pname.imported
-
- var exp Object
- funcMode := value
- if pkg.cgo {
- // cgo special cases C.malloc: it's
- // rewritten to _CMalloc and does not
- // support two-result calls.
- if sel == "malloc" {
- sel = "_CMalloc"
- } else {
- funcMode = cgofunc
- }
- for _, prefix := range cgoPrefixes {
- // cgo objects are part of the current package (in file
- // _cgo_gotypes.go). Use regular lookup.
- _, exp = check.scope.LookupParent(prefix+sel, check.pos)
- if exp != nil {
- break
- }
- }
- if exp == nil {
- check.errorf(e.Sel.Pos(), "%s not declared by package C", sel)
- goto Error
- }
- check.objDecl(exp, nil)
- } else {
- exp = pkg.scope.Lookup(sel)
- if exp == nil {
- if !pkg.fake {
- check.errorf(e.Sel.Pos(), "%s not declared by package %s", sel, pkg.name)
- }
- goto Error
- }
- if !exp.Exported() {
- check.errorf(e.Sel.Pos(), "%s not exported by package %s", sel, pkg.name)
- // ok to continue
+ exp := pkg.scope.Lookup(sel)
+ if exp == nil {
+ if !pkg.fake {
+ check.errorf(e.Sel.Pos(), "%s not declared by package %s", sel, pkg.name)
}
+ goto Error
+ }
+ if !exp.Exported() {
+ check.errorf(e.Sel.Pos(), "%s not exported by package %s", sel, pkg.name)
+ // ok to continue
}
check.recordUse(e.Sel, exp)
case *Var:
x.mode = variable
x.typ = exp.typ
- if pkg.cgo && strings.HasPrefix(exp.name, "_Cvar_") {
- x.typ = x.typ.(*Pointer).base
- }
case *Func:
- x.mode = funcMode
+ x.mode = value
x.typ = exp.typ
- if pkg.cgo && strings.HasPrefix(exp.name, "_Cmacro_") {
- x.mode = value
- x.typ = x.typ.(*Signature).results.vars[0].typ
- }
case *Builtin:
x.mode = builtin
x.typ = exp.typ
package types
import (
- "errors"
"go/ast"
"go/constant"
"go/token"
// Files checks the provided files as part of the checker's package.
func (check *Checker) Files(files []*ast.File) error { return check.checkFiles(files) }
-var errBadCgo = errors.New("cannot use FakeImportC and UsesCgo together")
-
func (check *Checker) checkFiles(files []*ast.File) (err error) {
- if check.conf.FakeImportC && check.conf.UsesCgo {
- return errBadCgo
- }
-
defer check.handleBailout(&err)
check.initFiles(files)
if a[0] == nil || a[1] == nil {
return
}
- assert(isTyped(a[0]) && isTyped(a[1]) && (isBoolean(a[1]) || a[1] == universeError))
+ assert(isTyped(a[0]) && isTyped(a[1]) && isBoolean(a[1]))
if m := check.Types; m != nil {
for {
tv := m[x]
mapindex // operand is a map index expression (acts like a variable on lhs, commaok on rhs of an assignment)
value // operand is a computed value
commaok // like value, but operand may be used in a comma,ok expression
- commaerr // like commaok, but second value is error, not boolean
- cgofunc // operand is a cgo function
)
var operandModeString = [...]string{
mapindex: "map index expression",
value: "value",
commaok: "comma, ok expression",
- commaerr: "comma, error expression",
- cgofunc: "cgo function",
}
// An operand represents an intermediate value during type checking.
// commaok <expr> (<untyped kind> <mode> )
// commaok <expr> ( <mode> of type <typ>)
//
-// commaerr <expr> (<untyped kind> <mode> )
-// commaerr <expr> ( <mode> of type <typ>)
-//
-// cgofunc <expr> (<untyped kind> <mode> )
-// cgofunc <expr> ( <mode> of type <typ>)
-//
func operandString(x *operand, qf Qualifier) string {
var buf bytes.Buffer
complete bool
imports []*Package
fake bool // scope lookup errors are silently dropped if package is fake (internal use only)
- cgo bool // uses of this package will be rewritten into uses of declarations from _cgo_gotypes.go
}
// NewPackage returns a new Package for the given package path and name.
}
// no package yet => import it
- if path == "C" && (check.conf.FakeImportC || check.conf.UsesCgo) {
+ if path == "C" && check.conf.FakeImportC {
imp = NewPackage("C", "C")
- imp.fake = true // package scope is not populated
- imp.cgo = check.conf.UsesCgo
+ imp.fake = true
} else {
// ordinary import
var err error
var Unsafe *Package
var (
- universeIota *Const
- universeByte *Basic // uint8 alias, but has name "byte"
- universeRune *Basic // int32 alias, but has name "rune"
- universeError *Named
+ universeIota *Const
+ universeByte *Basic // uint8 alias, but has name "byte"
+ universeRune *Basic // int32 alias, but has name "rune"
)
// Typ contains the predeclared *Basic types indexed by their
universeIota = Universe.Lookup("iota").(*Const)
universeByte = Universe.Lookup("byte").(*TypeName).typ.(*Basic)
universeRune = Universe.Lookup("rune").(*TypeName).typ.(*Basic)
- universeError = Universe.Lookup("error").(*TypeName).typ.(*Named)
}
// Objects with names containing blanks are internal and not entered into