github.com/bir3/gocompiler@v0.3.205/src/cmd/compile/internal/noder/validate.go (about) 1 // Copyright 2021 The Go Authors. All rights reserved. 2 // Use of this source code is governed by a BSD-style 3 // license that can be found in the LICENSE file. 4 5 package noder 6 7 import ( 8 "github.com/bir3/gocompiler/src/go/constant" 9 10 "github.com/bir3/gocompiler/src/cmd/compile/internal/base" 11 "github.com/bir3/gocompiler/src/cmd/compile/internal/syntax" 12 "github.com/bir3/gocompiler/src/cmd/compile/internal/types" 13 "github.com/bir3/gocompiler/src/cmd/compile/internal/types2" 14 ) 15 16 // match reports whether types t1 and t2 are consistent 17 // representations for a given expression's type. 18 func (g *irgen) match(t1 *types.Type, t2 types2.Type, hasOK bool) bool { 19 tuple, ok := t2.(*types2.Tuple) 20 if !ok { 21 // Not a tuple; can use simple type identity comparison. 22 return types.Identical(t1, g.typ(t2)) 23 } 24 25 if hasOK { 26 // For has-ok values, types2 represents the expression's type as a 27 // 2-element tuple, whereas ir just uses the first type and infers 28 // that the second type is boolean. Must match either, since we 29 // sometimes delay the transformation to the ir form. 30 if tuple.Len() == 2 && types.Identical(t1, g.typ(tuple.At(0).Type())) { 31 return true 32 } 33 return types.Identical(t1, g.typ(t2)) 34 } 35 36 if t1 == nil || tuple == nil { 37 return t1 == nil && tuple == nil 38 } 39 if !t1.IsFuncArgStruct() { 40 return false 41 } 42 if t1.NumFields() != tuple.Len() { 43 return false 44 } 45 for i, result := range t1.FieldSlice() { 46 if !types.Identical(result.Type, g.typ(tuple.At(i).Type())) { 47 return false 48 } 49 } 50 return true 51 } 52 53 func (g *irgen) validate(n syntax.Node) { 54 switch n := n.(type) { 55 case *syntax.CallExpr: 56 tv := g.typeAndValue(n.Fun) 57 if tv.IsBuiltin() { 58 fun := n.Fun 59 for { 60 builtin, ok := fun.(*syntax.ParenExpr) 61 if !ok { 62 break 63 } 64 fun = builtin.X 65 } 66 switch builtin := fun.(type) { 67 case *syntax.Name: 68 g.validateBuiltin(builtin.Value, n) 69 case *syntax.SelectorExpr: 70 g.validateBuiltin(builtin.Sel.Value, n) 71 default: 72 g.unhandled("builtin", n) 73 } 74 } 75 } 76 } 77 78 func (g *irgen) validateBuiltin(name string, call *syntax.CallExpr) { 79 switch name { 80 case "Alignof", "Offsetof", "Sizeof": 81 // Check that types2+gcSizes calculates sizes the same 82 // as cmd/compile does. 83 84 tv := g.typeAndValue(call) 85 if !tv.IsValue() { 86 base.FatalfAt(g.pos(call), "expected a value") 87 } 88 89 if tv.Value == nil { 90 break // unsafe op is not a constant, so no further validation 91 } 92 93 got, ok := constant.Int64Val(tv.Value) 94 if !ok { 95 base.FatalfAt(g.pos(call), "expected int64 constant value") 96 } 97 98 want := g.unsafeExpr(name, call.ArgList[0]) 99 if got != want { 100 base.FatalfAt(g.pos(call), "got %v from types2, but want %v", got, want) 101 } 102 } 103 } 104 105 // unsafeExpr evaluates the given unsafe builtin function on arg. 106 func (g *irgen) unsafeExpr(name string, arg syntax.Expr) int64 { 107 switch name { 108 case "Alignof": 109 return g.typ(g.type2(arg)).Alignment() 110 case "Sizeof": 111 return g.typ(g.type2(arg)).Size() 112 } 113 114 // Offsetof 115 116 sel := arg.(*syntax.SelectorExpr) 117 selection := g.info.Selections[sel] 118 119 typ := g.typ(g.type2(sel.X)) 120 typ = deref(typ) 121 122 var offset int64 123 for _, i := range selection.Index() { 124 // Ensure field offsets have been calculated. 125 types.CalcSize(typ) 126 127 f := typ.Field(i) 128 offset += f.Offset 129 typ = f.Type 130 } 131 return offset 132 }