Black Lives Matter. Support the Equal Justice Initiative.

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

Documentation: cmd/compile/internal/noder

     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  			switch builtin := n.Fun.(type) {
    59  			case *syntax.Name:
    60  				g.validateBuiltin(builtin.Value, n)
    61  			case *syntax.SelectorExpr:
    62  				g.validateBuiltin(builtin.Sel.Value, n)
    63  			default:
    64  				g.unhandled("builtin", n)
    65  			}
    66  		}
    67  	}
    68  }
    69  
    70  func (g *irgen) validateBuiltin(name string, call *syntax.CallExpr) {
    71  	switch name {
    72  	case "Alignof", "Offsetof", "Sizeof":
    73  		// Check that types2+gcSizes calculates sizes the same
    74  		// as cmd/compile does.
    75  
    76  		got, ok := constant.Int64Val(g.info.Types[call].Value)
    77  		if !ok {
    78  			base.FatalfAt(g.pos(call), "expected int64 constant value")
    79  		}
    80  
    81  		want := g.unsafeExpr(name, call.ArgList[0])
    82  		if got != want {
    83  			base.FatalfAt(g.pos(call), "got %v from types2, but want %v", got, want)
    84  		}
    85  	}
    86  }
    87  
    88  // unsafeExpr evaluates the given unsafe builtin function on arg.
    89  func (g *irgen) unsafeExpr(name string, arg syntax.Expr) int64 {
    90  	switch name {
    91  	case "Alignof":
    92  		return g.typ(g.info.Types[arg].Type).Alignment()
    93  	case "Sizeof":
    94  		return g.typ(g.info.Types[arg].Type).Size()
    95  	}
    96  
    97  	// Offsetof
    98  
    99  	sel := arg.(*syntax.SelectorExpr)
   100  	selection := g.info.Selections[sel]
   101  
   102  	typ := g.typ(g.info.Types[sel.X].Type)
   103  	typ = deref(typ)
   104  
   105  	var offset int64
   106  	for _, i := range selection.Index() {
   107  		// Ensure field offsets have been calculated.
   108  		types.CalcSize(typ)
   109  
   110  		f := typ.Field(i)
   111  		offset += f.Offset
   112  		typ = f.Type
   113  	}
   114  	return offset
   115  }
   116  

View as plain text