From a45457df82263c292e2c66c152a12b5df0f27f15 Mon Sep 17 00:00:00 2001 From: Cuong Manh Le Date: Mon, 1 Nov 2021 02:04:13 +0700 Subject: [PATCH] cmd/compile: fix panic when refer to method of imported instantiated type In case of reference to method call of an imported fully-instantiated type, nameNode.Func will be nil causes checkFetchBody panic. To fix this, make sure checkFetchBody is only called when Func is not nil. Fixes #49246 Change-Id: I32e9208385a86d4600d8ebf6f5efd8fca571ea16 Reviewed-on: https://go-review.googlesource.com/c/go/+/360056 Trust: Cuong Manh Le Trust: Dan Scales Run-TryBot: Cuong Manh Le TryBot-Result: Go Bot Reviewed-by: Dan Scales --- src/cmd/compile/internal/noder/stencil.go | 15 +++++++++++++-- test/typeparam/issue49246.dir/a.go | 20 ++++++++++++++++++++ test/typeparam/issue49246.dir/b.go | 9 +++++++++ test/typeparam/issue49246.go | 7 +++++++ 4 files changed, 49 insertions(+), 2 deletions(-) create mode 100644 test/typeparam/issue49246.dir/a.go create mode 100644 test/typeparam/issue49246.dir/b.go create mode 100644 test/typeparam/issue49246.go diff --git a/src/cmd/compile/internal/noder/stencil.go b/src/cmd/compile/internal/noder/stencil.go index 56010a356e..74281bc479 100644 --- a/src/cmd/compile/internal/noder/stencil.go +++ b/src/cmd/compile/internal/noder/stencil.go @@ -624,7 +624,7 @@ func (g *genInst) getDictOrSubdict(declInfo *instInfo, n ir.Node, nameNode *ir.N // yet. If so, it imports the body. func checkFetchBody(nameNode *ir.Name) { if nameNode.Func.Body == nil && nameNode.Func.Inl != nil { - // If there is no body yet but Func.Inl exists, then we can can + // If there is no body yet but Func.Inl exists, then we can // import the whole generic body. assert(nameNode.Func.Inl.Cost == 1 && nameNode.Sym().Pkg != types.LocalPkg) typecheck.ImportBody(nameNode.Func) @@ -638,7 +638,18 @@ func checkFetchBody(nameNode *ir.Name) { // with the type arguments shapes. If the instantiated function is not already // cached, then it calls genericSubst to create the new instantiation. func (g *genInst) getInstantiation(nameNode *ir.Name, shapes []*types.Type, isMeth bool) *instInfo { - checkFetchBody(nameNode) + if nameNode.Func == nil { + // If nameNode.Func is nil, this must be a reference to a method of + // an imported instantiated type. We will have already called + // g.instantiateMethods() on the fully-instantiated type, so + // g.instInfoMap[sym] will be non-nil below. + rcvr := nameNode.Type().Recv() + if rcvr == nil || !deref(rcvr.Type).IsFullyInstantiated() { + base.FatalfAt(nameNode.Pos(), "Unexpected function instantiation %v with no body", nameNode) + } + } else { + checkFetchBody(nameNode) + } // Convert any non-shape type arguments to their shape, so we can reduce the // number of instantiations we have to generate. You can actually have a mix diff --git a/test/typeparam/issue49246.dir/a.go b/test/typeparam/issue49246.dir/a.go new file mode 100644 index 0000000000..97459ee748 --- /dev/null +++ b/test/typeparam/issue49246.dir/a.go @@ -0,0 +1,20 @@ +// Copyright 2021 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 a + +type R[T any] struct{ v T } + +func (r R[T]) Self() R[T] { return R[T]{} } + +type Fn[T any] func() R[T] + +func X() (r R[int]) { return r.Self() } + +func Y[T any](a Fn[T]) Fn[int] { + return func() (r R[int]) { + // No crash: return R[int]{} + return r.Self() + } +} diff --git a/test/typeparam/issue49246.dir/b.go b/test/typeparam/issue49246.dir/b.go new file mode 100644 index 0000000000..5141b72fd4 --- /dev/null +++ b/test/typeparam/issue49246.dir/b.go @@ -0,0 +1,9 @@ +// Copyright 2021 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 b + +import "./a" + +func Crash() { a.Y(a.X)() } diff --git a/test/typeparam/issue49246.go b/test/typeparam/issue49246.go new file mode 100644 index 0000000000..87b4ff46c1 --- /dev/null +++ b/test/typeparam/issue49246.go @@ -0,0 +1,7 @@ +// compiledir -G=3 + +// Copyright 2021 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 ignored