Skip to content

Commit c8e3104

Browse files
committed
go/ir: add SliceToArrayPointer op
This is a backport of golang.org/cl/333749 and golang.org/cl/348511. Updates: gh-1045 Closes: gh-1081 [via git-merge-pr] Co-authored-by: Cuong Manh Le <[email protected]> (cherry picked from commit 61e00c9)
1 parent f9cde0a commit c8e3104

File tree

9 files changed

+125
-65
lines changed

9 files changed

+125
-65
lines changed

analysis/facts/nilness/nilness.go

+7
Original file line numberDiff line numberDiff line change
@@ -132,6 +132,13 @@ func impl(pass *analysis.Pass, fn *ir.Function, seenFns map[*ir.Function]struct{
132132
return mightReturnNil(v.X)
133133
case *ir.Convert:
134134
return mightReturnNil(v.X)
135+
case *ir.SliceToArrayPointer:
136+
if v.Type().Underlying().(*types.Pointer).Elem().Underlying().(*types.Array).Len() == 0 {
137+
return mightReturnNil(v.X)
138+
} else {
139+
// converting a slice to an array pointer of length > 0 panics if the slice is nil
140+
return neverNil
141+
}
135142
case *ir.Slice:
136143
return mightReturnNil(v.X)
137144
case *ir.Phi:

analysis/facts/nilness/testdata/src/Nilness/Nilness.go

+36
Original file line numberDiff line numberDiff line change
@@ -101,3 +101,39 @@ func fn20() *int {
101101
}
102102
return nil
103103
}
104+
105+
func fn21() *[5]int { // want fn21:`never returns nil: \[never\]`
106+
var x []int
107+
return (*[5]int)(x)
108+
}
109+
110+
func fn22() *[0]int {
111+
var x []int
112+
return (*[0]int)(x)
113+
}
114+
115+
func fn23() *[5]int { // want fn23:`never returns nil: \[never\]`
116+
var x []int
117+
type T [5]int
118+
ret := (*T)(x)
119+
return (*[5]int)(ret)
120+
}
121+
122+
func fn24() *[0]int {
123+
var x []int
124+
type T [0]int
125+
ret := (*T)(x)
126+
return (*[0]int)(ret)
127+
}
128+
129+
func fn25() *[5]int { // want fn25:`never returns nil: \[never\]`
130+
var x []int
131+
type T *[5]int
132+
return (T)(x)
133+
}
134+
135+
func fn26() *[0]int {
136+
var x []int
137+
type T *[0]int
138+
return (T)(x)
139+
}

go/ir/UPSTREAM

+1-1
Original file line numberDiff line numberDiff line change
@@ -5,5 +5,5 @@ The changes are too many to list here, and it is best to consider this package i
55
Upstream changes still get applied when they address bugs in portions of code we have inherited.
66

77
The last upstream commit we've looked at was:
8-
640c1dea83015e5271a001c99370762fc63dc280
8+
915f6209478fe61eb90dbe155a8a1c58655b931f
99

go/ir/doc.go

+50-49
Original file line numberDiff line numberDiff line change
@@ -49,55 +49,56 @@
4949
// concrete type which of these interfaces it implements.
5050
//
5151
// Value? Instruction? Member?
52-
// *Alloc ✔ ✔
53-
// *BinOp ✔ ✔
54-
// *BlankStore ✔
55-
// *Builtin ✔
56-
// *Call ✔ ✔
57-
// *ChangeInterface ✔ ✔
58-
// *ChangeType ✔ ✔
59-
// *Const ✔ ✔
60-
// *Convert ✔ ✔
61-
// *DebugRef ✔
62-
// *Defer ✔ ✔
63-
// *Extract ✔ ✔
64-
// *Field ✔ ✔
65-
// *FieldAddr ✔ ✔
66-
// *FreeVar ✔
67-
// *Function ✔ ✔ (func)
68-
// *Global ✔ ✔ (var)
69-
// *Go ✔ ✔
70-
// *If ✔
71-
// *Index ✔ ✔
72-
// *IndexAddr ✔ ✔
73-
// *Jump ✔
74-
// *Load ✔ ✔
75-
// *MakeChan ✔ ✔
76-
// *MakeClosure ✔ ✔
77-
// *MakeInterface ✔ ✔
78-
// *MakeMap ✔ ✔
79-
// *MakeSlice ✔ ✔
80-
// *MapLookup ✔ ✔
81-
// *MapUpdate ✔ ✔
82-
// *NamedConst ✔ (const)
83-
// *Next ✔ ✔
84-
// *Panic ✔
85-
// *Parameter ✔ ✔
86-
// *Phi ✔ ✔
87-
// *Range ✔ ✔
88-
// *Recv ✔ ✔
89-
// *Return ✔
90-
// *RunDefers ✔
91-
// *Select ✔ ✔
92-
// *Send ✔ ✔
93-
// *Sigma ✔ ✔
94-
// *Slice ✔ ✔
95-
// *Store ✔ ✔
96-
// *StringLookup ✔ ✔
97-
// *Type ✔ (type)
98-
// *TypeAssert ✔ ✔
99-
// *UnOp ✔ ✔
100-
// *Unreachable ✔
52+
// *Alloc ✔ ✔
53+
// *BinOp ✔ ✔
54+
// *BlankStore ✔
55+
// *Builtin ✔
56+
// *Call ✔ ✔
57+
// *ChangeInterface ✔ ✔
58+
// *ChangeType ✔ ✔
59+
// *Const ✔ ✔
60+
// *Convert ✔ ✔
61+
// *DebugRef ✔
62+
// *Defer ✔ ✔
63+
// *Extract ✔ ✔
64+
// *Field ✔ ✔
65+
// *FieldAddr ✔ ✔
66+
// *FreeVar ✔
67+
// *Function ✔ ✔ (func)
68+
// *Global ✔ ✔ (var)
69+
// *Go ✔ ✔
70+
// *If ✔
71+
// *Index ✔ ✔
72+
// *IndexAddr ✔ ✔
73+
// *Jump ✔
74+
// *Load ✔ ✔
75+
// *MakeChan ✔ ✔
76+
// *MakeClosure ✔ ✔
77+
// *MakeInterface ✔ ✔
78+
// *MakeMap ✔ ✔
79+
// *MakeSlice ✔ ✔
80+
// *MapLookup ✔ ✔
81+
// *MapUpdate ✔ ✔
82+
// *NamedConst ✔ (const)
83+
// *Next ✔ ✔
84+
// *Panic ✔
85+
// *Parameter ✔ ✔
86+
// *Phi ✔ ✔
87+
// *Range ✔ ✔
88+
// *Recv ✔ ✔
89+
// *Return ✔
90+
// *RunDefers ✔
91+
// *Select ✔ ✔
92+
// *Send ✔ ✔
93+
// *Sigma ✔ ✔
94+
// *Slice ✔ ✔
95+
// *SliceToArrayPointer ✔ ✔
96+
// *Store ✔ ✔
97+
// *StringLookup ✔ ✔
98+
// *Type ✔ (type)
99+
// *TypeAssert ✔ ✔
100+
// *UnOp ✔ ✔
101+
// *Unreachable ✔
101102
//
102103
// Other key types in this package include: Program, Package, Function
103104
// and BasicBlock.

go/ir/emit.go

+2-2
Original file line numberDiff line numberDiff line change
@@ -239,8 +239,8 @@ func emitConv(f *Function, val Value, typ types.Type, source ast.Node) Value {
239239
// Conversion from slice to array pointer?
240240
if slice, ok := ut_src.(*types.Slice); ok {
241241
if ptr, ok := ut_dst.(*types.Pointer); ok {
242-
if arr, ok := ptr.Elem().(*types.Array); ok && types.Identical(slice.Elem(), arr.Elem()) {
243-
c := &Convert{X: val}
242+
if arr, ok := ptr.Elem().Underlying().(*types.Array); ok && types.Identical(slice.Elem(), arr.Elem()) {
243+
c := &SliceToArrayPointer{X: val}
244244
c.setType(ut_dst)
245245
return f.emit(c, source)
246246
}

go/ir/print.go

+5-4
Original file line numberDiff line numberDiff line change
@@ -162,10 +162,11 @@ func printConv(prefix string, v, x Value) string {
162162
relName(x, v.(Instruction)))
163163
}
164164

165-
func (v *ChangeType) String() string { return printConv("ChangeType", v, v.X) }
166-
func (v *Convert) String() string { return printConv("Convert", v, v.X) }
167-
func (v *ChangeInterface) String() string { return printConv("ChangeInterface", v, v.X) }
168-
func (v *MakeInterface) String() string { return printConv("MakeInterface", v, v.X) }
165+
func (v *ChangeType) String() string { return printConv("ChangeType", v, v.X) }
166+
func (v *Convert) String() string { return printConv("Convert", v, v.X) }
167+
func (v *ChangeInterface) String() string { return printConv("ChangeInterface", v, v.X) }
168+
func (v *SliceToArrayPointer) String() string { return printConv("SliceToArrayPointer", v, v.X) }
169+
func (v *MakeInterface) String() string { return printConv("MakeInterface", v, v.X) }
169170

170171
func (v *MakeClosure) String() string {
171172
from := v.Parent().pkg()

go/ir/sanity.go

+1-7
Original file line numberDiff line numberDiff line change
@@ -141,14 +141,8 @@ func (s *sanity) checkInstr(idx int, instr Instruction) {
141141
case *Call:
142142
case *ChangeInterface:
143143
case *ChangeType:
144+
case *SliceToArrayPointer:
144145
case *Convert:
145-
if _, ok := instr.X.Type().Underlying().(*types.Slice); ok {
146-
if ptr, ok := instr.Type().Underlying().(*types.Pointer); ok {
147-
if _, ok := ptr.Elem().(*types.Array); ok {
148-
break
149-
}
150-
}
151-
}
152146
if _, ok := instr.X.Type().Underlying().(*types.Basic); !ok {
153147
if _, ok := instr.Type().Underlying().(*types.Basic); !ok {
154148
s.errorf("convert %s -> %s: at least one type must be basic", instr.X.Type(), instr.Type())

go/ir/ssa.go

+20-1
Original file line numberDiff line numberDiff line change
@@ -729,9 +729,10 @@ type ChangeType struct {
729729
// - between pointers and unsafe.Pointer.
730730
// - between unsafe.Pointer and uintptr.
731731
// - from (Unicode) integer to (UTF-8) string.
732-
// - from slice to array pointer.
733732
// A conversion may imply a type name change also.
734733
//
734+
// This operation cannot fail dynamically.
735+
//
735736
// Conversions of untyped string/number/bool constants to a specific
736737
// representation are eliminated during IR construction.
737738
//
@@ -763,6 +764,20 @@ type ChangeInterface struct {
763764
X Value
764765
}
765766

767+
// The SliceToArrayPointer instruction yields the conversion of slice X to
768+
// array pointer.
769+
//
770+
// Pos() returns the ast.CallExpr.Lparen, if the instruction arose
771+
// from an explicit conversion in the source.
772+
//
773+
// Example printed form:
774+
// t1 = SliceToArrayPointer <*[4]byte> t1
775+
//
776+
type SliceToArrayPointer struct {
777+
register
778+
X Value
779+
}
780+
766781
// MakeInterface constructs an instance of an interface type from a
767782
// value of a concrete type.
768783
//
@@ -1731,6 +1746,10 @@ func (v *Convert) Operands(rands []*Value) []*Value {
17311746
return append(rands, &v.X)
17321747
}
17331748

1749+
func (v *SliceToArrayPointer) Operands(rands []*Value) []*Value {
1750+
return append(rands, &v.X)
1751+
}
1752+
17341753
func (s *DebugRef) Operands(rands []*Value) []*Value {
17351754
return append(rands, &s.X)
17361755
}

unused/unused.go

+3-1
Original file line numberDiff line numberDiff line change
@@ -1661,8 +1661,10 @@ func (g *graph) instructions(fn *ir.Function) {
16611661
// nothing to do
16621662
case *ir.ConstantSwitch:
16631663
// nothing to do
1664+
case *ir.SliceToArrayPointer:
1665+
// nothing to do
16641666
default:
1665-
panic(fmt.Sprintf("unreachable: %T", instr))
1667+
lint.ExhaustiveTypeSwitch(instr)
16661668
}
16671669
}
16681670
}

0 commit comments

Comments
 (0)