diff --git a/_test/issue-1285.go b/_test/issue-1285.go new file mode 100644 index 00000000..b4e8e74b --- /dev/null +++ b/_test/issue-1285.go @@ -0,0 +1,25 @@ +package main + +type ( + T1 struct{ Path [12]int8 } + T2 struct{ Path *[12]int8 } +) + +var ( + t11 = &T1{} + t21 = &T2{} +) + +func main() { + b := [12]byte{} + t12 := &T1{} + t22 := &T2{} + b11 := (*[len(t11.Path)]byte)(&b) + b12 := (*[len(t12.Path)]byte)(&b) + b21 := (*[len(t21.Path)]byte)(&b) + b22 := (*[len(t22.Path)]byte)(&b) + println(len(b11), len(b12), len(b21), len(b22)) +} + +// Output: +// 12 12 12 12 diff --git a/interp/cfg.go b/interp/cfg.go index d9fbab98..5c61ffa3 100644 --- a/interp/cfg.go +++ b/interp/cfg.go @@ -49,8 +49,10 @@ const nilIdent = "nil" // and pre-compute frame sizes and indexes for all un-named (temporary) and named // variables. A list of nodes of init functions is returned. // Following this pass, the CFG is ready to run. -func (interp *Interpreter) cfg(root *node, importPath, pkgName string) ([]*node, error) { - sc := interp.initScopePkg(importPath, pkgName) +func (interp *Interpreter) cfg(root *node, sc *scope, importPath, pkgName string) ([]*node, error) { + if sc == nil { + sc = interp.initScopePkg(importPath, pkgName) + } check := typecheck{scope: sc} var initNodes []*node var err error @@ -443,7 +445,7 @@ func (interp *Interpreter) cfg(root *node, importPath, pkgName string) ([]*node, // values which may be used in further declarations. if !sc.global { for _, c := range n.child { - if _, err = interp.cfg(c, importPath, pkgName); err != nil { + if _, err = interp.cfg(c, sc, importPath, pkgName); err != nil { // No error processing here, to allow recovery in subtree nodes. err = nil } @@ -887,7 +889,11 @@ func (interp *Interpreter) cfg(root *node, importPath, pkgName string) ([]*node, // Store result directly to frame output location, to avoid a frame copy. n.findex = 0 case bname == "cap" && isInConstOrTypeDecl(n): - switch n.child[1].typ.TypeOf().Kind() { + t := n.child[1].typ.TypeOf() + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + switch t.Kind() { case reflect.Array, reflect.Chan: capConst(n) default: @@ -896,7 +902,11 @@ func (interp *Interpreter) cfg(root *node, importPath, pkgName string) ([]*node, n.findex = notInFrame n.gen = nop case bname == "len" && isInConstOrTypeDecl(n): - switch n.child[1].typ.TypeOf().Kind() { + t := n.child[1].typ.TypeOf() + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + switch t.Kind() { case reflect.Array, reflect.Chan, reflect.String: lenConst(n) default: @@ -1257,7 +1267,7 @@ func (interp *Interpreter) cfg(root *node, importPath, pkgName string) ([]*node, // retry with the filename, in case ident is a package name. sym, level, found = sc.lookup(filepath.Join(n.ident, baseName)) if !found { - err = n.cfgErrorf("undefined: %s", n.ident) + err = n.cfgErrorf("undefined: %s %d", n.ident, n.index) break } } @@ -2409,7 +2419,7 @@ func isInConstOrTypeDecl(n *node) bool { anc := n.anc for anc != nil { switch anc.kind { - case constDecl, typeDecl: + case constDecl, typeDecl, arrayType, chanType: return true case varDecl, funcDecl: return false diff --git a/interp/gta.go b/interp/gta.go index b624f435..05b5ac20 100644 --- a/interp/gta.go +++ b/interp/gta.go @@ -25,7 +25,7 @@ func (interp *Interpreter) gta(root *node, rpath, importPath, pkgName string) ([ case constDecl: // Early parse of constDecl subtree, to compute all constant // values which may be used in further declarations. - if _, err = interp.cfg(n, importPath, pkgName); err != nil { + if _, err = interp.cfg(n, sc, importPath, pkgName); err != nil { // No error processing here, to allow recovery in subtree nodes. // TODO(marc): check for a non recoverable error and return it for better diagnostic. err = nil @@ -61,7 +61,7 @@ func (interp *Interpreter) gta(root *node, rpath, importPath, pkgName string) ([ dest, src := n.child[i], n.child[sbase+i] val := src.rval if n.anc.kind == constDecl { - if _, err2 := interp.cfg(n, importPath, pkgName); err2 != nil { + if _, err2 := interp.cfg(n, sc, importPath, pkgName); err2 != nil { // Constant value can not be computed yet. // Come back when child dependencies are known. revisit = append(revisit, n) diff --git a/interp/program.go b/interp/program.go index 51c5cd90..9ceefccf 100644 --- a/interp/program.go +++ b/interp/program.go @@ -79,7 +79,7 @@ func (interp *Interpreter) CompileAST(n ast.Node) (*Program, error) { } // Annotate AST with CFG informations. - initNodes, err := interp.cfg(root, pkgName, pkgName) + initNodes, err := interp.cfg(root, nil, pkgName, pkgName) if err != nil { if interp.cfgDot { dotCmd := interp.dotCmd diff --git a/interp/run.go b/interp/run.go index 769abd4c..e9984396 100644 --- a/interp/run.go +++ b/interp/run.go @@ -3144,23 +3144,37 @@ func _delete(n *node) { } func capConst(n *node) { - n.rval = reflect.New(reflect.TypeOf(int(0))).Elem() // There is no Cap() method for reflect.Type, just return Len() instead. - n.rval.SetInt(int64(n.child[1].typ.TypeOf().Len())) + lenConst(n) } func lenConst(n *node) { n.rval = reflect.New(reflect.TypeOf(int(0))).Elem() - if c1 := n.child[1]; c1.rval.IsValid() { + c1 := n.child[1] + if c1.rval.IsValid() { n.rval.SetInt(int64(len(vString(c1.rval)))) - } else { - n.rval.SetInt(int64(c1.typ.TypeOf().Len())) + return } + t := c1.typ.TypeOf() + for t.Kind() == reflect.Ptr { + t = t.Elem() + } + n.rval.SetInt(int64(t.Len())) } func _len(n *node) { dest := genValueOutput(n, reflect.TypeOf(int(0))) value := genValue(n.child[1]) + if isPtr(n.child[1].typ) { + val := value + value = func(f *frame) reflect.Value { + v := val(f).Elem() + for v.Type().Kind() == reflect.Ptr { + v = v.Elem() + } + return v + } + } next := getExec(n.tnext) if wantEmptyInterface(n) { diff --git a/interp/src.go b/interp/src.go index a1f20c21..46fcba1c 100644 --- a/interp/src.go +++ b/interp/src.go @@ -122,7 +122,7 @@ func (interp *Interpreter) importSrc(rPath, importPath string, skipTest bool) (s // Generate control flow graphs. for _, root := range rootNodes { var nodes []*node - if nodes, err = interp.cfg(root, importPath, pkgName); err != nil { + if nodes, err = interp.cfg(root, nil, importPath, pkgName); err != nil { return "", err } initNodes = append(initNodes, nodes...) diff --git a/interp/type.go b/interp/type.go index 2deddf16..97a670b3 100644 --- a/interp/type.go +++ b/interp/type.go @@ -456,7 +456,7 @@ func nodeType2(interp *Interpreter, sc *scope, n *node, seen []*node) (t *itype, length = int(vInt(sym.rval)) default: // Size is defined by a numeric constant expression. - if _, err = interp.cfg(c0, sc.pkgID, sc.pkgName); err != nil { + if _, err = interp.cfg(c0, sc, sc.pkgID, sc.pkgName); err != nil { return nil, err } v, ok := c0.rval.Interface().(constant.Value)