Source file src/cmd/compile/internal/noder/validate.go

     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  	"go/constant"
     9  
    10  	"cmd/compile/internal/base"
    11  	"cmd/compile/internal/syntax"
    12  	"cmd/compile/internal/types"
    13  	"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.info.Types[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.info.Types[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.info.Types[arg].Type).Alignment()
   110  	case "Sizeof":
   111  		return g.typ(g.info.Types[arg].Type).Size()
   112  	}
   113  
   114  	// Offsetof
   115  
   116  	sel := arg.(*syntax.SelectorExpr)
   117  	selection := g.info.Selections[sel]
   118  
   119  	typ := g.typ(g.info.Types[sel.X].Type)
   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  }
   133  

View as plain text