mirror of https://github.com/golang/go.git
114 lines
2.7 KiB
Go
114 lines
2.7 KiB
Go
// 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 noder
|
|
|
|
import (
|
|
"go/constant"
|
|
|
|
"cmd/compile/internal/base"
|
|
"cmd/compile/internal/syntax"
|
|
"cmd/compile/internal/types"
|
|
"cmd/compile/internal/types2"
|
|
)
|
|
|
|
// match reports whether types t1 and t2 are consistent
|
|
// representations for a given expression's type.
|
|
func (g *irgen) match(t1 *types.Type, t2 types2.Type, hasOK bool) bool {
|
|
tuple, ok := t2.(*types2.Tuple)
|
|
if !ok {
|
|
// Not a tuple; can use simple type identity comparison.
|
|
return types.Identical(t1, g.typ(t2))
|
|
}
|
|
|
|
if hasOK {
|
|
// For has-ok values, types2 represents the expression's type as
|
|
// a 2-element tuple, whereas ir just uses the first type and
|
|
// infers that the second type is boolean.
|
|
return tuple.Len() == 2 && types.Identical(t1, g.typ(tuple.At(0).Type()))
|
|
}
|
|
|
|
if t1 == nil || tuple == nil {
|
|
return t1 == nil && tuple == nil
|
|
}
|
|
if !t1.IsFuncArgStruct() {
|
|
return false
|
|
}
|
|
if t1.NumFields() != tuple.Len() {
|
|
return false
|
|
}
|
|
for i, result := range t1.FieldSlice() {
|
|
if !types.Identical(result.Type, g.typ(tuple.At(i).Type())) {
|
|
return false
|
|
}
|
|
}
|
|
return true
|
|
}
|
|
|
|
func (g *irgen) validate(n syntax.Node) {
|
|
switch n := n.(type) {
|
|
case *syntax.CallExpr:
|
|
tv := g.info.Types[n.Fun]
|
|
if tv.IsBuiltin() {
|
|
switch builtin := n.Fun.(type) {
|
|
case *syntax.Name:
|
|
g.validateBuiltin(builtin.Value, n)
|
|
case *syntax.SelectorExpr:
|
|
g.validateBuiltin(builtin.Sel.Value, n)
|
|
default:
|
|
g.unhandled("builtin", n)
|
|
}
|
|
}
|
|
}
|
|
}
|
|
|
|
func (g *irgen) validateBuiltin(name string, call *syntax.CallExpr) {
|
|
switch name {
|
|
case "Alignof", "Offsetof", "Sizeof":
|
|
// Check that types2+gcSizes calculates sizes the same
|
|
// as cmd/compile does.
|
|
|
|
got, ok := constant.Int64Val(g.info.Types[call].Value)
|
|
if !ok {
|
|
base.FatalfAt(g.pos(call), "expected int64 constant value")
|
|
}
|
|
|
|
want := g.unsafeExpr(name, call.ArgList[0])
|
|
if got != want {
|
|
base.FatalfAt(g.pos(call), "got %v from types2, but want %v", got, want)
|
|
}
|
|
}
|
|
}
|
|
|
|
// unsafeExpr evaluates the given unsafe builtin function on arg.
|
|
func (g *irgen) unsafeExpr(name string, arg syntax.Expr) int64 {
|
|
switch name {
|
|
case "Alignof":
|
|
return g.typ(g.info.Types[arg].Type).Alignment()
|
|
case "Sizeof":
|
|
return g.typ(g.info.Types[arg].Type).Size()
|
|
}
|
|
|
|
// Offsetof
|
|
|
|
sel := arg.(*syntax.SelectorExpr)
|
|
selection := g.info.Selections[sel]
|
|
|
|
typ := g.typ(g.info.Types[sel.X].Type)
|
|
if typ.IsPtr() {
|
|
typ = typ.Elem()
|
|
}
|
|
|
|
var offset int64
|
|
for _, i := range selection.Index() {
|
|
// Ensure field offsets have been calculated.
|
|
types.CalcSize(typ)
|
|
|
|
f := typ.Field(i)
|
|
offset += f.Offset
|
|
typ = f.Type
|
|
}
|
|
return offset
|
|
}
|